Bläddra i källkod

* Corrected string lengths according to bugreport:198
- CHATBOX_SIZE: 70 -> 70+1
- removed some too aggressive checks in clif_parse_globalmessage()
- removed CHAT_SIZE define as it actually doesn't apply anywhere
- added CHAT_SIZE_MAX to serve as a custom limit to input string lengths
- added length/contents checks to /b and /lb (against fake names)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11386 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage 17 år sedan
förälder
incheckning
52a7948f8b
8 ändrade filer med 164 tillägg och 172 borttagningar
  1. 8 1
      Changelog-Trunk.txt
  2. 3 3
      src/map/atcommand.c
  3. 92 83
      src/map/clif.c
  4. 29 55
      src/map/log.c
  5. 1 1
      src/map/log.h
  6. 6 7
      src/map/map.h
  7. 20 20
      src/map/script.c
  8. 5 2
      src/map/skill.c

+ 8 - 1
Changelog-Trunk.txt

@@ -3,6 +3,13 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2007/10/09
+	* Corrected string lengths according to bugreport:198 [ultramage]
+	- CHATBOX_SIZE: 70 -> 70+1
+	- removed some too aggressive checks in clif_parse_globalmessage()
+	- removed CHAT_SIZE define as it actually doesn't apply anywhere
+	- added CHAT_SIZE_MAX to serve as a custom limit to input string lengths
+	- added length/contents checks to /b and /lb (against fake names)
 2007/10/08
 	* Delayed the check for required items when a skill is cast to when they 
 	  are consumed. Now skills only fail due to lack of items after being cast.
@@ -20,7 +27,7 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 	* Removed that ridiculous spinner that displays during map/npc loading
 	- and added a more informative progress indicator (idea from jA/eapp)
 	* Removed loads of code that supported these functions
-	- -100b per npc => -1,5MB of wasted memory
+	- -230b per npc => -3MB of wasted memory
 	* Fixed related npcs that erroneously used 'stoptimer'
 	* Checked/fixed/removed some old script and npc commands
 	+ cmdothernpc

+ 3 - 3
src/map/atcommand.c

@@ -906,7 +906,7 @@ int atcommand_config_read(const char *cfgName)
  *------------------------------------------*/
 int atcommand_commands(const int fd, struct map_session_data* sd, const char* command, const char* message)
 {
-	char cz_line_buff[CHATBOX_SIZE+1];
+	char cz_line_buff[CHATBOX_SIZE];
 
 	register char *lpcz_cur = cz_line_buff;
 	register unsigned int ui_slen;
@@ -914,7 +914,7 @@ int atcommand_commands(const int fd, struct map_session_data* sd, const char* co
 	int i_cur_cmd,gm_lvl = pc_isGM(sd), count = 0;
 
 	memset(cz_line_buff,' ',CHATBOX_SIZE);
-	cz_line_buff[CHATBOX_SIZE] = 0;
+	cz_line_buff[CHATBOX_SIZE-1] = 0;
 
 	clif_displaymessage(fd, msg_txt(273));
 
@@ -932,7 +932,7 @@ int atcommand_commands(const int fd, struct map_session_data* sd, const char* co
 			clif_displaymessage(fd,(char*)cz_line_buff);
 			lpcz_cur = cz_line_buff;
 			memset(cz_line_buff,' ',CHATBOX_SIZE);
-			cz_line_buff[CHATBOX_SIZE] = 0;
+			cz_line_buff[CHATBOX_SIZE-1] = 0;
 		}
 
 		memcpy(lpcz_cur,atcommand_info[i_cur_cmd].command,ui_slen);

+ 92 - 83
src/map/clif.c

@@ -6923,12 +6923,11 @@ void clif_emotion(struct block_list *bl,int type)
 void clif_talkiebox(struct block_list* bl, const char* talkie)
 {
 	unsigned char buf[86];
-
 	nullpo_retv(bl);
 
-	WBUFW(buf,0)=0x191;
-	WBUFL(buf,2)=bl->id;
-	memcpy(WBUFP(buf,6),talkie,MESSAGE_SIZE);
+	WBUFW(buf,0) = 0x191;
+	WBUFL(buf,2) = bl->id;
+	safestrncpy((char*)WBUFP(buf,6),talkie,MESSAGE_SIZE);
 	clif_send(buf,packet_len(0x191),bl,AREA);
 }
 
@@ -8212,7 +8211,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
 
 /*==========================================
  * Validates and processes global messages
- * S 008c/00f3 <packet len>.w <text>.?B (<name> : <message>)
+ * S 008c/00f3 <packet len>.w <text>.?B (<name> : <message>) 00
  *------------------------------------------*/
 void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 {
@@ -8223,12 +8222,12 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 	// basic structure checks
 	if( packetlen > RFIFOREST(fd) )
 	{	// there has to be enough data to read
-		ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!", sd->status.name);
+		ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name);
 		return;
 	}
 	if( packetlen < 4 + 1 )
 	{	// 4-byte header and at least an empty string is expected
-		ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (no message data)!", sd->status.name);
+		ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (no message data)!\n", sd->status.name);
 		return;
 	}
 
@@ -8242,41 +8241,31 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 		name[namelen] != ' ' || name[namelen+1] != ':' || name[namelen+2] != ' ' ) // followed by ' : '
 	{
 		//Hacked message, or infamous "client desynch" issue where they pick one char while loading another.
-		ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message using an incorrect name! Forcing a relog...", sd->status.name);
+		ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name);
 		clif_setwaitclose(fd); // Just kick them out to correct it.
 		return;
 	}
 
 	message = text + namelen + 3;
-	messagelen = textlen - namelen - 3 - 1; // this should be the message length
+	messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included)
 	// verify <message> part of the packet
-	if( message[messagelen] != '\0' )
+	if( message[messagelen-1] != '\0' )
 	{	// message must be zero-terminated
-		ShowWarning("clif_parse_GlobalMessage: Player '%s' sent an unterminated string!", sd->status.name);
+		ShowWarning("clif_parse_GlobalMessage: Player '%s' sent an unterminated string!\n", sd->status.name);
 		return;		
 	}
-	if( messagelen != strnlen(message, messagelen+1) )
+	if( messagelen != strnlen(message, messagelen)+1 )
 	{	// the declared length must match real length
-		ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!", sd->status.name);
+		ShowWarning("clif_parse_GlobalMessage: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name);
 		return;		
 	}
-	if( messagelen > CHATBOX_SIZE )
+	if( messagelen > CHAT_SIZE_MAX )
 	{	// messages mustn't be too long
-		int i;
-		// special case here - allow some more freedom for frost joke & dazzler 
-		// TODO:? You could use a state flag when FrostJoke/Scream is used, and unset it once the skill triggers. [Skotlex]
-		ARR_FIND( 0, MAX_SKILLTIMERSKILL, i, sd->ud.skilltimerskill[i] == 0 || sd->ud.skilltimerskill[i]->skill_id == BA_FROSTJOKE || sd->ud.skilltimerskill[i]->skill_id == DC_SCREAM );
-
-		if( i == MAX_SKILLTIMERSKILL || !sd->ud.skilltimerskill[i])
-		{	// normal message, too long
-			ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!", sd->status.name, CHATBOX_SIZE, message);
-			return;
-		}
-		if( messagelen > 255 )
-		{	// frost joke/dazzler, but still too long
-			ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!", sd->status.name, 255, message);
-			return;
-		}
+		// Normally you can only enter CHATBOX_SIZE-1 chars into the chat box, but Frost Joke / Dazzler's text can be longer.
+		// Neither the official client nor server place any restriction on the length of the text in the packet,
+		// but we'll only allow reasonably long strings here. This also makes sure all strings fit into the `chatlog` table.
+		ShowWarning("clif_parse_GlobalMessage: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX, message);
+		return;
 	}
 
 	if( is_atcommand(fd, sd, text) != AtCommand_None || is_charcommand(fd, sd, text) != CharCommand_None )
@@ -8771,26 +8760,40 @@ void clif_parse_Wis(int fd, struct map_session_data* sd)
 
 /*==========================================
  * /b
+ * S 0099 <packet len>.w <text>.?B (<name>: <message>) 00
  *------------------------------------------*/
-void clif_parse_GMmessage(int fd, struct map_session_data *sd)
+void clif_parse_GMmessage(int fd, struct map_session_data* sd)
 {
-	char* mes;
-	int size, lv;
+	char *text, *name, *message;
+	unsigned int textlen, namelen, messagelen;
+	int lv;
 
 	if (battle_config.atc_gmonly && !pc_isGM(sd))
 		return;
 	if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_Broadcast)))
 		return;
 
-	size = RFIFOW(fd,2)-4;
-	mes = (char*)RFIFOP(fd,4);
-	mes_len_check(mes, size, CHAT_SIZE);
+	text = (char*)RFIFOP(fd,4);
+	textlen = RFIFOW(fd,2) - 4;
+
+	name = text;
+	namelen = strnlen(sd->status.name, NAME_LENGTH - 1);
+	// verify <name> part of the packet
+	if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name
+		name[namelen] != ':' || name[namelen+1] != ' ' ) // followed by ': '
+		return;
+
+	// make sure the <message> part of the packet is safe to handle
+	message = text + namelen + 2;
+	messagelen = textlen - namelen - 2; // this should be the message length (w/ zero byte included)
+	mes_len_check(message, messagelen, CHATBOX_SIZE);
+
+	intif_GMmessage(text, textlen, 0);
 
-	intif_GMmessage(mes, size, 0);
 	if(log_config.gm && lv >= log_config.gm) {
-		char message[CHAT_SIZE+4];
-		sprintf(message, "/b %s", mes);
-		log_atcommand(sd, message);
+		char msg[CHATBOX_SIZE+4];
+		sprintf(msg, "/b %s", message);
+		log_atcommand(sd, msg);
 	}
 }
 
@@ -9468,8 +9471,7 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, int skilll
 			return;
 		}
 		//You can't use Graffiti/TalkieBox AND have a vending open, so this is safe.
-		memcpy(sd->message, RFIFOP(fd,skillmoreinfo), MESSAGE_SIZE);
-		sd->message[MESSAGE_SIZE-1] = '\0'; //Overflow protection [Skotlex]
+		safestrncpy(sd->message, (char*)RFIFOP(fd,skillmoreinfo), MESSAGE_SIZE);
 	}
 
 	if (sd->ud.skilltimer != -1)
@@ -9649,34 +9651,30 @@ void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd)
 }
 
 /*==========================================
- *
+ * Value entered into a NPC input box.
+ * S 0143 <npcID>.l <amount>.l
  *------------------------------------------*/
 void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd)
 {
-	sd->npc_amount=(int)RFIFOL(fd,6);
-	npc_scriptcont(sd,RFIFOL(fd,2));
+	int npcid = RFIFOL(fd,2);
+	int amount = (int)RFIFOL(fd,6);
+
+	sd->npc_amount = amount;
+	npc_scriptcont(sd, npcid);
 }
 
 /*==========================================
- *
+ * Text entered into a NPC input box.
+ * S 01d5 <len>.w <npcID>.l <input>.?B 00
  *------------------------------------------*/
-void clif_parse_NpcStringInput(int fd,struct map_session_data *sd)
+void clif_parse_NpcStringInput(int fd, struct map_session_data* sd)
 {
-	short message_len;
-	message_len = RFIFOW(fd,2)-7;
-
-	if(message_len < 1)
-		return; //Blank message?
-
-	if(message_len >= sizeof(sd->npc_str)){
-		ShowWarning("clif: input string too long !\n");
-		message_len = sizeof(sd->npc_str);
-	}
+	int message_len = RFIFOW(fd,2)-8;
+	int npcid = RFIFOL(fd,4);
+	const char* message = (char*)RFIFOP(fd,8);
 
-	// Exploit prevention if crafted packets (without null) is being sent. [Lance]
-	memcpy(sd->npc_str,RFIFOP(fd,8),message_len); 
-	sd->npc_str[message_len-1]=0;
-	npc_scriptcont(sd,RFIFOL(fd,4));
+	safestrncpy(sd->npc_str, message, min(message_len,CHATBOX_SIZE));
+	npc_scriptcont(sd, npcid);
 }
 
 /*==========================================
@@ -9775,31 +9773,46 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd)
 }
 
 /*==========================================
- * 019c /lb“™
+ * /lb
+ * S 019c <packet len>.w <text>.?B (<name>: <message>) 00
  *------------------------------------------*/
-void clif_parse_LGMmessage(int fd, struct map_session_data *sd)
+void clif_parse_LGMmessage(int fd, struct map_session_data* sd)
 {
-	unsigned char buf[CHAT_SIZE+4];
-	char *mes;
-	int len, lv;
+	char *text, *name, *message;
+	unsigned int textlen, namelen, messagelen;
+
+	unsigned char buf[CHATBOX_SIZE+4];
+	int lv;
 
 	if (battle_config.atc_gmonly && !pc_isGM(sd))
 		return;
 	if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_LocalBroadcast)))
 		return;
 
-	len = RFIFOW(fd,2) - 4;
-	mes = (char*)RFIFOP(fd,4);
-	mes_len_check(mes, len, CHAT_SIZE);
+	text = (char*)RFIFOP(fd,4);
+	textlen = RFIFOW(fd,2) - 4;
+
+	name = text;
+	namelen = strnlen(sd->status.name, NAME_LENGTH - 1);
+	// verify <name> part of the packet
+	if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name
+		name[namelen] != ':' || name[namelen+1] != ' ' ) // followed by ': '
+		return;
+
+	// make sure the <message> part of the packet is safe to handle
+	message = text + namelen + 2;
+	messagelen = textlen - namelen - 2; // this should be the message length (w/ zero byte included)
+	mes_len_check(message, messagelen, CHATBOX_SIZE);
 
 	WBUFW(buf,0) = 0x9a;
-	WBUFW(buf,2) = len+4;
-	memcpy(WBUFP(buf,4), mes, len);
+	WBUFW(buf,2) = textlen+4;
+	memcpy(WBUFP(buf,4), text, textlen);
 	clif_send(buf, WBUFW(buf,2), &sd->bl, ALL_SAMEMAP);
+
 	if(log_config.gm && lv >= log_config.gm) {
-		char message[CHAT_SIZE+5];
-		sprintf(message, "/lb %s", mes);
-		log_atcommand(sd, message);
+		char msg[CHATBOX_SIZE+5];
+		sprintf(msg, "/lb %s", message);
+		log_atcommand(sd, msg);
 	}
 }
 
@@ -10040,12 +10053,10 @@ void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd)
  *------------------------------------------*/
 void clif_parse_PartyMessage(int fd, struct map_session_data* sd)
 {
-	char* message;
-	int len;
+	int len = RFIFOW(fd,2) - 4;
+	char* message = (char*)RFIFOP(fd,4);
 
-	len = RFIFOW(fd,2) - 4;
-	message = (char*)RFIFOP(fd,4);
-	mes_len_check(message, len, CHAT_SIZE);
+	mes_len_check(message, len, CHATBOX_SIZE);
 
 	if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None)
 		return;
@@ -10309,12 +10320,10 @@ void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd)
  *------------------------------------------*/
 void clif_parse_GuildMessage(int fd, struct map_session_data* sd)
 {
-	char* message;
-	int len;
+	int len = RFIFOW(fd,2) - 4;
+	char* message = (char*)RFIFOP(fd,4);
 
-	len = RFIFOW(fd,2) - 4;
-	message = (char*)RFIFOP(fd,4);
-	mes_len_check(message, len, CHAT_SIZE);
+	mes_len_check(message, len, CHATBOX_SIZE);
 
 	if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None)
 		return;

+ 29 - 55
src/map/log.c

@@ -66,7 +66,7 @@ int log_branch(struct map_session_data *sd)
 	nullpo_retr(0, sd);
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
 		SqlStmt* stmt;
 		stmt = SqlStmt_Malloc(logmysql_handle);
@@ -104,18 +104,16 @@ int log_pick_pc(struct map_session_data *sd, const char *type, int nameid, int a
 		return 0; //we skip logging this item set - it doesn't meet our logging conditions [Lupus]
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
-		if (itm == NULL) {
-			//We log common item
+		if( itm == NULL ) { //We log common item
 			if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
 				log_config.log_pick_db, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex)) )
 			{
 				Sql_ShowDebug(logmysql_handle);
 				return 0;
 			}
-		} else {
-			//We log Extended item
+		} else { //We log Extended item
 			if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
 				log_config.log_pick_db, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex)) )
 			{
@@ -134,15 +132,10 @@ int log_pick_pc(struct map_session_data *sd, const char *type, int nameid, int a
 		time(&curtime);
 		strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime));
 
-		if (itm == NULL) {
-		//We log common item
-			fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n",
-				timestring, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex));
-
-		} else {
-		//We log Extended item
-			fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n",
-				timestring, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex));
+		if( itm == NULL ) { //We log common item
+			fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n", timestring, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex));
+		} else { //We log Extended item
+			fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n", timestring, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex));
 		}
 		fclose(logfp);
 	}
@@ -166,18 +159,16 @@ int log_pick_mob(struct mob_data *md, const char *type, int nameid, int amount,
 		mapname="";
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
-		if (itm==NULL) {
-		//We log common item
+		if( itm == NULL ) { //We log common item
 			if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
 				log_config.log_pick_db, md->class_, type, nameid, amount, mapname) )
 			{
 				Sql_ShowDebug(logmysql_handle);
 				return 0;
 			}
-		} else {
-		//We log Extended item
+		} else { //We log Extended item
 			if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
 				log_config.log_pick_db, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname) )
 			{
@@ -196,15 +187,10 @@ int log_pick_mob(struct mob_data *md, const char *type, int nameid, int amount,
 		time(&curtime);
 		strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime));
 
-		if (itm==NULL) {
-		//We log common item
-			fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n",
-				timestring, md->class_, type, nameid, amount, mapname);
-
-		} else {
-		//We log Extended item
-			fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n",
-				timestring, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname);
+		if( itm == NULL ) { //We log common item
+			fprintf(logfp,"%s - %d\t%s\t%d,%d,%s\n", timestring, md->class_, type, nameid, amount, mapname);
+		} else { //We log Extended item
+			fprintf(logfp,"%s - %d\t%s\t%d,%d,%d,%d,%d,%d,%d,%s\n", timestring, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname);
 		}
 		fclose(logfp);
 	}
@@ -220,7 +206,7 @@ int log_zeny(struct map_session_data *sd, char *type, struct map_session_data *s
 	nullpo_retr(0, sd);
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
 		if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%s')",
 			 log_config.log_zeny_db, sd->status.char_id, src_sd->status.char_id, type, amount, mapindex_id2name(sd->mapindex)) )
@@ -252,7 +238,7 @@ int log_mvpdrop(struct map_session_data *sd, int monster_id, int *log_mvp)
 	nullpo_retr(0, sd);
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
 		if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ",
 			log_config.log_mvpdrop_db, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], mapindex_id2name(sd->mapindex)) )
@@ -285,16 +271,10 @@ int log_atcommand(struct map_session_data* sd, const char* message)
 	nullpo_retr(0, sd);
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
 		SqlStmt* stmt;
 
-		if (strlen(message) > CHAT_SIZE) {
-			if (battle_config.error_log)
-				ShowError("log atcommand: Received message too long from player %s (%d:%d)!\n", sd->status.name, sd->status.account_id, sd->status.char_id);
-			return 0;
-		}
-
 		stmt = SqlStmt_Malloc(logmysql_handle);
 		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_gm_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
@@ -330,7 +310,7 @@ int log_npc(struct map_session_data* sd, const char* message)
 	nullpo_retr(0, sd);
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
 		SqlStmt* stmt;
 		stmt = SqlStmt_Malloc(logmysql_handle);
@@ -380,20 +360,14 @@ int log_chat(const char* type, int type_id, int src_charid, int src_accid, const
 		return 0; //Deactivated
 
 #ifndef TXT_ONLY
-	if(log_config.sql_logs > 0)
+	if( log_config.sql_logs )
 	{
 		SqlStmt* stmt;
 		
-		if (strlen(message) > CHAT_SIZE) {
-			if (battle_config.error_log)
-				ShowError("log chat: Received message too long from type %d (%d:%d)!\n", type_id, src_accid, src_charid);
-			return 0;
-		}
-
 		stmt = SqlStmt_Malloc(logmysql_handle);
 		if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%s', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", log_config.log_chat_db, type, type_id, src_charid, src_accid, map, x, y)
 		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH))
-		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE))
+		||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX))
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt) )
 		{
 			SqlStmt_ShowDebug(stmt);
@@ -456,7 +430,7 @@ int log_config_read(char *cfgName)
 				if (log_config.enable_logs&1) //Log everything.
 					log_config.enable_logs=0xFFFFFFFF;
 			} else if(strcmpi(w1,"sql_logs") == 0) {
-				log_config.sql_logs = (atoi(w2));
+				log_config.sql_logs = (bool)atoi(w2);
 //start of common filter settings
 			} else if(strcmpi(w1,"rare_items_log") == 0) {
 				log_config.rare_items_log = (atoi(w2));
@@ -517,31 +491,31 @@ int log_config_read(char *cfgName)
 
 			else if(strcmpi(w1, "log_branch_file") == 0) {
 				strcpy(log_config.log_branch, w2);
-				if(log_config.branch > 0 && log_config.sql_logs < 1)
+				if(log_config.branch > 0 && !log_config.sql_logs)
 					ShowNotice("Logging Dead Branch Usage to file `%s`.txt\n", w2);
 			} else if(strcmpi(w1, "log_pick_file") == 0) {
 				strcpy(log_config.log_pick, w2);
-				if(log_config.filter > 0 && log_config.sql_logs < 1)
+				if(log_config.filter > 0 && !log_config.sql_logs)
 					ShowNotice("Logging Item Picks to file `%s`.txt\n", w2);
 			} else if(strcmpi(w1, "log_zeny_file") == 0) {
 				strcpy(log_config.log_zeny, w2);
-				if(log_config.zeny > 0 && log_config.sql_logs < 1)
+				if(log_config.zeny > 0 && !log_config.sql_logs)
 					ShowNotice("Logging Zeny to file `%s`.txt\n", w2);
 			} else if(strcmpi(w1, "log_mvpdrop_file") == 0) {
 				strcpy(log_config.log_mvpdrop, w2);
-				if(log_config.mvpdrop > 0 && log_config.sql_logs < 1)
+				if(log_config.mvpdrop > 0 && !log_config.sql_logs)
 					ShowNotice("Logging MVP Drops to file `%s`.txt\n", w2);
 			} else if(strcmpi(w1, "log_gm_file") == 0) {
 				strcpy(log_config.log_gm, w2);
-				if(log_config.gm > 0 && log_config.sql_logs < 1)
+				if(log_config.gm > 0 && !log_config.sql_logs)
 					ShowNotice("Logging GM Level %d Commands to file `%s`.txt\n", log_config.gm, w2);
 			} else if(strcmpi(w1, "log_npc_file") == 0) {
 				strcpy(log_config.log_npc, w2);
-				if(log_config.npc > 0 && log_config.sql_logs < 1)
+				if(log_config.npc > 0 && !log_config.sql_logs)
 					ShowNotice("Logging NPC 'logmes' to file `%s`.txt\n", w2);
 			} else if(strcmpi(w1, "log_chat_file") == 0) {
 				strcpy(log_config.log_chat, w2);
-				if(log_config.chat > 0 && log_config.sql_logs < 1)					
+				if(log_config.chat > 0 && !log_config.sql_logs)					
 					ShowNotice("Logging CHAT to file `%s`.txt\n", w2);
 			//support the import command, just like any other config
 			} else if(strcmpi(w1,"import") == 0) {

+ 1 - 1
src/map/log.h

@@ -41,7 +41,7 @@ enum log_what {
 extern struct Log_Config {
 	enum log_what enable_logs;
 	int filter;
-	int sql_logs;
+	bool sql_logs;
 	int rare_items_log,refine_items_log,price_items_log,amount_items_log; //for filter
 	int branch, drop, mvpdrop, zeny, gm, npc, chat;
 	char log_branch[64], log_pick[64], log_zeny[64], log_mvpdrop[64], log_gm[64], log_npc[64], log_chat[64];

+ 6 - 7
src/map/map.h

@@ -163,16 +163,15 @@ enum {
 	MAPID_BABY_SOUL_LINKER,
 };
 
-//Max size when inputting a string with those 'npc input boxes'
-//(also used for Graffiti, Talkie Box, Vending, and Chatrooms)
-#define MESSAGE_SIZE 80
+//Max size for inputs to Graffiti, Talkie Box and Vending text prompts
+#define MESSAGE_SIZE (79 + 1)
 //String length you can write in the 'talking box'
-#define CHATBOX_SIZE 70
-//Talk max size: <name> : <message of 70> [Skotlex]
-#define CHAT_SIZE (NAME_LENGTH + 3 + CHATBOX_SIZE)
+#define CHATBOX_SIZE (70 + 1)
 //Chatroom-related string sizes
 #define CHATROOM_TITLE_SIZE (36 + 1)
 #define CHATROOM_PASS_SIZE (8 + 1)
+//Max allowed chat text length
+#define CHAT_SIZE_MAX 150
 
 #define DEFAULT_AUTOSAVE_INTERVAL 5*60*1000
 
@@ -610,7 +609,7 @@ struct map_session_data {
 	int npc_menu;
 	int npc_amount;
 	struct script_state *st;
-	char npc_str[256];
+	char npc_str[CHATBOX_SIZE]; // for passing npc input box text to script engine
 	int npc_timer_id; //For player attached npc timers. [Skotlex]
 	unsigned int chatID;
 	time_t idletime;

+ 20 - 20
src/map/script.c

@@ -5334,29 +5334,29 @@ BUILDIN_FUNC(input)
 		return 1;
 	}
 
-	if(sd->state.menu_or_input){
-		sd->state.menu_or_input=0;
-		if( postfix=='$' )
+	if( !sd->state.menu_or_input )
+	{	// first invocation, display npc input box
+		sd->state.menu_or_input = 1;
+		st->state = RERUNLINE;
+		if( postfix == '$' )
+			clif_scriptinputstr(sd,st->oid);
+		else	
+			clif_scriptinput(sd,st->oid);
+	}
+	else
+	{	// take received text/value and store it in the designated variable
+		sd->state.menu_or_input = 0;
+		if( postfix == '$' )
 		{
-			set_reg(st,sd,num,name,(void*)sd->npc_str,
-				script_getref(st,2));
-			return 0;
+			set_reg(st,sd,num,name,(void*)sd->npc_str,script_getref(st,2));
+		}
+		else
+		{
+			// limit the input to a non-negative value smaller than 'vending_max_value' (for scripts that didn't check this)
+			sd->npc_amount = cap_value(sd->npc_amount, 0, battle_config.vending_max_value);
+			set_reg(st,sd,num,name,(void*)sd->npc_amount,script_getref(st,2));
 		}
-		// Yor, Lupus & Fritz have messed with this.
-		// Basicly it prevents negative input since most scripts do not account for them.
-		sd->npc_amount = cap_value(sd->npc_amount, 0, battle_config.vending_max_value);
-
-		set_reg(st,sd,num,name,(void*)sd->npc_amount,
-			script_getref(st,2));
-		return 0;
 	}
-	//state.menu_or_input = 0
-	st->state=RERUNLINE;
-	if( postfix=='$' )
-		clif_scriptinputstr(sd,st->oid);
-	else	
-		clif_scriptinput(sd,st->oid);
-	sd->state.menu_or_input=1;
 	return 0;
 }
 

+ 5 - 2
src/map/skill.c

@@ -2729,8 +2729,8 @@ int skill_addtimerskill (struct block_list *src, unsigned int tick, int target,
 	ud = unit_bl2ud(src);
 	nullpo_retr(1, ud);
 	
-	for(i=0;i<MAX_SKILLTIMERSKILL && ud->skilltimerskill[i]; i++);
-	if (i==MAX_SKILLTIMERSKILL) return 1;
+	ARR_FIND( 0, MAX_SKILLTIMERSKILL, i, ud->skilltimerskill[i] == 0 );
+	if( i == MAX_SKILLTIMERSKILL ) return 1;
 	
 	ud->skilltimerskill[i] = ers_alloc(skill_timer_ers, struct skill_timerskill);
 	ud->skilltimerskill[i]->timer = add_timer(tick, skill_timerskill, src->id, i);
@@ -4393,7 +4393,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	case DC_SCREAM:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
 		skill_addtimerskill(src,tick+2000,bl->id,src->x,src->y,skillid,skilllv,0,flag);
+
 		if (md) {
+			// custom hack to make the mob display the skill, because these skills don't show the skill use text themselves
+			//NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches)
 			char temp[128];
 			if (strlen(md->name) + strlen(skill_db[skillid].desc) > 120)
 				break; //Message won't fit on buffer. [Skotlex]