Browse Source

- Improvements to the mail system.
- Added a sql patch, renaming "read_flag" column to "status" on the mail db.
- Need more testing.

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

zephyrus 17 years ago
parent
commit
284222a415
11 changed files with 314 additions and 226 deletions
  1. 2 0
      Changelog-Trunk.txt
  2. 1 0
      sql-files/upgrade_svn10582.sql
  3. 84 43
      src/char_sql/int_mail.c
  4. 2 2
      src/char_sql/inter.c
  5. 11 1
      src/common/mmo.h
  6. 97 118
      src/map/clif.c
  7. 4 4
      src/map/clif.h
  8. 73 44
      src/map/intif.c
  9. 36 12
      src/map/mail.c
  10. 3 2
      src/map/mail.h
  11. 1 0
      src/map/map.h

+ 2 - 0
Changelog-Trunk.txt

@@ -3,6 +3,8 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 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.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 
+2007/10/27
+	* Improvements to the mail system. Need Testing, [Zephyrus]
 2007/10/26
 2007/10/26
 	* Moved the new novending cell check from the internal code to the
 	* Moved the new novending cell check from the internal code to the
 	  client-server interface (allows server to force-open shop if needed)
 	  client-server interface (allows server to force-open shop if needed)

+ 1 - 0
sql-files/upgrade_svn10582.sql

@@ -0,0 +1 @@
+ALTER TABLE `mail` CHANGE `read_flag` `status` SMALLINT(2) NOT NULL default 0;

+ 84 - 43
src/char_sql/int_mail.c

@@ -34,11 +34,12 @@ static int mail_fromsql(int char_id, struct mail_data* md)
 	md->full = false;
 	md->full = false;
 
 
 	StringBuf_Init(&buf);
 	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`read_flag`,"
+	StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`,"
 		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`");
 		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`");
 	for (i = 0; i < MAX_SLOTS; i++)
 	for (i = 0; i < MAX_SLOTS; i++)
 		StringBuf_Printf(&buf, ",`card%d`", i);
 		StringBuf_Printf(&buf, ",`card%d`", i);
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' ORDER BY `id` LIMIT %d", mail_db, char_id, MAIL_MAX_INBOX + 1);
+	StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` > -1 AND `status` < 3 "
+		"ORDER BY `id` LIMIT %d", mail_db, char_id, MAIL_MAX_INBOX + 1);
 
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
 		Sql_ShowDebug(sql_handle);
 		Sql_ShowDebug(sql_handle);
@@ -56,7 +57,7 @@ static int mail_fromsql(int char_id, struct mail_data* md)
 		Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH);
 		Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH);
 		Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH);
 		Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH);
 		Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data);
 		Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data);
-		Sql_GetData(sql_handle, 8, &data, NULL); msg->read = atoi(data);
+		Sql_GetData(sql_handle, 8, &data, NULL); msg->status = atoi(data);
 		Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data);
 		Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data);
 		item = &msg->item;
 		item = &msg->item;
 		Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data);
 		Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data);
@@ -83,17 +84,16 @@ static int mail_fromsql(int char_id, struct mail_data* md)
 	for (i = 0; i < md->amount; i++)
 	for (i = 0; i < md->amount; i++)
 	{
 	{
 		msg = &md->msg[i];
 		msg = &md->msg[i];
-		if( msg->read == 0 )
+		if( msg->status == MAIL_NEW )
 		{
 		{
-			if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `read_flag` = '1' WHERE `id` = '%d'", mail_db, msg->id) )
+			if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) )
 				Sql_ShowDebug(sql_handle);
 				Sql_ShowDebug(sql_handle);
 
 
+			msg->status = MAIL_UNREAD;
 			md->unchecked++;
 			md->unchecked++;
 		}
 		}
-		else if ( msg->read == 1 )
+		else if ( msg->status == MAIL_UNREAD )
 			md->unread++;
 			md->unread++;
-
-		msg->read = (msg->read < 2)?0:1;
 	}
 	}
 
 
 	ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount);
 	ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount);
@@ -110,11 +110,11 @@ static int mail_savemessage(struct mail_message* msg)
 
 
 	// build message save query
 	// build message save query
 	StringBuf_Init(&buf);
 	StringBuf_Init(&buf);
-	StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `read_flag`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db);
+	StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db);
 	for (j = 0; j < MAX_SLOTS; j++)
 	for (j = 0; j < MAX_SLOTS; j++)
 		StringBuf_Printf(&buf, ", `card%d`", j);
 		StringBuf_Printf(&buf, ", `card%d`", j);
-	StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%d', '0', '%d', '%d', '%d', '%d', '%d', '%d'",
-		msg->send_id, msg->dest_id, msg->timestamp, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify);
+	StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d'",
+		msg->send_id, msg->dest_id, msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify);
 	for (j = 0; j < MAX_SLOTS; j++)
 	for (j = 0; j < MAX_SLOTS; j++)
 		StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]);
 		StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]);
 	StringBuf_AppendStr(&buf, ")");
 	StringBuf_AppendStr(&buf, ")");
@@ -141,17 +141,17 @@ static int mail_savemessage(struct mail_message* msg)
 
 
 /// Retrieves a single message from the database.
 /// Retrieves a single message from the database.
 /// Returns true if the operation succeeds (or false if it fails).
 /// Returns true if the operation succeeds (or false if it fails).
-static bool mail_loadmessage(int char_id, int mail_id, struct mail_message* msg)
+static bool mail_loadmessage(int mail_id, struct mail_message* msg)
 {
 {
 	int j;
 	int j;
 	StringBuf buf;
 	StringBuf buf;
 
 
 	StringBuf_Init(&buf);
 	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`read_flag`,"
+	StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`,"
 		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`");
 		"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`");
 	for( j = 0; j < MAX_SLOTS; j++ )
 	for( j = 0; j < MAX_SLOTS; j++ )
 		StringBuf_Printf(&buf, ",`card%d`", j);
 		StringBuf_Printf(&buf, ",`card%d`", j);
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id` = '%d' AND `id` = '%d'", mail_db, char_id, mail_id);
+	StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id);
 
 
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))
 	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf))
 	||  SQL_SUCCESS != Sql_NextRow(sql_handle) )
 	||  SQL_SUCCESS != Sql_NextRow(sql_handle) )
@@ -173,7 +173,7 @@ static bool mail_loadmessage(int char_id, int mail_id, struct mail_message* msg)
 		Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH);
 		Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH);
 		Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH);
 		Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH);
 		Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data);
 		Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data);
-		Sql_GetData(sql_handle, 8, &data, NULL); msg->read = atoi(data);
+		Sql_GetData(sql_handle, 8, &data, NULL); msg->status = atoi(data);
 		Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data);
 		Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data);
 		Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data);
 		Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data);
 		Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data);
 		Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data);
@@ -190,15 +190,6 @@ static bool mail_loadmessage(int char_id, int mail_id, struct mail_message* msg)
 	StringBuf_Destroy(&buf);
 	StringBuf_Destroy(&buf);
 	Sql_FreeResult(sql_handle);
 	Sql_FreeResult(sql_handle);
 
 
-	// this thing converts the database value (0,1,2) into a boolean yes/no
-	//TODO: provide decent enum instead of using 'magic' values
-	if (msg->read == 1)
-	{
-		msg->read = 0;
-	}
-	else
-		msg->read = 1;
-
 	return true;
 	return true;
 }
 }
 
 
@@ -231,7 +222,7 @@ static void mapif_parse_Mail_requestinbox(int fd)
 static void mapif_parse_Mail_read(int fd)
 static void mapif_parse_Mail_read(int fd)
 {
 {
 	int mail_id = RFIFOL(fd,2);
 	int mail_id = RFIFOL(fd,2);
-	if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `read_flag` = '2' WHERE `id` = '%d'", mail_db, mail_id) )
+	if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `read_flag` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READED, mail_id) )
 		Sql_ShowDebug(sql_handle);
 		Sql_ShowDebug(sql_handle);
 }
 }
 
 
@@ -265,7 +256,13 @@ static void mapif_Mail_getattach(int fd, int char_id, int mail_id)
 {
 {
 	struct mail_message msg;
 	struct mail_message msg;
 
 
-	if( !mail_loadmessage(char_id, mail_id, &msg) )
+	if( !mail_loadmessage(mail_id, &msg) )
+		return;
+
+	if( msg.dest_id != char_id )
+		return;
+
+	if( msg.status != MAIL_READED )
 		return;
 		return;
 
 
 	if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 )
 	if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 )
@@ -294,7 +291,7 @@ static void mapif_parse_Mail_getattach(int fd)
 static void mapif_Mail_delete(int fd, int char_id, int mail_id)
 static void mapif_Mail_delete(int fd, int char_id, int mail_id)
 {
 {
 	bool failed = false;
 	bool failed = false;
-	if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) )
+	if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_DELETED, mail_id) )
 	{
 	{
 		Sql_ShowDebug(sql_handle);
 		Sql_ShowDebug(sql_handle);
 		failed = true;
 		failed = true;
@@ -313,6 +310,26 @@ static void mapif_parse_Mail_delete(int fd)
 	mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6));
 	mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6));
 }
 }
 
 
+/*==========================================
+ * Report New Mail to Map Server
+ *------------------------------------------*/
+static void mapif_Mail_new(int mail_id)
+{
+	struct mail_message msg;
+
+	if( mail_loadmessage(mail_id, &msg) )
+	{
+		unsigned char buf[74];
+
+		WBUFW(buf,0) = 0x3849;
+		WBUFL(buf,2) = msg.dest_id;
+		WBUFL(buf,6) = mail_id;
+		memcpy(WBUFP(buf,10), msg.send_name, NAME_LENGTH);
+		memcpy(WBUFP(buf,34), msg.title, MAIL_TITLE_LENGTH);
+		mapif_sendall(buf, 74);
+	}
+}
+
 /*==========================================
 /*==========================================
  * Return Mail
  * Return Mail
  *------------------------------------------*/
  *------------------------------------------*/
@@ -321,9 +338,11 @@ static void mapif_Mail_return(int fd, int char_id, int mail_id)
 	struct mail_message msg;
 	struct mail_message msg;
 	int new_mail = 0;
 	int new_mail = 0;
 
 
-	if( mail_loadmessage(char_id, mail_id, &msg) )
+	if( mail_loadmessage(mail_id, &msg) )
 	{
 	{
-		if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) )
+		if( msg.dest_id != char_id)
+			return;
+		else if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_RETURNED, mail_id) )
 			Sql_ShowDebug(sql_handle);
 			Sql_ShowDebug(sql_handle);
 		else
 		else
 		{
 		{
@@ -339,18 +358,20 @@ static void mapif_Mail_return(int fd, int char_id, int mail_id)
 			snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title);
 			snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title);
 			safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH);
 			safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH);
 
 
+			msg.status = MAIL_NEW;
 			msg.timestamp = (unsigned int)calc_times();
 			msg.timestamp = (unsigned int)calc_times();
 
 
 			new_mail = mail_savemessage(&msg);
 			new_mail = mail_savemessage(&msg);
+			mapif_Mail_new(new_mail);
 		}
 		}
 	}
 	}
 
 
-	WFIFOHEAD(fd,14);
+	WFIFOHEAD(fd,11);
 	WFIFOW(fd,0) = 0x384c;
 	WFIFOW(fd,0) = 0x384c;
 	WFIFOL(fd,2) = char_id;
 	WFIFOL(fd,2) = char_id;
 	WFIFOL(fd,6) = mail_id;
 	WFIFOL(fd,6) = mail_id;
-	WFIFOL(fd,10) = new_mail;
-	WFIFOSET(fd,14);
+	WFIFOB(fd,10) = (new_mail == 0);
+	WFIFOSET(fd,11);
 }
 }
 
 
 static void mapif_parse_Mail_return(int fd)
 static void mapif_parse_Mail_return(int fd)
@@ -358,18 +379,16 @@ static void mapif_parse_Mail_return(int fd)
 	mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6));
 	mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6));
 }
 }
 
 
+/*==========================================
+ * Send Mail
+ *------------------------------------------*/
 static void mapif_Mail_send(int fd, struct mail_message* msg)
 static void mapif_Mail_send(int fd, struct mail_message* msg)
 {
 {
-	int len = strlen(msg->title);
-
-	WFIFOHEAD(fd,len);
+	WFIFOHEAD(fd,10);
 	WFIFOW(fd,0) = 0x384d;
 	WFIFOW(fd,0) = 0x384d;
-	WFIFOW(fd,2) = len + 16;
-	WFIFOL(fd,4) = msg->send_id;
-	WFIFOL(fd,8) = msg->id;
-	WFIFOL(fd,12) = msg->dest_id;
-	safestrncpy((char*)WFIFOP(fd,16), msg->title, len);
-	WFIFOSET(fd,WFIFOW(fd,2));
+	WFIFOL(fd,2) = msg->send_id;
+	WFIFOL(fd,6) = msg->id;
+	WFIFOSET(fd,10);
 }
 }
 
 
 static void mapif_parse_Mail_send(int fd)
 static void mapif_parse_Mail_send(int fd)
@@ -381,9 +400,8 @@ static void mapif_parse_Mail_send(int fd)
 	if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message))
 	if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message))
 		return;
 		return;
 
 
-	memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message));
-
 	account_id = RFIFOL(fd,4);
 	account_id = RFIFOL(fd,4);
+	memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message));
 
 
 	// Try to find the Dest Char by Name
 	// Try to find the Dest Char by Name
 	Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH));
 	Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH));
@@ -403,13 +421,35 @@ static void mapif_parse_Mail_send(int fd)
 	Sql_FreeResult(sql_handle);
 	Sql_FreeResult(sql_handle);
 
 
 	if( msg.dest_id > 0 )
 	if( msg.dest_id > 0 )
+	{
+		msg.status = MAIL_UNVERIFIED;
 		msg.id = mail_savemessage(&msg);
 		msg.id = mail_savemessage(&msg);
+	}
 	else
 	else
 		msg.id = 0;
 		msg.id = 0;
 
 
 	mapif_Mail_send(fd, &msg);
 	mapif_Mail_send(fd, &msg);
 }
 }
 
 
+static void mapif_parse_Mail_confirmation(int fd)
+{
+	int mail_id = RFIFOL(fd,2);
+	bool fail = RFIFOB(fd,6);
+
+	if( fail )
+	{
+		if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_INVALID, mail_id) )
+			Sql_ShowDebug(sql_handle);
+	}
+	else
+	{
+		if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_NEW, mail_id) )
+			Sql_ShowDebug(sql_handle);
+		else
+			mapif_Mail_new(mail_id);
+	}
+}
+
 /*==========================================
 /*==========================================
  * Packets From Map Server
  * Packets From Map Server
  *------------------------------------------*/
  *------------------------------------------*/
@@ -423,6 +463,7 @@ int inter_mail_parse_frommap(int fd)
 		case 0x304b: mapif_parse_Mail_delete(fd); break;
 		case 0x304b: mapif_parse_Mail_delete(fd); break;
 		case 0x304c: mapif_parse_Mail_return(fd); break;
 		case 0x304c: mapif_parse_Mail_return(fd); break;
 		case 0x304d: mapif_parse_Mail_send(fd); break;
 		case 0x304d: mapif_parse_Mail_send(fd); break;
+		case 0x304e: mapif_parse_Mail_confirmation(fd); break;
 		default:
 		default:
 			return 0;
 			return 0;
 	}
 	}

+ 2 - 2
src/char_sql/inter.c

@@ -54,7 +54,7 @@ int inter_send_packet_length[] = {
 	-1, 7, 0, 0,  0, 0, 0, 0, -1,11, 0, 0,  0, 0,  0, 0,	// 3810-
 	-1, 7, 0, 0,  0, 0, 0, 0, -1,11, 0, 0,  0, 0,  0, 0,	// 3810-
 	35,-1,11,15, 34,29, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0,	// 3820-
 	35,-1,11,15, 34,29, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0,	// 3820-
 	10,-1,15, 0, 79,19, 7,-1,  0,-1,-1,-1, 14,67,186,-1,	// 3830-
 	10,-1,15, 0, 79,19, 7,-1,  0,-1,-1,-1, 14,67,186,-1,	// 3830-
-	 9, 9,-1, 0,  0, 0, 0, 0, -1, 0,-1,12, 14,-1,  0, 0,	// 3840-
+	 9, 9,-1, 0,  0, 0, 0, 0, -1,74,-1,11, 11,10,  0, 0,	// 3840-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3850-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3850-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3860-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3860-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3870-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3870-
@@ -66,7 +66,7 @@ int inter_recv_packet_length[] = {
 	 6,-1, 0, 0,  0, 0, 0, 0, 10,-1, 0, 0,  0, 0,  0, 0,	// 3010-
 	 6,-1, 0, 0,  0, 0, 0, 0, 10,-1, 0, 0,  0, 0,  0, 0,	// 3010-
 	-1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0,  0, 0,  0, 0,	// 3020-
 	-1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0,  0, 0,  0, 0,	// 3020-
 	-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1,	// 3030-
 	-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1,	// 3030-
-	 5, 9, 0, 0,  0, 0, 0, 0,  7, 6,10,10, 10,-1,  0, 0,	// 3040-
+	 5, 9, 0, 0,  0, 0, 0, 0,  7, 6,10,10, 10,-1,  7, 0,	// 3040-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3050-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3050-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3060-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3060-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3070-
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3070-

+ 11 - 1
src/common/mmo.h

@@ -250,7 +250,7 @@ struct mail_message {
 	char title[MAIL_TITLE_LENGTH];
 	char title[MAIL_TITLE_LENGTH];
 	char body[MAIL_BODY_LENGTH];
 	char body[MAIL_BODY_LENGTH];
 
 
-	unsigned char read;
+	short status;
 	unsigned int timestamp; // marks when the message was sent
 	unsigned int timestamp; // marks when the message was sent
 
 
 	int zeny;
 	int zeny;
@@ -415,6 +415,16 @@ enum {
 	GBI_SKILLLV,		// ギルドスキルLv
 	GBI_SKILLLV,		// ギルドスキルLv
 };
 };
 
 
+enum {
+	MAIL_UNVERIFIED = -1,
+	MAIL_NEW,
+	MAIL_UNREAD,
+	MAIL_READED,
+	MAIL_DELETED,
+	MAIL_RETURNED,
+	MAIL_INVALID,
+};
+
 enum {
 enum {
 	GMI_POSITION	=0,		// メンバーの役職変更
 	GMI_POSITION	=0,		// メンバーの役職変更
 	GMI_EXP,
 	GMI_EXP,

+ 97 - 118
src/map/clif.c

@@ -11300,6 +11300,77 @@ void clif_parse_AutoRevive(int fd, struct map_session_data *sd)
  * By Zephyrus
  * By Zephyrus
  *==========================================*/
  *==========================================*/
 
 
+/*------------------------------------------
+ * Reply to an Attachment operation
+ * 0 : From inventory to Attachment OK
+ * 1 : Fail to set the attachment
+ * 2 : Weight Problems (when get the attachment)
+ *------------------------------------------*/
+void clif_Mail_attachment(int fd, unsigned char flag)
+{
+	WFIFOHEAD(fd,packet_len(0x245));
+	WFIFOW(fd,0) = 0x245;
+	WFIFOB(fd,2) = flag;
+	WFIFOSET(fd,packet_len(0x245));
+}
+
+/*------------------------------------------
+ * Send Mail ack
+ * 0 : Message Send Ok
+ * 1 : Destination char not found
+ *------------------------------------------*/
+void clif_Mail_send(int fd, bool fail)
+{
+	WFIFOHEAD(fd,packet_len(0x249));
+	WFIFOW(fd,0) = 0x249;
+	WFIFOB(fd,2) = fail;
+	WFIFOSET(fd,packet_len(0x249));
+}
+
+/*------------------------------------------
+ * Delete Mail ack
+ * 0 : Delete ok
+ * 1 : Delete failed
+ *------------------------------------------*/
+void clif_Mail_delete(int fd, int mail_id, short fail)
+{
+	WFIFOHEAD(fd, packet_len(0x257));
+	WFIFOW(fd,0) = 0x257;
+	WFIFOL(fd,2) = mail_id;
+	WFIFOW(fd,6) = fail;
+	WFIFOSET(fd, packet_len(0x257));
+}
+
+/*------------------------------------------
+ * Return Mail ack
+ * 0 : Mail returned to the sender
+ * 1 : The mail does not exist
+ *------------------------------------------*/
+void clif_Mail_return(int fd, int mail_id, short fail)
+{
+	WFIFOHEAD(fd,packet_len(0x274));
+	WFIFOW(fd,0) = 0x274;
+	WFIFOL(fd,2) = mail_id;
+	WFIFOW(fd,6) = fail;
+	WFIFOSET(fd,packet_len(0x274));
+}
+
+/*------------------------------------------
+ * You have New Mail
+ *------------------------------------------*/
+void clif_Mail_new(struct map_session_data *sd, int mail_id, const char *sender, const char *title)
+{
+	int fd = sd->fd;
+	sd->mail.inbox.changed = true;
+		
+	WFIFOHEAD(fd,packet_len(0x24a));
+	WFIFOW(fd,0) = 0x24a;
+	WFIFOL(fd,2) = mail_id;
+	memcpy(WFIFOP(fd,6), sender, NAME_LENGTH);
+	memcpy(WFIFOP(fd,30), title, MAIL_TITLE_LENGTH);
+	WFIFOSET(fd,packet_len(0x24a));
+}
+
 /*------------------------------------------
 /*------------------------------------------
  * Opens Mail Window on Client
  * Opens Mail Window on Client
  *------------------------------------------*/
  *------------------------------------------*/
@@ -11331,25 +11402,26 @@ void clif_Mail_refreshinbox(struct map_session_data *sd)
 	{
 	{
 		msg = &md->msg[i];
 		msg = &md->msg[i];
 		if (msg->id < 1)
 		if (msg->id < 1)
-			continue; // Deleted Message
+			continue;
 
 
 		WFIFOL(fd,8+73*j) = msg->id;
 		WFIFOL(fd,8+73*j) = msg->id;
 		memcpy(WFIFOP(fd,12+73*j), msg->title, MAIL_TITLE_LENGTH);
 		memcpy(WFIFOP(fd,12+73*j), msg->title, MAIL_TITLE_LENGTH);
-		WFIFOB(fd,52+73*j) = msg->read;
+		WFIFOB(fd,52+73*j) = (msg->status == MAIL_UNREAD);
 		memcpy(WFIFOP(fd,53+73*j), msg->send_name, NAME_LENGTH);
 		memcpy(WFIFOP(fd,53+73*j), msg->send_name, NAME_LENGTH);
 		WFIFOL(fd,77+73*j) = msg->timestamp;
 		WFIFOL(fd,77+73*j) = msg->timestamp;
 		j++;
 		j++;
 	}
 	}
 	WFIFOSET(fd,len);
 	WFIFOSET(fd,len);
 }
 }
+
 /*------------------------------------------
 /*------------------------------------------
  * Client Request Inbox List
  * Client Request Inbox List
  *------------------------------------------*/
  *------------------------------------------*/
 void clif_parse_Mail_refreshinbox(int fd, struct map_session_data *sd)
 void clif_parse_Mail_refreshinbox(int fd, struct map_session_data *sd)
 {
 {
 	struct mail_data *md;
 	struct mail_data *md;
-
 	nullpo_retv(sd);
 	nullpo_retv(sd);
+
 	md = &sd->mail.inbox;
 	md = &sd->mail.inbox;
 
 
 	if( md->amount < MAIL_MAX_INBOX && (md->full || md->changed) )
 	if( md->amount < MAIL_MAX_INBOX && (md->full || md->changed) )
@@ -11371,6 +11443,7 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id)
 	ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
 	ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
 	if( i == MAIL_MAX_INBOX )
 	if( i == MAIL_MAX_INBOX )
 	{
 	{
+		clif_Mail_return(sd->fd, mail_id, 1); // Mail don't exists
 		ShowWarning("clif_parse_Mail_read: account %d trying to read a message not the inbox.\n", sd->status.account_id);
 		ShowWarning("clif_parse_Mail_read: account %d trying to read a message not the inbox.\n", sd->status.account_id);
 		return;
 		return;
 	}
 	}
@@ -11397,36 +11470,26 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id)
 		WFIFOL(fd,72) = 0;
 		WFIFOL(fd,72) = 0;
 		WFIFOL(fd,76) = msg->zeny;
 		WFIFOL(fd,76) = msg->zeny;
 
 
-		if (item->nameid)
+		if( item->nameid && (data = itemdb_search(item->nameid)) != NULL )
 		{
 		{
 			WFIFOL(fd,80) = item->amount;
 			WFIFOL(fd,80) = item->amount;
-			if ((data = itemdb_search(item->nameid)) != NULL)
-				WFIFOW(fd,84) = (data->view_id)?data->view_id:item->nameid;
-			else
-				ShowWarning("clif_parse_Mail_read: Invalid attachment on message %d.\n", msg->id);
-
+			WFIFOW(fd,84) = (data->view_id)?data->view_id:item->nameid;
 			WFIFOW(fd,86) = data->type;
 			WFIFOW(fd,86) = data->type;
-		}
-		else
-		{
-			WFIFOL(fd,80) = 0;
-			WFIFOW(fd,84) = 0;
-			WFIFOW(fd,86) = 0;
+			WFIFOB(fd,88) = item->identify;
+			WFIFOB(fd,89) = item->attribute;
+			WFIFOB(fd,90) = item->refine;
+			WFIFOW(fd,91) = item->card[0];
+			WFIFOW(fd,93) = item->card[1];
+			WFIFOW(fd,95) = item->card[2];
+			WFIFOW(fd,97) = item->card[3];
 		}
 		}
 
 
-		WFIFOB(fd,88) = item->identify;
-		WFIFOB(fd,89) = item->attribute;
-		WFIFOB(fd,90) = item->refine;
-		WFIFOW(fd,91) = item->card[0];
-		WFIFOW(fd,93) = item->card[1];
-		WFIFOW(fd,95) = item->card[2];
-		WFIFOW(fd,97) = item->card[3];
 		WFIFOB(fd,99) = (unsigned char)msg_len;
 		WFIFOB(fd,99) = (unsigned char)msg_len;
 		safestrncpy((char*)WFIFOP(fd,100), msg->body, msg_len);
 		safestrncpy((char*)WFIFOP(fd,100), msg->body, msg_len);
 		WFIFOSET(fd,len);
 		WFIFOSET(fd,len);
 
 
-		if (!msg->read) {
-			msg->read = 1;
+		if (msg->status == MAIL_UNREAD) {
+			msg->status = MAIL_READED;
 			intif_Mail_read(mail_id);
 			intif_Mail_read(mail_id);
 			clif_parse_Mail_refreshinbox(fd, sd);
 			clif_parse_Mail_refreshinbox(fd, sd);
 		}
 		}
@@ -11465,10 +11528,7 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd)
 		weight = data->weight * sd->mail.inbox.msg[i].item.amount;
 		weight = data->weight * sd->mail.inbox.msg[i].item.amount;
 		if (weight > sd->max_weight - sd->weight)
 		if (weight > sd->max_weight - sd->weight)
 		{
 		{
-			WFIFOHEAD(fd,packet_len(0x245));
-			WFIFOW(fd,0) = 0x245;
-			WFIFOB(fd,2) = 2;
-			WFIFOSET(fd,packet_len(0x245));
+			clif_Mail_attachment(fd, 2);
 			return;
 			return;
 		}
 		}
 	}
 	}
@@ -11477,39 +11537,12 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd)
 	memset(&sd->mail.inbox.msg[i].item, 0, sizeof(struct item));
 	memset(&sd->mail.inbox.msg[i].item, 0, sizeof(struct item));
 	clif_Mail_read(sd, mail_id);
 	clif_Mail_read(sd, mail_id);
 
 
-	// Send the request for Char Server to delete the attachment
-	// If it is done, the client will receive it.
 	intif_Mail_getattach(sd->status.char_id, mail_id);
 	intif_Mail_getattach(sd->status.char_id, mail_id);
 }
 }
 
 
 /*------------------------------------------
 /*------------------------------------------
  * Delete Message
  * Delete Message
  *------------------------------------------*/
  *------------------------------------------*/
-void clif_Mail_delete(struct map_session_data *sd, int mail_id, bool failed)
-{
-	int fd = sd->fd;
-
-	if( !failed )
-	{
-		int i;
-		ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
-		if( i < MAIL_MAX_INBOX )
-		{
-			memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message));
-			sd->mail.inbox.amount--;
-		}
-
-		if( sd->mail.inbox.full )
-			intif_Mail_requestinbox(sd->status.char_id, 1); // Reload the Mail Inbox
-	}
-
-	WFIFOHEAD(fd, packet_len(0x257));
-	WFIFOW(fd,0) = 0x257;
-	WFIFOL(fd,2) = mail_id;
-	WFIFOW(fd,6) = failed;
-	WFIFOSET(fd, packet_len(0x257));
-}
-
 void clif_parse_Mail_delete(int fd, struct map_session_data *sd)
 void clif_parse_Mail_delete(int fd, struct map_session_data *sd)
 {
 {
 	int i, mail_id = RFIFOL(fd,2);
 	int i, mail_id = RFIFOL(fd,2);
@@ -11522,25 +11555,13 @@ void clif_parse_Mail_delete(int fd, struct map_session_data *sd)
 
 
 		if( (msg->item.nameid > 0 && msg->item.amount > 0) || msg->zeny > 0 )
 		if( (msg->item.nameid > 0 && msg->item.amount > 0) || msg->zeny > 0 )
 		{
 		{
-			clif_Mail_delete(sd, mail_id, 1);
+			clif_Mail_delete(sd->fd, mail_id, 1);
 			return;
 			return;
 		}
 		}
 		
 		
 		intif_Mail_delete(sd->status.char_id, mail_id);
 		intif_Mail_delete(sd->status.char_id, mail_id);
 	}
 	}
 }
 }
-/*------------------------------------------
- * You have Mail Message
- *------------------------------------------*/
-void clif_Mail_new(int fd, int mail_id, const char *sender, const char *title)
-{
-	WFIFOHEAD(fd,packet_len(0x24a));
-	WFIFOW(fd,0) = 0x24a;
-	WFIFOL(fd,2) = mail_id;
-	memcpy(WFIFOP(fd,6), sender, NAME_LENGTH);
-	memcpy(WFIFOP(fd,30), title, MAIL_TITLE_LENGTH);
-	WFIFOSET(fd,packet_len(0x24a));
-}
 
 
 /*------------------------------------------
 /*------------------------------------------
  * Return Mail Message
  * Return Mail Message
@@ -11553,38 +11574,8 @@ void clif_parse_Mail_return(int fd, struct map_session_data *sd)
 	ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
 	ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
 	if (i < MAIL_MAX_INBOX)
 	if (i < MAIL_MAX_INBOX)
 		intif_Mail_return(sd->status.char_id, mail_id);
 		intif_Mail_return(sd->status.char_id, mail_id);
-}
-
-void clif_Mail_return(struct map_session_data *sd, int mail_id, int new_mail)
-{
-	int fd = sd->fd;
-
-	if (new_mail > 0)
-	{
-		int i;
-		ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
-		if (i < MAIL_MAX_INBOX)
-		{
-			struct map_session_data *rd = map_charid2sd(sd->mail.inbox.msg[i].send_id);
-			if (rd)
-			{
-				char title[MAIL_TITLE_LENGTH];
-				snprintf(title, MAIL_TITLE_LENGTH, "RE:%s", sd->mail.inbox.msg[i].title);
-				
-				rd->mail.inbox.changed = 1;
-				clif_Mail_new(rd->fd, new_mail, sd->status.name, title);
-			}
-
-			memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message));
-			sd->mail.inbox.amount--;
-		}
-	}
-
-	WFIFOHEAD(fd,packet_len(0x274));
-	WFIFOW(fd,0) = 0x274;
-	WFIFOL(fd,2) = mail_id;
-	WFIFOW(fd,6) = (new_mail > 0)?0:1;
-	WFIFOSET(fd,packet_len(0x274));
+	else
+		clif_Mail_return(sd->fd, mail_id, 1);
 }
 }
 
 
 /*------------------------------------------
 /*------------------------------------------
@@ -11594,7 +11585,7 @@ void clif_parse_Mail_setattach(int fd, struct map_session_data *sd)
 {
 {
 	int idx = RFIFOW(fd,2);
 	int idx = RFIFOW(fd,2);
 	int amount = RFIFOL(fd,4);
 	int amount = RFIFOL(fd,4);
-	char flag;
+	unsigned char flag;
 
 
 	nullpo_retv(sd);
 	nullpo_retv(sd);
 	if (idx < 0 || amount < 0)
 	if (idx < 0 || amount < 0)
@@ -11602,12 +11593,7 @@ void clif_parse_Mail_setattach(int fd, struct map_session_data *sd)
 
 
 	flag = mail_setitem(sd, idx, amount);
 	flag = mail_setitem(sd, idx, amount);
 	if (flag > -1)
 	if (flag > -1)
-	{
-		WFIFOHEAD(fd,packet_len(0x245));
-		WFIFOW(fd,0) = 0x245;
-		WFIFOB(fd,2) = flag;
-		WFIFOSET(fd,packet_len(0x245));
-	}
+		clif_Mail_attachment(fd,flag);
 }
 }
 
 
 /*------------------------------------------
 /*------------------------------------------
@@ -11624,16 +11610,6 @@ void clif_parse_Mail_winopen(int fd, struct map_session_data *sd)
 		mail_removezeny(sd, 0);
 		mail_removezeny(sd, 0);
 }
 }
 
 
-/*------------------------------------------
- * Send Mail
- *------------------------------------------*/
-void clif_Mail_send(int fd, unsigned char flag)
-{
-	WFIFOHEAD(fd,packet_len(0x249));
-	WFIFOW(fd,0) = 0x249;
-	WFIFOB(fd,2) = flag;
-	WFIFOSET(fd,packet_len(0x249));
-}
 
 
 /// S 0248 <packet len>.w <nick>.24B <title>.40B <body len>.B <message>.?B
 /// S 0248 <packet len>.w <nick>.24B <title>.40B <body len>.B <message>.?B
 void clif_parse_Mail_send(int fd, struct map_session_data *sd)
 void clif_parse_Mail_send(int fd, struct map_session_data *sd)
@@ -11642,6 +11618,9 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd)
 	int body_len;
 	int body_len;
 	nullpo_retv(sd);
 	nullpo_retv(sd);
 
 
+	if( sd->state.trading )
+		return;
+
 	if( RFIFOW(fd,2) < 69 ) {
 	if( RFIFOW(fd,2) < 69 ) {
 		ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id);
 		ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id);
 		return;
 		return;
@@ -11681,7 +11660,7 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd)
 	msg.timestamp = (int)mail_calctimes();
 	msg.timestamp = (int)mail_calctimes();
 	intif_Mail_send(sd->status.account_id, &msg);
 	intif_Mail_send(sd->status.account_id, &msg);
 
 
-	sd->cansendmail_tick = gettick() + 1000; // 5 Seconds flood Protection
+	sd->cansendmail_tick = gettick() + 1000; // 1 Second flood Protection
 }
 }
 
 
 #endif
 #endif

+ 4 - 4
src/map/clif.h

@@ -386,10 +386,10 @@ int do_init_clif(void);
 // MAIL SYSTEM
 // MAIL SYSTEM
 void clif_Mail_openmail(int fd);
 void clif_Mail_openmail(int fd);
 void clif_Mail_read(struct map_session_data *sd, int mail_id);
 void clif_Mail_read(struct map_session_data *sd, int mail_id);
-void clif_Mail_delete(struct map_session_data *sd, int mail_id, bool failed);
-void clif_Mail_return(struct map_session_data *sd, int mail_id, int new_mail);
-void clif_Mail_send(int fd, unsigned char flag);
-void clif_Mail_new(int fd, int mail_id, const char *sender, const char *title);
+void clif_Mail_delete(int fd, int mail_id, short fail);
+void clif_Mail_return(int fd, int mail_id, short fail);
+void clif_Mail_send(int fd, bool fail);
+void clif_Mail_new(struct map_session_data *sd, int mail_id, const char *sender, const char *title);
 void clif_Mail_refreshinbox(struct map_session_data *sd);
 void clif_Mail_refreshinbox(struct map_session_data *sd);
 #endif
 #endif
 
 

+ 73 - 44
src/map/intif.c

@@ -34,7 +34,7 @@ static const int packet_len_table[]={
 	-1, 7, 0, 0,  0, 0, 0, 0, -1,11, 0, 0,  0, 0,  0, 0, //0x3810
 	-1, 7, 0, 0,  0, 0, 0, 0, -1,11, 0, 0,  0, 0,  0, 0, //0x3810
 	39,-1,15,15, 14,19, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0, //0x3820
 	39,-1,15,15, 14,19, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0, //0x3820
 	10,-1,15, 0, 79,19, 7,-1,  0,-1,-1,-1, 14,67,186,-1, //0x3830
 	10,-1,15, 0, 79,19, 7,-1,  0,-1,-1,-1, 14,67,186,-1, //0x3830
-	 9, 9,-1,14,  0, 0, 0, 0, -1, 0,-1,11, 14,-1,  0, 0, //0x3840
+	 9, 9,-1,14,  0, 0, 0, 0, -1,74,-1,11, 11,10,  0, 0, //0x3840
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
@@ -1538,7 +1538,7 @@ int intif_Mail_getattach(int char_id, int mail_id)
 int intif_parse_Mail_getattach(int fd)
 int intif_parse_Mail_getattach(int fd)
 {
 {
 	struct map_session_data *sd;
 	struct map_session_data *sd;
-	struct item *item;
+	struct item item;
 	int zeny = RFIFOL(fd,8);
 	int zeny = RFIFOL(fd,8);
 
 
 	sd = map_charid2sd( RFIFOL(fd,4) );
 	sd = map_charid2sd( RFIFOL(fd,4) );
@@ -1566,12 +1566,9 @@ int intif_parse_Mail_getattach(int fd)
 		clif_updatestatus(sd, SP_ZENY);
 		clif_updatestatus(sd, SP_ZENY);
 	}
 	}
 
 
-	item = (struct item*)aCalloc(sizeof(struct item), 1);
-	memcpy(item, RFIFOP(fd,12), sizeof(struct item));
-	if (item->nameid > 0 && item->amount > 0)
-		pc_additem(sd, item, item->amount);
-
-	aFree(item);
+	memcpy(&item, RFIFOP(fd,12), sizeof(struct item));
+	if (item.nameid > 0 && item.amount > 0)
+		pc_additem(sd, &item, item.amount);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1609,7 +1606,21 @@ int intif_parse_Mail_delete(int fd)
 	if (sd->state.finalsave)
 	if (sd->state.finalsave)
 		return 1;
 		return 1;
 
 
-	clif_Mail_delete(sd, mail_id, failed);
+	if (!failed)
+	{
+		int i;
+		ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
+		if( i < MAIL_MAX_INBOX )
+		{
+			memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message));
+			sd->mail.inbox.amount--;
+		}
+
+		if( sd->mail.inbox.full )
+			intif_Mail_requestinbox(sd->status.char_id, 1); // Free space is available for new mails
+	}
+
+	clif_Mail_delete(sd->fd, mail_id, failed);
 	return 0;
 	return 0;
 }
 }
 /*------------------------------------------
 /*------------------------------------------
@@ -1632,19 +1643,31 @@ int intif_Mail_return(int char_id, int mail_id)
 int intif_parse_Mail_return(int fd)
 int intif_parse_Mail_return(int fd)
 {
 {
 	struct map_session_data *sd = map_charid2sd(RFIFOL(fd,2));
 	struct map_session_data *sd = map_charid2sd(RFIFOL(fd,2));
-	int mail_id = RFIFOL(fd,6), new_mail = RFIFOL(fd,10);
+	int mail_id = RFIFOL(fd,6);
+	short fail = RFIFOB(fd,10);
 
 
-	if (sd == NULL)
+	if( sd == NULL )
 	{
 	{
 		if (battle_config.error_log)
 		if (battle_config.error_log)
 			ShowError("intif_parse_Mail_return: char not found %d\n",RFIFOL(fd,2));
 			ShowError("intif_parse_Mail_return: char not found %d\n",RFIFOL(fd,2));
 		return 1;
 		return 1;
 	}
 	}
 
 
-	if (sd->state.finalsave)
+	if( sd->state.finalsave )
 		return 1;
 		return 1;
 
 
-	clif_Mail_return(sd, mail_id, new_mail);
+	if( !fail )
+	{
+		int i;
+		ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id);
+		if (i < MAIL_MAX_INBOX)
+		{
+			memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message));
+			sd->mail.inbox.amount--;
+		}
+	}
+
+	clif_Mail_return(sd->fd, mail_id, fail);
 	return 0;
 	return 0;
 }
 }
 /*------------------------------------------
 /*------------------------------------------
@@ -1669,44 +1692,49 @@ int intif_Mail_send(int account_id, struct mail_message *msg)
 
 
 int intif_parse_Mail_send(int fd)
 int intif_parse_Mail_send(int fd)
 {
 {
-	struct map_session_data* sd = map_charid2sd(RFIFOL(fd,4));
-	int mail_id = RFIFOL(fd,8);
-	int dest_id = RFIFOL(fd,12);
-	struct map_session_data* rd;
+	struct map_session_data *sd = map_charid2sd(RFIFOL(fd,2));
+	int mail_id = RFIFOL(fd,6);
+	bool fail = false;
 
 
-	if( mail_id == 0 )
-	{// nick->charid lookup failed, no such char
-		// Return the items to the owner
-		mail_removeitem(sd, 0);
-		mail_removezeny(sd, 0);
-		clif_Mail_send(sd->fd, 1); // failed
-		return 0;
-	}
+	if( mail_id > 0 )
+	{
+		if( sd == NULL )
+			fail = true;
 
 
-	if( sd == NULL )
-	{// original sender disconnected, item cannot be deleted!
-		if( battle_config.error_log )
-			ShowError("intif_parse_Mail_send: char not found %d\n",RFIFOL(fd,2));
+		if( !mail_checkattach(sd) )
+		{
+			fail = true;
 
 
-		// the best thing we can do at this point is requesting removal of the mail with the duped item
-		intif_Mail_delete(dest_id, mail_id);
-		return 0;
-	}
+			mail_removeitem(sd, 0);
+			mail_removezeny(sd, 0);
+		}
+
+		WFIFOHEAD(inter_fd,7);
+		WFIFOW(inter_fd,0) = 0x304e;
+		WFIFOL(inter_fd,2) = mail_id;
+		WFIFOB(inter_fd,6) = fail;
+		WFIFOSET(inter_fd,7);
 
 
-	// physically delete the item
-	mail_removeitem(sd, 1);
-	mail_removezeny(sd, 1);
-	clif_Mail_send(sd->fd, 0); // success
+		clif_Mail_send(sd->fd, fail);
+	}
+	else
+		clif_Mail_send(sd->fd, true);
+	
+	return 0;
+}
 
 
-	// notify recipient about new mail
-	rd = map_charid2sd(dest_id);
-	if( rd != NULL )
+int intif_parse_Mail_new(int fd)
+{
+	struct map_session_data *sd = map_charid2sd(RFIFOL(fd,2));
+	if( sd != NULL )
 	{
 	{
-		char title[MAIL_TITLE_LENGTH];
-		memcpy(title, RFIFOP(fd,16), RFIFOW(fd,2) - 16);
+		char sender_name[NAME_LENGTH], title[MAIL_TITLE_LENGTH];
+		int mail_id = RFIFOL(fd,6);
+
+		safestrncpy(sender_name, RFIFOP(fd,10), NAME_LENGTH);
+		safestrncpy(title, RFIFOP(fd,34), MAIL_TITLE_LENGTH);
 
 
-		rd->mail.inbox.changed = 1;
-		clif_Mail_new(rd->fd, mail_id, sd->status.name, title);
+		clif_Mail_new(sd, mail_id, sender_name, title);
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -1787,6 +1815,7 @@ int intif_parse(int fd)
 // Mail System
 // Mail System
 #ifndef TXT_ONLY
 #ifndef TXT_ONLY
 	case 0x3848:	intif_parse_Mail_inboxreceived(fd); break;
 	case 0x3848:	intif_parse_Mail_inboxreceived(fd); break;
+	case 0x3849:	intif_parse_Mail_new(fd); break;
 	case 0x384a:	intif_parse_Mail_getattach(fd); break;
 	case 0x384a:	intif_parse_Mail_getattach(fd); break;
 	case 0x384b:	intif_parse_Mail_delete(fd); break;
 	case 0x384b:	intif_parse_Mail_delete(fd); break;
 	case 0x384c:	intif_parse_Mail_return(fd); break;
 	case 0x384c:	intif_parse_Mail_return(fd); break;

+ 36 - 12
src/map/mail.c

@@ -31,6 +31,7 @@ int mail_removeitem(struct map_session_data *sd, short flag)
 			clif_additem(sd, sd->mail.index, sd->mail.amount, 0);
 			clif_additem(sd, sd->mail.index, sd->mail.amount, 0);
 	}
 	}
 
 
+	sd->mail.nameid = 0;
 	sd->mail.index = 0;
 	sd->mail.index = 0;
 	sd->mail.amount = 0;
 	sd->mail.amount = 0;
 	return 1;
 	return 1;
@@ -49,10 +50,8 @@ int mail_removezeny(struct map_session_data *sd, short flag)
 	return 1;
 	return 1;
 }
 }
 
 
-char mail_setitem(struct map_session_data *sd, int idx, int amount)
+unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount)
 {
 {
-	nullpo_retr(-1,sd);
-
 	if (idx == 0)
 	if (idx == 0)
 	{ // Zeny Transfer
 	{ // Zeny Transfer
 		if (amount < 0)
 		if (amount < 0)
@@ -69,15 +68,15 @@ char mail_setitem(struct map_session_data *sd, int idx, int amount)
 		mail_removeitem(sd, 0);
 		mail_removeitem(sd, 0);
 
 
 		if( idx < 0 || idx > MAX_INVENTORY )
 		if( idx < 0 || idx > MAX_INVENTORY )
-			return 2;
+			return 1;
 		if( amount < 0 || amount > sd->status.inventory[idx].amount )
 		if( amount < 0 || amount > sd->status.inventory[idx].amount )
-			return 2;
-		if( itemdb_isdropable(&sd->status.inventory[idx], pc_isGM(sd)) == 0 )
-			return 2;
+			return 1;
+		if( !itemdb_isdropable(&sd->status.inventory[idx], pc_isGM(sd)) )
+			return 1;
 
 
 		sd->mail.index = idx;
 		sd->mail.index = idx;
+		sd->mail.nameid = sd->status.inventory[idx].nameid;
 		sd->mail.amount = amount;
 		sd->mail.amount = amount;
-
 		clif_delitem(sd, idx, amount);
 		clif_delitem(sd, idx, amount);
 
 
 		return 0;
 		return 0;
@@ -86,7 +85,7 @@ char mail_setitem(struct map_session_data *sd, int idx, int amount)
 	return -1;
 	return -1;
 }
 }
 
 
-int mail_getattach(struct map_session_data *sd, struct mail_message *msg)
+bool mail_getattach(struct map_session_data *sd, struct mail_message *msg)
 {
 {
 	int n;
 	int n;
 	
 	
@@ -94,13 +93,16 @@ int mail_getattach(struct map_session_data *sd, struct mail_message *msg)
 	nullpo_retr(0,msg);
 	nullpo_retr(0,msg);
 
 
 	if( sd->mail.zeny < 0 || sd->mail.zeny > sd->status.zeny )
 	if( sd->mail.zeny < 0 || sd->mail.zeny > sd->status.zeny )
-		return 0;
+		return false;
 
 
 	n = sd->mail.index;
 	n = sd->mail.index;
 	if( sd->mail.amount )
 	if( sd->mail.amount )
 	{
 	{
+		if( sd->status.inventory[n].nameid != sd->mail.nameid )
+			return false;
+
 		if( sd->status.inventory[n].amount < sd->mail.amount )
 		if( sd->status.inventory[n].amount < sd->mail.amount )
-			return 0;
+			return false;
 
 
 		memcpy(&msg->item, &sd->status.inventory[n], sizeof(struct item));
 		memcpy(&msg->item, &sd->status.inventory[n], sizeof(struct item));
 		msg->item.amount = sd->mail.amount;
 		msg->item.amount = sd->mail.amount;
@@ -108,7 +110,29 @@ int mail_getattach(struct map_session_data *sd, struct mail_message *msg)
 
 
 	msg->zeny = sd->mail.zeny;
 	msg->zeny = sd->mail.zeny;
 
 
-	return 1;
+	return true;
+}
+
+bool mail_checkattach(struct map_session_data *sd)
+{
+	nullpo_retr(false,sd);
+
+	if( sd->mail.zeny > 0 && sd->status.zeny < sd->status.zeny )
+		return false;
+
+	if( sd->mail.amount > 0 )
+	{
+		if( sd->status.inventory[sd->mail.index].nameid != sd->mail.nameid )
+			return false;
+
+		if( sd->status.inventory[sd->mail.index].amount < sd->mail.amount )
+			return false;
+	}
+
+	mail_removeitem(sd,1);
+	mail_removezeny(sd,1);
+
+	return true;
 }
 }
 
 
 int mail_openmail(struct map_session_data *sd)
 int mail_openmail(struct map_session_data *sd)

+ 3 - 2
src/map/mail.h

@@ -10,8 +10,9 @@ time_t mail_calctimes(void);
 
 
 int mail_removeitem(struct map_session_data *sd, short flag);
 int mail_removeitem(struct map_session_data *sd, short flag);
 int mail_removezeny(struct map_session_data *sd, short flag);
 int mail_removezeny(struct map_session_data *sd, short flag);
-char mail_setitem(struct map_session_data *sd, int idx, int amount);
-int mail_getattach(struct map_session_data *sd, struct mail_message *msg);
+unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount);
+bool mail_getattach(struct map_session_data *sd, struct mail_message *msg);
+bool mail_checkattach(struct map_session_data *sd);
 int mail_openmail(struct map_session_data *sd);
 int mail_openmail(struct map_session_data *sd);
 
 
 #endif /* _MAIL_H_ */
 #endif /* _MAIL_H_ */

+ 1 - 0
src/map/map.h

@@ -803,6 +803,7 @@ struct map_session_data {
 
 
 	// Mail System [Zephyrus]
 	// Mail System [Zephyrus]
 	struct {
 	struct {
+		short nameid;
 		int index, amount, zeny;
 		int index, amount, zeny;
 		struct mail_data inbox;
 		struct mail_data inbox;
 	} mail;
 	} mail;