diff options
-rw-r--r-- | Changelog-Trunk.txt | 3 | ||||
-rw-r--r-- | db/packet_db.txt | 16 | ||||
-rw-r--r-- | sql-files/mail.sql | 33 | ||||
-rw-r--r-- | src/char_sql/Makefile.in | 3 | ||||
-rw-r--r-- | src/char_sql/char.c | 3 | ||||
-rw-r--r-- | src/char_sql/char.h | 1 | ||||
-rw-r--r-- | src/char_sql/int_mail.c | 476 | ||||
-rw-r--r-- | src/char_sql/int_mail.h | 12 | ||||
-rw-r--r-- | src/char_sql/inter.c | 49 | ||||
-rw-r--r-- | src/char_sql/inter.h | 7 | ||||
-rw-r--r-- | src/common/mmo.h | 31 | ||||
-rw-r--r-- | src/map/atcommand.c | 108 | ||||
-rw-r--r-- | src/map/atcommand.h | 8 | ||||
-rw-r--r-- | src/map/clif.c | 423 | ||||
-rw-r--r-- | src/map/clif.h | 10 | ||||
-rw-r--r-- | src/map/intif.c | 281 | ||||
-rw-r--r-- | src/map/intif.h | 9 | ||||
-rw-r--r-- | src/map/mail.c | 375 | ||||
-rw-r--r-- | src/map/mail.h | 13 | ||||
-rw-r--r-- | src/map/map.c | 67 | ||||
-rw-r--r-- | src/map/map.h | 14 | ||||
-rw-r--r-- | src/map/pc.c | 10 | ||||
-rw-r--r-- | src/map/script.c | 16 | ||||
-rw-r--r-- | vcproj-8/char-server_sql.vcproj | 10 |
24 files changed, 1462 insertions, 516 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index a1f5e854d..3eca6b5ae 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -6,6 +6,9 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2007/10/22 * Heat isn't supposed to consume SP when used against players [Playtester] - please report if it still consumes SP in pvp + * Added the new mail system implementation (Requires more test and + optimizations) [Zephyrus] + - Updated the mail DB structure. 2007/10/21 * Fixed a small mistake in r11503 causing a fatal error&exit on unix when you try to do a graceful exit (by ctrl+c for example) [ultramage] diff --git a/db/packet_db.txt b/db/packet_db.txt index c872c8ef6..ccdd2a17e 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -754,17 +754,17 @@ packet_ver: 18 0x0190,21,actionrequest,5:20 0x0216,6 //Start mail system? -0x023f,2 +0x023f,2,mailrefresh,0 0x0240,8 -0x0241,6 +0x0241,6,mailread,2 0x0242,-1 -0x0243,6 -0x0244,6 +0x0243,6,maildelete,2 +0x0244,6,mailgetattach,2 0x0245,7 //Start writing a mail? -0x0246,4 +0x0246,4,mailwinopen,2 //Send Item/Zeny -0x0247,8 +0x0247,8,mailsetattach,2:4 //Message 0x0248,68 //Delivered? @@ -811,7 +811,7 @@ packet_ver: 19 //2005-08-29aSakexe 0x0240,-1 -0x0248,-1 +0x0248,-1,mailsend,2:4:28:68 0x0255,5 0x0256,0 0x0257,8 @@ -871,7 +871,7 @@ packet_ver: 19 0x0274,8 //2006-03-13aSakexe -0x0273,30 +0x0273,30,mailreturn,2:6 //2006-03-27aSakexe packet_ver: 20 diff --git a/sql-files/mail.sql b/sql-files/mail.sql index 62cc9d65d..b5fd22ead 100644 --- a/sql-files/mail.sql +++ b/sql-files/mail.sql @@ -1,12 +1,23 @@ +DROP TABLE IF EXISTS `mail`; CREATE TABLE `mail` ( - `message_id` int(11) NOT NULL auto_increment, - `to_account_id` int(11) NOT NULL default '0', - `to_char_name` varchar(24) NOT NULL default '', - `from_account_id` int(11) NOT NULL default '0', - `from_char_name` varchar(24) NOT NULL default '', - `message` varchar(80) NOT NULL default '', - `read_flag` tinyint(1) NOT NULL default '0', - `priority` tinyint(1) NOT NULL default '0', - `check_flag` tinyint(1) NOT NULL default '0', - PRIMARY KEY (`message_id`) -) TYPE=MyISAM; + `id` bigint(20) unsigned NOT NULL auto_increment, + `send_name` tinytext NOT NULL DEFAULT '', + `send_id` int(11) unsigned NOT NULL default '0', + `dest_name` tinytext NOT NULL DEFAULT '', + `dest_id` int(11) unsigned NOT NULL default '0', + `title` tinytext NOT NULL DEFAULT '', + `message` text NOT NULL DEFAULT '', + `time` int(11) unsigned NOT NULL default '0', + `read_flag` tinyint(1) unsigned NOT NULL default '0', + `zeny` int(11) unsigned NOT NULL default '0', + `nameid` int(11) unsigned NOT NULL default '0', + `amount` int(11) unsigned NOT NULL default '0', + `refine` tinyint(3) unsigned NOT NULL default '0', + `attribute` tinyint(4) unsigned NOT NULL default '0', + `identify` smallint(6) NOT NULL default '0', + `card0` smallint(11) NOT NULL default '0', + `card1` smallint(11) NOT NULL default '0', + `card2` smallint(11) NOT NULL default '0', + `card3` smallint(11) NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM; diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index b47869208..685d4286d 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -9,7 +9,7 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/strlib.h ../common/grfio.h \ ../common/mapindex.h ../common/ers.h ../common/sql.h -CHAR_OBJ = char.o inter.o int_party.o int_guild.o int_storage.o int_pet.o int_homun.o +CHAR_OBJ = char.o inter.o int_party.o int_guild.o int_storage.o int_pet.o int_homun.o int_mail.o HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) @@ -54,3 +54,4 @@ int_guild.o: int_guild.c int_guild.h inter.h $(COMMON_H) int_storage.o: int_storage.c int_storage.h char.h $(COMMON_H) int_pet.o: int_pet.c int_pet.h inter.h char.h $(COMMON_H) int_homun.o: int_homun.c int_homun.h inter.h char.h $(COMMON_H) +int_mail.o: int_mail.c int_mail.h inter.h char.h $(COMMON_H)
\ No newline at end of file diff --git a/src/char_sql/char.c b/src/char_sql/char.c index d66bbe1f2..649d4c368 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -59,6 +59,7 @@ char guild_skill_db[256] = "guild_skill"; char guild_storage_db[256] = "guild_storage"; char party_db[256] = "party"; char pet_db[256] = "pet"; +char mail_db[256] = "mail"; // MAIL SYSTEM char friend_db[256] = "friends"; char hotkey_db[256] = "hotkey"; @@ -3447,6 +3448,8 @@ void sql_config_read(const char* cfgName) strcpy(party_db,w2); else if(!strcmpi(w1,"pet_db")) strcpy(pet_db,w2); + else if(!strcmpi(w1,"mail_db")) + strcpy(mail_db,w2); else if(!strcmpi(w1,"friend_db")) strcpy(friend_db,w2); else if(!strcmpi(w1,"hotkey_db")) diff --git a/src/char_sql/char.h b/src/char_sql/char.h index c99d1e16a..63f302808 100644 --- a/src/char_sql/char.h +++ b/src/char_sql/char.h @@ -57,6 +57,7 @@ extern char guild_skill_db[256]; extern char guild_storage_db[256]; extern char party_db[256]; extern char pet_db[256]; +extern char mail_db[256]; extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris] diff --git a/src/char_sql/int_mail.c b/src/char_sql/int_mail.c new file mode 100644 index 000000000..4c21861c3 --- /dev/null +++ b/src/char_sql/int_mail.c @@ -0,0 +1,476 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "../common/mmo.h"
+#include "../common/malloc.h"
+#include "../common/showmsg.h"
+#include "../common/socket.h"
+#include "../common/strlib.h"
+#include "../common/sql.h"
+#include "char.h"
+#include "inter.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct mail_data *mail_data_pt = NULL;
+
+time_t calc_times(void)
+{
+ time_t temp = time(NULL);
+ return mktime(localtime(&temp));
+}
+
+int mail_fromsql(int char_id, struct mail_data *md)
+{
+ int i, j;
+ struct mail_message *msg;
+ struct item *item;
+ char *data;
+ StringBuf buf;
+
+ memset(md, 0, sizeof(struct mail_data));
+ md->amount = 0;
+ md->satured = 0;
+
+ StringBuf_Init(&buf);
+ StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`read_flag`,"
+ "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`");
+ for (i = 0; i < MAX_SLOTS; 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, MAX_MAIL_INBOX + 1);
+
+ if( SQL_ERROR == Sql_Query(mail_handle, StringBuf_Value(&buf)) )
+ Sql_ShowDebug(mail_handle);
+
+ StringBuf_Destroy(&buf);
+
+ for (i = 0; i < MAX_MAIL_INBOX && SQL_SUCCESS == Sql_NextRow(mail_handle); ++i )
+ {
+ msg = &md->msg[i];
+ Sql_GetData(mail_handle, 0, &data, NULL); msg->id = atoi(data);
+ Sql_GetData(mail_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH);
+ Sql_GetData(mail_handle, 2, &data, NULL); msg->send_id = atoi(data);
+ Sql_GetData(mail_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH);
+ Sql_GetData(mail_handle, 4, &data, NULL); msg->dest_id = atoi(data);
+ Sql_GetData(mail_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH);
+ Sql_GetData(mail_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH);
+ Sql_GetData(mail_handle, 7, &data, NULL); msg->timestamp = atoi(data);
+ Sql_GetData(mail_handle, 8, &data, NULL); msg->read = atoi(data);
+ Sql_GetData(mail_handle, 9, &data, NULL); msg->zeny = atoi(data);
+ item = &msg->item;
+ Sql_GetData(mail_handle,10, &data, NULL); item->amount = (short)atoi(data);
+ Sql_GetData(mail_handle,11, &data, NULL); item->nameid = atoi(data);
+ Sql_GetData(mail_handle,12, &data, NULL); item->refine = atoi(data);
+ Sql_GetData(mail_handle,13, &data, NULL); item->attribute = atoi(data);
+ Sql_GetData(mail_handle,14, &data, NULL); item->identify = atoi(data);
+
+ for (j = 0; j < MAX_SLOTS; j++)
+ {
+ Sql_GetData(mail_handle, 15 + j, &data, NULL);
+ item->card[j] = atoi(data);
+ }
+ }
+
+ if ( SQL_SUCCESS == Sql_NextRow(mail_handle) )
+ md->satured = 1; // New Mails cannot arrive
+ else
+ md->satured = 0;
+
+ md->amount = i;
+ md->changed = 0;
+ Sql_FreeResult(mail_handle);
+
+ md->unchecked = 0;
+ md->unreaded = 0;
+ for (i = 0; i < md->amount; i++)
+ {
+ msg = &md->msg[i];
+ if (!msg->read)
+ {
+ if ( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `read_flag` = '1' WHERE `id` = '%d'", mail_db, msg->id) )
+ Sql_ShowDebug(mail_handle);
+
+ md->unchecked++;
+ }
+ else if ( msg->read == 1 )
+ md->unreaded++;
+
+ msg->read = (msg->read < 2)?0:1;
+ }
+
+ ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount);
+ return 1;
+}
+
+int mail_savemessage(struct mail_message *msg)
+{
+ StringBuf buf;
+ int j;
+ char esc_send_name[NAME_LENGTH*2+1], esc_dest_name[NAME_LENGTH*2+1];
+ char esc_title[MAIL_TITLE_LENGTH*2+1], esc_body[MAIL_BODY_LENGTH*2+1];
+
+ if (!msg)
+ return 0;
+
+ Sql_EscapeStringLen(mail_handle, esc_send_name, msg->send_name, strnlen(msg->send_name, NAME_LENGTH));
+ Sql_EscapeStringLen(mail_handle, esc_dest_name, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH));
+ Sql_EscapeStringLen(mail_handle, esc_title, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH));
+ Sql_EscapeStringLen(mail_handle, esc_body, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH));
+
+ 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);
+ for (j = 0; j < MAX_SLOTS; j++)
+ StringBuf_Printf(&buf, ", `card%d`", j);
+ StringBuf_Printf(&buf, ") VALUES ('%s', '%d', '%s', '%d', '%s', '%s', '%d', '0', '%d', '%d', '%d', '%d', '%d', '%d'",
+ esc_send_name, msg->send_id, esc_dest_name, msg->dest_id, esc_title, esc_body, msg->timestamp, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify);
+ for (j = 0; j < MAX_SLOTS; j++)
+ StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]);
+ StringBuf_AppendStr(&buf, ")");
+
+ if( SQL_ERROR == Sql_QueryStr(mail_handle, StringBuf_Value(&buf)) )
+ {
+ Sql_ShowDebug(mail_handle);
+ j = 0;
+ }
+ else
+ j = (int)Sql_LastInsertId(mail_handle);
+
+ StringBuf_Destroy(&buf);
+
+ return j;
+}
+
+int mail_loadmessage(int char_id, int mail_id, struct mail_message *message, short flag)
+{
+ char *data;
+ struct item *item;
+ int j = 0;
+ StringBuf buf;
+
+ StringBuf_Init(&buf);
+ StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`read_flag`,"
+ "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`");
+ for (j = 0; j < MAX_SLOTS; 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);
+
+ if( SQL_ERROR == Sql_Query(mail_handle, StringBuf_Value(&buf)) )
+ Sql_ShowDebug(mail_handle);
+ else if( Sql_NumRows(mail_handle) == 0 )
+ ShowWarning("Char %d trying to read an invalid mail.\n", char_id);
+ else
+ {
+ Sql_NextRow(mail_handle);
+
+ Sql_GetData(mail_handle, 0, &data, NULL); message->id = atoi(data);
+ Sql_GetData(mail_handle, 1, &data, NULL); safestrncpy(message->send_name, data, NAME_LENGTH);
+ Sql_GetData(mail_handle, 2, &data, NULL); message->send_id = atoi(data);
+ Sql_GetData(mail_handle, 3, &data, NULL); safestrncpy(message->dest_name, data, NAME_LENGTH);
+ Sql_GetData(mail_handle, 4, &data, NULL); message->dest_id = atoi(data);
+ Sql_GetData(mail_handle, 5, &data, NULL); safestrncpy(message->title, data, MAIL_TITLE_LENGTH);
+ Sql_GetData(mail_handle, 6, &data, NULL); safestrncpy(message->body, data, MAIL_BODY_LENGTH);
+ Sql_GetData(mail_handle, 7, &data, NULL); message->timestamp = atoi(data);
+ Sql_GetData(mail_handle, 8, &data, NULL); message->read = atoi(data);
+ Sql_GetData(mail_handle, 9, &data, NULL); message->zeny = atoi(data);
+ item = &message->item;
+ Sql_GetData(mail_handle,10, &data, NULL); item->amount = (short)atoi(data);
+ Sql_GetData(mail_handle,11, &data, NULL); item->nameid = atoi(data);
+ Sql_GetData(mail_handle,12, &data, NULL); item->refine = atoi(data);
+ Sql_GetData(mail_handle,13, &data, NULL); item->attribute = atoi(data);
+ Sql_GetData(mail_handle,14, &data, NULL); item->identify = atoi(data);
+ for (j = 0; j < MAX_SLOTS; j++)
+ {
+ Sql_GetData(mail_handle,15 + j, &data, NULL);
+ item->card[j] = atoi(data);
+ }
+
+ j = 1;
+ }
+
+ StringBuf_Destroy(&buf);
+ Sql_FreeResult(mail_handle);
+
+ if (message->read == 1)
+ {
+ message->read = 0;
+ if (flag)
+ if ( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `read_flag` = '2' WHERE `id` = '%d'", mail_db, message->id) )
+ Sql_ShowDebug(mail_handle);
+ }
+ else
+ message->read = 1;
+
+ return j;
+}
+
+/*==========================================
+ * Client Inbox Request
+ *------------------------------------------*/
+int mapif_Mail_sendinbox(int fd, int char_id, unsigned char flag)
+{
+ WFIFOHEAD(fd, sizeof(struct mail_data) + 9);
+ mail_fromsql(char_id, mail_data_pt);
+ WFIFOW(fd,0) = 0x3848;
+ WFIFOW(fd,2) = sizeof(struct mail_data) + 9;
+ WFIFOL(fd,4) = char_id;
+ WFIFOB(fd,8) = flag;
+ memcpy(WFIFOP(fd,9),mail_data_pt,sizeof(struct mail_data));
+ WFIFOSET(fd,WFIFOW(fd,2));
+
+ return 0;
+}
+
+int mapif_parse_Mail_requestinbox(int fd)
+{
+ RFIFOHEAD(fd);
+ mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6));
+
+ return 0;
+}
+
+/*==========================================
+ * Mail Readed Mark
+ *------------------------------------------*/
+int mapif_parse_Mail_read(int fd)
+{
+ int mail_id;
+ RFIFOHEAD(fd);
+
+ mail_id = RFIFOL(fd,2);
+ if( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `read_flag` = '2' WHERE `id` = '%d'", mail_db, mail_id) )
+ Sql_ShowDebug(mail_handle);
+
+ return 0;
+}
+
+/*==========================================
+ * Client Attachment Request
+ *------------------------------------------*/
+int mail_DeleteAttach(int mail_id)
+{
+ StringBuf buf;
+ int i;
+
+ StringBuf_Init(&buf);
+ StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db);
+ for (i = 0; i < MAX_SLOTS; i++)
+ StringBuf_Printf(&buf, ", `card%d` = '0'", i);
+ StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id);
+
+ if( SQL_ERROR == Sql_Query(mail_handle, StringBuf_Value(&buf)) )
+ {
+ Sql_ShowDebug(mail_handle);
+ StringBuf_Destroy(&buf);
+
+ return 0;
+ }
+
+ StringBuf_Destroy(&buf);
+ return 1;
+}
+
+int mapif_Mail_getattach(int fd, int char_id, int mail_id)
+{
+ struct mail_message *message = (struct mail_message*)aCalloc(sizeof(struct mail_message), 1);
+
+ if( mail_loadmessage(char_id, mail_id, message, 0) )
+ {
+ if( (message->item.nameid < 1 || message->item.amount < 1) && message->zeny < 1 )
+ {
+ aFree(message);
+ return 0; // No Attachment
+ }
+
+ if( mail_DeleteAttach(mail_id) )
+ {
+ WFIFOHEAD(fd, sizeof(struct item) + 12);
+ WFIFOW(fd,0) = 0x384a;
+ WFIFOW(fd,2) = sizeof(struct item) + 12;
+ WFIFOL(fd,4) = char_id;
+ WFIFOL(fd,8) = (message->zeny > 0)?message->zeny:0;
+ memcpy(WFIFOP(fd,12), &message->item, sizeof(struct item));
+ WFIFOSET(fd,WFIFOW(fd,2));
+ }
+ }
+
+ aFree(message);
+ return 0;
+}
+
+int mapif_parse_Mail_getattach(int fd)
+{
+ RFIFOHEAD(fd);
+ mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6));
+ return 0;
+}
+
+/*==========================================
+ * Delete Mail
+ *------------------------------------------*/
+int mapif_Mail_delete(int fd, int char_id, int mail_id)
+{
+ short flag = 0;
+
+ if ( SQL_ERROR == Sql_Query(mail_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) )
+ {
+ Sql_ShowDebug(mail_handle);
+ flag = 1;
+ }
+
+ WFIFOHEAD(fd,11);
+ WFIFOW(fd,0) = 0x384b;
+ WFIFOL(fd,2) = char_id;
+ WFIFOL(fd,6) = mail_id;
+ WFIFOW(fd,10) = flag;
+ WFIFOSET(fd,12);
+
+ return 0;
+}
+
+int mapif_parse_Mail_delete(int fd)
+{
+ RFIFOHEAD(fd);
+ mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6));
+ return 0;
+}
+/*==========================================
+ * Return Mail
+ *------------------------------------------*/
+int mapif_Mail_return(int fd, int char_id, int mail_id)
+{
+ struct mail_message *msg = (struct mail_message*)aCalloc(sizeof(struct mail_message), 1);
+ int new_mail = 0;
+
+ if( mail_loadmessage(char_id, mail_id, msg, 0) )
+ {
+ if( SQL_ERROR == Sql_Query(mail_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) )
+ Sql_ShowDebug(mail_handle);
+ else
+ {
+ char temp_[MAIL_TITLE_LENGTH];
+
+ swap(msg->send_id, msg->dest_id);
+ safestrncpy(temp_, msg->send_name, NAME_LENGTH);
+ safestrncpy(msg->send_name, msg->dest_name, NAME_LENGTH);
+ safestrncpy(msg->dest_name, temp_, NAME_LENGTH);
+
+ snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg->title);
+ safestrncpy(msg->title, temp_, MAIL_TITLE_LENGTH);
+ msg->timestamp = (unsigned int)calc_times();
+
+ new_mail = mail_savemessage(msg);
+ }
+ }
+
+ aFree(msg);
+
+ WFIFOHEAD(fd,14);
+ WFIFOW(fd,0) = 0x384c;
+ WFIFOL(fd,2) = char_id;
+ WFIFOL(fd,6) = mail_id;
+ WFIFOL(fd,10) = new_mail;
+ WFIFOSET(fd,14);
+
+ return 0;
+}
+
+int mapif_parse_Mail_return(int fd)
+{
+ RFIFOHEAD(fd);
+ mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6));
+ return 0;
+}
+
+int mapif_Mail_send(int fd, struct mail_message *msg)
+{
+ int len = strlen(msg->title) + 16;
+
+ WFIFOHEAD(fd,len);
+ WFIFOW(fd,0) = 0x384d;
+ WFIFOW(fd,2) = len;
+ WFIFOL(fd,4) = msg->send_id;
+ WFIFOL(fd,8) = msg->id;
+ WFIFOL(fd,12) = msg->dest_id;
+ memcpy(WFIFOP(fd,16), msg->title, strlen(msg->title));
+ WFIFOSET(fd,len);
+
+ return 0;
+}
+
+int mapif_parse_Mail_send(int fd)
+{
+ struct mail_message *msg;
+ int mail_id = 0, account_id = 0;
+
+ if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message))
+ return 0;
+
+ msg = (struct mail_message*)aCalloc(sizeof(struct mail_message), 1);
+ memcpy(msg, RFIFOP(fd,8), sizeof(struct mail_message));
+
+ account_id = RFIFOL(fd,4);
+
+ if( !msg->dest_id )
+ {
+ // Try to find the Dest Char by Name
+ char esc_name[NAME_LENGTH*2+1];
+
+ Sql_EscapeStringLen(sql_handle, esc_name, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH));
+ if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
+ Sql_ShowDebug(sql_handle);
+ else if ( Sql_NumRows(sql_handle) > 0 )
+ {
+ char *data;
+ Sql_NextRow(sql_handle);
+ Sql_GetData(sql_handle, 0, &data, NULL);
+ if (atoi(data) != account_id)
+ { // Cannot sends mail to char in the same account
+ Sql_GetData(sql_handle, 1, &data, NULL);
+ msg->dest_id = atoi(data);
+ }
+ }
+ Sql_FreeResult(sql_handle);
+ }
+
+ if( msg->dest_id > 0 )
+ mail_id = mail_savemessage(msg);
+
+ msg->id = mail_id;
+ mapif_Mail_send(fd, msg);
+
+ aFree(msg);
+ return 0;
+}
+
+/*==========================================
+ * Packets From Map Server
+ *------------------------------------------*/
+int inter_mail_parse_frommap(int fd)
+{
+ switch(RFIFOW(fd,0))
+ {
+ case 0x3048: mapif_parse_Mail_requestinbox(fd); break;
+ case 0x3049: mapif_parse_Mail_read(fd); break;
+ case 0x304a: mapif_parse_Mail_getattach(fd); break;
+ case 0x304b: mapif_parse_Mail_delete(fd); break;
+ case 0x304c: mapif_parse_Mail_return(fd); break;
+ case 0x304d: mapif_parse_Mail_send(fd); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int inter_mail_sql_init(void)
+{
+ mail_data_pt = (struct mail_data*)aCalloc(sizeof(struct mail_data), 1);
+ return 1;
+}
+
+void inter_mail_sql_final(void)
+{
+ if (mail_data_pt) aFree(mail_data_pt);
+ return;
+}
diff --git a/src/char_sql/int_mail.h b/src/char_sql/int_mail.h new file mode 100644 index 000000000..4561e1736 --- /dev/null +++ b/src/char_sql/int_mail.h @@ -0,0 +1,12 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INT_MAIL_SQL_H_
+#define _INT_MAIL_SQL_H_
+
+int inter_mail_parse_frommap(int fd);
+
+int inter_mail_sql_init(void);
+void inter_mail_sql_final(void);
+
+#endif /* _INT_MAIL_SQL_H_ */
diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c index ab03e102b..e37c258a1 100644 --- a/src/char_sql/inter.c +++ b/src/char_sql/inter.c @@ -15,6 +15,7 @@ #include "int_storage.h" #include "int_pet.h" #include "int_homun.h" +#include "int_mail.h" #include <stdio.h> #include <string.h> @@ -26,6 +27,7 @@ Sql* sql_handle = NULL; Sql* lsql_handle = NULL; +Sql* mail_handle = NULL; int char_server_port = 3306; char char_server_ip[32] = "127.0.0.1"; @@ -40,6 +42,12 @@ char login_server_id[32] = "ragnarok"; char login_server_pw[32] = "ragnarok"; char login_server_db[32] = "ragnarok"; +int mail_server_port = 3306; +char mail_server_ip[32] = "127.0.0.1"; +char mail_server_id[32] = "ragnarok"; +char mail_server_pw[32] = "ragnarok"; +char mail_server_db[32] = "ragnarok"; + #ifndef TXT_SQL_CONVERT static struct accreg *accreg_pt; @@ -53,7 +61,7 @@ int inter_send_packet_length[] = { -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- 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, 0, 0, 0, 0, 0, 0, 0, 0, // 3840- + 9, 9,-1, 0, 0, 0, 0, 0, -1, 0,-1,12, 14,-1, 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, // 3860- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3870- @@ -65,7 +73,7 @@ int inter_recv_packet_length[] = { 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,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, // 3030- - 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3040- + 5, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 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, // 3060- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3070- @@ -270,6 +278,28 @@ static int inter_config_read(const char* cfgName) strcpy(login_server_db, w2); ShowStatus ("set login_server_db : %s\n", w2); } + // MAIL SYSTEM + else + if(!strcmpi(w1,"mail_server_ip")) { + strcpy(mail_server_ip, w2); + ShowStatus ("set mail_server_ip : %s\n", w2); + } else + if(!strcmpi(w1,"mail_server_port")) { + mail_server_port = atoi(w2); + ShowStatus ("set mail_server_port : %s\n", w2); + } else + if(!strcmpi(w1,"mail_server_id")) { + strcpy(mail_server_id, w2); + ShowStatus ("set mail_server_id : %s\n", w2); + } else + if(!strcmpi(w1,"mail_server_pw")) { + strcpy(mail_server_pw, w2); + ShowStatus ("set mail_server_pw : %s\n", w2); + } else + if(!strcmpi(w1,"mail_server_db")) { + strcpy(mail_server_db, w2); + ShowStatus ("set mail_server_db : %s\n", w2); + } #ifndef TXT_SQL_CONVERT else if(!strcmpi(w1,"party_share_level")) party_share_level = atoi(w2); @@ -314,6 +344,7 @@ int inter_sql_ping(int tid, unsigned int tick, int id, int data) { ShowInfo("Pinging SQL server to keep connection alive...\n"); Sql_Ping(sql_handle); + Sql_Ping(mail_handle); if( char_gm_read ) Sql_Ping(lsql_handle); return 0; @@ -358,6 +389,16 @@ int inter_init_sql(const char *file) Sql_Free(sql_handle); exit(EXIT_FAILURE); } + // MAIL SYSTEM + mail_handle = Sql_Malloc(); + ShowInfo("Connect Mail DB server.... (Character Server)\n"); + if ( SQL_ERROR == Sql_Connect(mail_handle, mail_server_id, mail_server_pw, mail_server_ip, (uint16)mail_server_port, mail_server_db) ) + { + Sql_ShowDebug(mail_handle); + Sql_Free(mail_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } #ifndef TXT_SQL_CONVERT else if (inter_sql_test()) { ShowStatus("Connect Success! (Character Server)\n"); @@ -370,6 +411,7 @@ int inter_init_sql(const char *file) { Sql_ShowDebug(lsql_handle); Sql_Free(lsql_handle); + Sql_Free(mail_handle); Sql_Free(sql_handle); exit(EXIT_FAILURE); } @@ -396,6 +438,7 @@ int inter_init_sql(const char *file) inter_pet_sql_init(); inter_homunculus_sql_init(); // albator inter_accreg_sql_init(); + inter_mail_sql_init(); sql_ping_init(); #endif //TXT_SQL_CONVERT @@ -429,6 +472,7 @@ int inter_sql_test (void) ShowSQL ("Field `%s` not be found in `%s`. Consider updating your database!\n", fields[i], char_db); if( lsql_handle ) Sql_Free(lsql_handle); + Sql_Free(mail_handle); Sql_Free(sql_handle); exit(EXIT_FAILURE); } @@ -863,6 +907,7 @@ int inter_parse_frommap(int fd) || inter_storage_parse_frommap(fd) || inter_pet_parse_frommap(fd) || inter_homunculus_parse_frommap(fd) + || inter_mail_parse_frommap(fd) ) break; else diff --git a/src/char_sql/inter.h b/src/char_sql/inter.h index c79290c80..3f4999e5a 100644 --- a/src/char_sql/inter.h +++ b/src/char_sql/inter.h @@ -26,6 +26,7 @@ extern char inter_log_filename[1024]; extern Sql* sql_handle; extern Sql* lsql_handle; +extern Sql* mail_handle; extern int char_server_port; extern char char_server_ip[32]; @@ -39,6 +40,12 @@ extern char login_db_server_id[32]; extern char login_db_server_pw[32]; extern char login_db_server_db[32]; +extern int mail_server_port; +extern char mail_server_ip[32]; +extern char mail_server_id[32]; +extern char mail_server_pw[32]; +extern char mail_server_db[32]; + extern char main_chat_nick[16]; int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type); diff --git a/src/common/mmo.h b/src/common/mmo.h index abbce9d52..5374cf9b4 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -105,6 +105,11 @@ #define HM_CLASS_BASE 6001 #define HM_CLASS_MAX (HM_CLASS_BASE+MAX_HOMUNCULUS_CLASS-1) +//Mail System +#define MAX_MAIL_INBOX 30 +#define MAIL_TITLE_LENGTH 40 +#define MAIL_BODY_LENGTH 200 + struct item { int id; short nameid; @@ -236,6 +241,32 @@ struct mmo_charstatus { #endif }; +struct mail_message { + unsigned int id; + int send_id; + char send_name[NAME_LENGTH]; + int dest_id; + char dest_name[NAME_LENGTH]; + + char title[MAIL_TITLE_LENGTH]; + char body[MAIL_BODY_LENGTH]; + + unsigned char read; + unsigned int timestamp; + + int zeny; + struct item item; +}; + +struct mail_data { + short amount; + short changed; + short satured; + struct mail_message msg[MAX_MAIL_INBOX]; + + short unchecked, unreaded; +}; + struct registry { int global_num; struct global_reg global[GLOBAL_REG_NUM]; diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 5bcd80590..5ed008419 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -270,13 +270,7 @@ ACMD_FUNC(homshuffle); //[Skotlex] ACMD_FUNC(showmobs); //KarLaeda ACMD_FUNC(feelreset); //[HiddenDragon] #ifndef TXT_ONLY -ACMD_FUNC(checkmail); // [Valaris] -ACMD_FUNC(listmail); // [Valaris] -ACMD_FUNC(listnewmail); // [Valaris] -ACMD_FUNC(readmail); // [Valaris] -ACMD_FUNC(deletemail); // [Valaris] -ACMD_FUNC(sendmail); // [Valaris] -ACMD_FUNC(sendprioritymail); // [Valaris] +ACMD_FUNC(mail); // [MAIL SYSTEM] ACMD_FUNC(refreshonline); // [Valaris] #endif #ifdef DMALLOC @@ -574,13 +568,7 @@ static AtCommandInfo atcommand_info[] = { { AtCommand_ShowMobs, "@showmobs", 10, atcommand_showmobs }, //KarLaeda { AtCommand_FeelReset, "@feelreset", 10, atcommand_feelreset }, //[HiddenDragon] #ifndef TXT_ONLY // sql-only commands - { AtCommand_CheckMail, "@checkmail", 1, atcommand_listmail }, // [Valaris] - { AtCommand_ListMail, "@listmail", 1, atcommand_listmail }, // [Valaris] - { AtCommand_ListNewMail, "@listnewmail", 1, atcommand_listmail }, // [Valaris] - { AtCommand_ReadMail, "@readmail", 1, atcommand_readmail }, // [Valaris] - { AtCommand_DeleteMail, "@deletemail", 1, atcommand_deletemail }, // [Valaris] - { AtCommand_SendMail, "@sendmail", 1, atcommand_sendmail }, // [Valaris] - { AtCommand_SendPriorityMail, "@sendprioritymail",80, atcommand_sendmail }, // [Valaris] + { AtCommand_Mail, "@mail", 1, atcommand_mail }, // [Mail System] { AtCommand_RefreshOnline, "@refreshonline", 99, atcommand_refreshonline }, // [Valaris] #endif #ifdef DMALLOC @@ -7893,97 +7881,13 @@ int atcommand_killid2(const int fd, struct map_session_data* sd, const char* com #ifndef TXT_ONLY /* Begin SQL-Only commands */ /*========================================== - * Mail System commands by [Valaris] + * MAIL SYSTEM *------------------------------------------*/ -int atcommand_listmail(const int fd, struct map_session_data* sd, const char* command, const char* message) +int atcommand_mail(const int fd, struct map_session_data* sd, const char* command, const char* message) { - if(!mail_server_enable) - return 0; - - nullpo_retr(-1, sd); - - if(strlen(command)==12) // @listnewmail - mail_check(sd,3); - else if(strlen(command)==9) // @listmail - mail_check(sd,2); - else // @checkmail - mail_check(sd,1); - return 0; -} - -int atcommand_readmail(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - int index; - if(!mail_server_enable) - return 0; - - nullpo_retr(-1, sd); - - if (!message || !*message) { - clif_displaymessage(sd->fd,"You must specify a message number."); - return 0; - } - - index = atoi(message); - if (index < 1) { - clif_displaymessage(sd->fd,"Message number cannot be negative or zero."); - return 0; - } - - mail_read(sd,index); - - return 0; -} - -int atcommand_deletemail(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - int index; - if(!mail_server_enable) - return 0; - - nullpo_retr(-1, sd); - - if (!message || !*message) { - clif_displaymessage(sd->fd,"You must specify a message number."); - return 0; - } - - index = atoi(message); - if (index < 1) { - clif_displaymessage(sd->fd,"Message number cannot be negative or zero."); - return 0; - } - - mail_delete(sd,index); - - return 0; -} - -int atcommand_sendmail(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - char name[NAME_LENGTH],text[80]; - - if(!mail_server_enable) - return 0; - - nullpo_retr(-1, sd); - - if (!message || !*message) { - clif_displaymessage(sd->fd,"You must specify a recipient and a message."); - return 0; - } - - if ((sscanf(message, "\"%23[^\"]\" %79[^\n]", name, text) < 2) && - (sscanf(message, "%23s %79[^\n]", name, text) < 2)) { - clif_displaymessage(sd->fd,"You must specify a recipient and a message."); - return 0; - } - - if(strlen(command)==17) // @sendprioritymail - mail_send(sd,name,text,1); - else - mail_send(sd,name,text,0); + nullpo_retr(0,sd); + mail_openmail(sd); return 0; } diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 6b94d9061..d2532fda7 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -255,13 +255,7 @@ enum AtCommandType { AtCommand_HappyHappyJoyJoy, // SQL-only commands start #ifndef TXT_ONLY - AtCommand_CheckMail, // [Valaris] - AtCommand_ListMail, // [Valaris] - AtCommand_ListNewMail, // [Valaris] - AtCommand_ReadMail, // [Valaris] - AtCommand_SendMail, // [Valaris] - AtCommand_DeleteMail, // [Valaris] - AtCommand_SendPriorityMail, // [Valaris] + AtCommand_Mail, // [Mail System] AtCommand_RefreshOnline, // [Valaris] // SQL-only commands end #endif diff --git a/src/map/clif.c b/src/map/clif.c index 82f7aaa6f..956a5751e 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -36,6 +36,7 @@ #include "log.h" #include "irc.h" #include "clif.h" +#include "mail.h" #include <stdio.h> #include <stdlib.h> @@ -2500,7 +2501,7 @@ int clif_updatestatus(struct map_session_data *sd,int type) case SP_ZENY: WFIFOW(fd,0)=0xb1; - WFIFOL(fd,4)=sd->status.zeny; + WFIFOL(fd,4)=sd->status.zeny - sd->mail.zeny; break; case SP_BASEEXP: WFIFOW(fd,0)=0xb1; @@ -11294,6 +11295,409 @@ void clif_parse_AutoRevive(int fd, struct map_session_data *sd) pc_delitem(sd, item_position, 1, 0); } +#ifndef TXT_ONLY + +/*========================================== + * MAIL SYSTEM + * By Zephyrus + *------------------------------------------ + * Opens Mail Window on Client + *------------------------------------------*/ +void clif_Mail_openmail(int fd) +{ + WFIFOHEAD(fd,packet_len(0x260)); + WFIFOW(fd,0) = 0x260; + WFIFOL(fd,2) = 0; + WFIFOSET(fd,packet_len(0x260)); +} +/*------------------------------------------ + * Send Inbox Data to Client + *------------------------------------------*/ +void clif_Mail_refreshinbox(struct map_session_data *sd) +{ + int fd = sd->fd; + struct mail_data *md = &sd->mail.inbox; + struct mail_message *msg; + int len, i, j; + + len = 8 + (73 * md->amount); + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x240; + WFIFOW(fd,2) = len; + WFIFOL(fd,4) = md->amount; + for( i = j = 0; i < MAX_MAIL_INBOX && j < md->amount; i++ ) + { + msg = &md->msg[i]; + if (msg->id < 1) + continue; // Deleted Message + + WFIFOL(fd,8+73*j) = msg->id; + memcpy(WFIFOP(fd,12+73*j), msg->title, MAIL_TITLE_LENGTH); + WFIFOB(fd,52+73*j) = msg->read; + memcpy(WFIFOP(fd,53+73*j), msg->send_name, NAME_LENGTH); + WFIFOL(fd,77+73*j) = msg->timestamp; + j++; + } + WFIFOSET(fd,len); +} +/*------------------------------------------ + * Client Request Inbox List + *------------------------------------------*/ +void clif_parse_Mail_refreshinbox(int fd, struct map_session_data *sd) +{ + struct mail_data *md; + + nullpo_retv(sd); + md = &sd->mail.inbox; + + if( md->amount < MAX_MAIL_INBOX && (md->satured || md->changed) ) + intif_Mail_requestinbox(sd->status.char_id, 1); + else + clif_Mail_refreshinbox(sd); + + mail_removeitem(sd, 0); + mail_removezeny(sd, 0); +} + +/*------------------------------------------ + * Read Message + *------------------------------------------*/ +void clif_Mail_read(struct map_session_data *sd, int mail_id) +{ + int i, fd = sd->fd; + + ARR_FIND(0, MAX_MAIL_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); + if (i < MAX_MAIL_INBOX) + { + struct mail_message *msg = &sd->mail.inbox.msg[i]; + struct item *item = &msg->item; + struct item_data *data; + int msg_len = strlen(msg->body), len; + + if( msg_len == 0 ) { + strcpy(msg->body, "(no message)"); + msg_len = strlen(msg->body); + } + + len = 101 + msg_len; + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x242; + WFIFOW(fd,2) = len; + WFIFOL(fd,4) = msg->id; + memcpy(WFIFOP(fd, 8), msg->title, MAIL_TITLE_LENGTH); + memcpy(WFIFOP(fd,48), msg->send_name, NAME_LENGTH); + WFIFOL(fd,72) = 0; + WFIFOL(fd,76) = msg->zeny; + + if (item->nameid) + { + 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,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,99) = (unsigned char)msg_len; + memcpy(WFIFOP(fd,100), msg->body, msg_len); + WFIFOB(fd,len - 1) = 0x00; + WFIFOSET(fd,len); + + if (!msg->read) { + msg->read = 1; + intif_Mail_read(mail_id); + clif_parse_Mail_refreshinbox(fd, sd); + } + } + else + ShowWarning("clif_parse_Mail_read: account %d trying to read a message not the inbox.\n", sd->status.account_id); +} + +void clif_parse_Mail_read(int fd, struct map_session_data *sd) +{ + nullpo_retv(sd); + clif_Mail_read(sd, RFIFOL(fd,2)); +} + +/*------------------------------------------ + * Get Attachment from Message + *------------------------------------------*/ +void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) +{ + int i, mail_id = RFIFOL(fd,2); + nullpo_retv(sd); + + ARR_FIND(0, MAX_MAIL_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); + if (i < MAX_MAIL_INBOX) + { + if (sd->mail.inbox.msg[i].zeny < 1 && (sd->mail.inbox.msg[i].item.nameid < 1 || sd->mail.inbox.msg[i].item.amount < 1)) + return; + + if (sd->mail.inbox.msg[i].item.nameid > 0) + { + struct item_data *data; + unsigned int weight; + + if ((data = itemdb_search(sd->mail.inbox.msg[i].item.nameid)) == NULL) + return; + + weight = data->weight * sd->mail.inbox.msg[i].item.amount; + if (weight > sd->max_weight - sd->weight) + { + clif_displaymessage(fd, "Attachment to heavy for you..."); + return; + } + } + + sd->mail.inbox.msg[i].zeny = 0; + memset(&sd->mail.inbox.msg[i].item, 0, sizeof(struct item)); + 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); + } +} +/*------------------------------------------ + * Delete Message + *------------------------------------------*/ +void clif_Mail_delete(struct map_session_data *sd, int mail_id, short flag) +{ + int fd = sd->fd; + + if (!flag) + { + int i; + ARR_FIND(0, MAX_MAIL_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); + if( i < MAX_MAIL_INBOX ) + { + memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message)); + sd->mail.inbox.amount--; + } + } + + WFIFOHEAD(fd, packet_len(0x257)); + WFIFOW(fd,0) = 0x257; + WFIFOL(fd,2) = mail_id; + WFIFOW(fd,6) = flag; + WFIFOSET(fd, packet_len(0x257)); + + if( !flag && sd->mail.inbox.satured ) + intif_Mail_requestinbox(sd->status.char_id, 1); // Reload the Mail Inbox +} + +void clif_parse_Mail_delete(int fd, struct map_session_data *sd) +{ + int i, mail_id = RFIFOL(fd,2); + nullpo_retv(sd); + + ARR_FIND(0, MAX_MAIL_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); + if (i < MAX_MAIL_INBOX) + { + struct mail_message *msg = &sd->mail.inbox.msg[i]; + + if( (msg->item.nameid > 0 && msg->item.amount > 0) || msg->zeny > 0 ) + { + clif_Mail_delete(sd, mail_id, 1); + return; + } + + 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 + *------------------------------------------*/ +void clif_parse_Mail_return(int fd, struct map_session_data *sd) +{ + int i, mail_id = RFIFOL(fd,2); + nullpo_retv(sd); + + ARR_FIND(0, MAX_MAIL_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); + if (i < MAX_MAIL_INBOX) + 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, MAX_MAIL_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); + if (i < MAX_MAIL_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)); +} + +/*------------------------------------------ + * Set Attachment + *------------------------------------------*/ +void clif_parse_Mail_setattach(int fd, struct map_session_data *sd) +{ + int idx = RFIFOW(fd,2), amount = RFIFOL(fd,4); + char flag; + + nullpo_retv(sd); + if (idx < 0 || amount < 0) + return; + + flag = mail_setitem(sd, idx, amount); + if (flag > -1) + { + WFIFOHEAD(fd,packet_len(0x245)); + WFIFOW(fd,0) = 0x245; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,packet_len(0x245)); + } +} + +/*------------------------------------------ + * Mail Window Operation + *------------------------------------------*/ +void clif_parse_Mail_winopen(int fd, struct map_session_data *sd) +{ + int flag = RFIFOW(fd,2); + nullpo_retv(sd); + + if (!flag || flag == 1) + mail_removeitem(sd, 0); + if (!flag || flag == 2) + 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)); +} + +void clif_parse_Mail_send(int fd, struct map_session_data *sd) +{ + struct map_session_data *rd; + struct mail_message *msg; + int body_len; + nullpo_retv(sd); + + if( RFIFOW(fd,2) < 69 ) { + ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id); + return; + } + + if( DIFF_TICK(sd->cansendmail_tick, gettick()) > 0 ) + { + clif_displaymessage(sd->fd,"Cannot send mails too fast!!."); + clif_Mail_send(fd, 1); + return; + } + + body_len = RFIFOB(fd,68); + rd = map_nick2sd_nocase(RFIFOP(fd,4)); + + if (rd && rd == sd) { + clif_Mail_send(fd, 1); + mail_removeitem(sd,0); + mail_removezeny(sd,0); + return; + } + + if (body_len > MAIL_BODY_LENGTH) + body_len = MAIL_BODY_LENGTH; + + msg = (struct mail_message*)aCalloc(sizeof(struct mail_message), 1); + + if (mail_getattach(sd, msg)) + { + msg->send_id = sd->status.char_id; + safestrncpy(msg->send_name, sd->status.name, NAME_LENGTH); + + if (rd) { + msg->dest_id = rd->status.char_id; + safestrncpy(msg->dest_name, rd->status.name, NAME_LENGTH); + } else { + msg->dest_id = 0; + safestrncpy(msg->dest_name, RFIFOP(fd,4), NAME_LENGTH); + } + + memcpy(msg->title, RFIFOP(fd,28), MAIL_TITLE_LENGTH); + + if (body_len) + memcpy(msg->body, RFIFOP(fd,69), body_len); + else + memset(msg->body, 0x00, MAIL_BODY_LENGTH); + + msg->timestamp = (int)mail_calctimes(); + intif_Mail_send(sd->status.account_id, msg); + + sd->cansendmail_tick = gettick() + 1000; // 5 Seconds flood Protection + } + else + { + mail_removeitem(sd,0); + mail_removezeny(sd,0); + clif_Mail_send(sd->fd, 1); // Fail + } + + aFree(msg); +} + +#endif + /*========================================== * パケットデバッグ *------------------------------------------*/ @@ -11551,10 +11955,10 @@ static int packetdb_readdb(void) //#0x0240 -1, -1, -1, -1, -1, 3, 4, 8, -1, 3, 70, 4, 8, 12, 4, 10, 3, 32, -1, 3, 3, 5, 5, 8, 2, 3, -1, -1, 4, -1, 4, 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, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //#0x0280 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 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,191, 0, 0, 0, 0, 0, 0, @@ -11705,6 +12109,17 @@ static int packetdb_readdb(void) {clif_parse_StoragePassword,"storagepassword"}, {clif_parse_Hotkey,"hotkey"}, {clif_parse_AutoRevive,"autorevive"}, +#ifndef TXT_ONLY + // MAIL SYSTEM + {clif_parse_Mail_refreshinbox,"mailrefresh"}, + {clif_parse_Mail_read,"mailread"}, + {clif_parse_Mail_getattach,"mailgetattach"}, + {clif_parse_Mail_delete,"maildelete"}, + {clif_parse_Mail_return,"mailreturn"}, + {clif_parse_Mail_setattach,"mailsetattach"}, + {clif_parse_Mail_winopen,"mailwinopen"}, + {clif_parse_Mail_send,"mailsend"}, +#endif {NULL,NULL} }; diff --git a/src/map/clif.h b/src/map/clif.h index 543a17da1..117c7fb24 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -382,5 +382,15 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target int do_final_clif(void); int do_init_clif(void); +#ifndef TXT_ONLY +// MAIL SYSTEM +void clif_Mail_openmail(int fd); +void clif_Mail_read(struct map_session_data *sd, int mail_id); +void clif_Mail_delete(struct map_session_data *sd, int mail_id, short flag); +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_refreshinbox(struct map_session_data *sd); +#endif #endif /* _CLIF_H_ */ diff --git a/src/map/intif.c b/src/map/intif.c index 3bf2d45ae..e6fe15242 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -18,6 +18,7 @@ #include "pet.h" #include "atcommand.h" #include "mercenary.h" //albator +#include "mail.h" #include <sys/types.h> #include <stdio.h> @@ -32,7 +33,7 @@ static const int packet_len_table[]={ -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 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, 0, 0, 0, 0, 0, 0, 0, 0, //0x3840 + 9, 9,-1,14, 0, 0, 0, 0, -1, 0,-1,12, 14,-1, 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, @@ -1458,6 +1459,275 @@ int intif_parse_DeleteHomunculusOk(int fd) return 0; } + +/*========================================== + * MAIL SYSTEM + * By Zephyrus + *------------------------------------------ + * Inbox Request + * flag: 0 Update Inbox | 1 OpenMail + *------------------------------------------*/ +#ifndef TXT_ONLY + +int intif_Mail_requestinbox(int char_id, unsigned char flag) +{ + if (CheckForCharServer()) + return 0; + + WFIFOHEAD(inter_fd,7); + WFIFOW(inter_fd,0) = 0x3048; + WFIFOL(inter_fd,2) = char_id; + WFIFOB(inter_fd,6) = flag; + WFIFOSET(inter_fd,7); + + return 0; +} + +int intif_parse_Mail_inboxreceived(int fd) +{ + struct map_session_data *sd; + unsigned char flag = RFIFOB(fd,8); + + sd = map_charid2sd( RFIFOL(fd,4) ); + + if (sd == NULL) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_inboxreceived: char not found %d\n",RFIFOL(fd,4)); + return 1; + } + + if (sd->state.finalsave) + return 1; + + if (RFIFOW(fd,2) - 9 != sizeof(struct mail_data)) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_inboxreceived: data size error %d %d\n", RFIFOW(fd,2) - 9, sizeof(struct mail_data)); + return 1; + } + + memset(&sd->mail.inbox, 0, sizeof(struct mail_data)); + memcpy(&sd->mail.inbox, RFIFOP(fd,9), sizeof(struct mail_data)); + + if (flag) + clif_Mail_refreshinbox(sd); + else + { + char output[128]; + sprintf(output, "You have %d new emails (%d unreaded)", sd->mail.inbox.unchecked, sd->mail.inbox.unreaded + sd->mail.inbox.unchecked); + clif_disp_onlyself(sd, output, strlen(output)); + } + return 0; +} +/*------------------------------------------ + * Mail Readed + *------------------------------------------*/ +int intif_Mail_read(int mail_id) +{ + if (CheckForCharServer()) + return 0; + + WFIFOHEAD(inter_fd,6); + WFIFOW(inter_fd,0) = 0x3049; + WFIFOL(inter_fd,2) = mail_id; + WFIFOSET(inter_fd,6); + + return 0; +} +/*------------------------------------------ + * Get Attachment + *------------------------------------------*/ +int intif_Mail_getattach(int char_id, int mail_id) +{ + if (CheckForCharServer()) + return 0; + + WFIFOHEAD(inter_fd,10); + WFIFOW(inter_fd,0) = 0x304a; + WFIFOL(inter_fd,2) = char_id; + WFIFOL(inter_fd,6) = mail_id; + WFIFOSET(inter_fd, 10); + + return 0; +} + +int intif_parse_Mail_getattach(int fd) +{ + struct map_session_data *sd; + struct item *item; + int zeny = RFIFOL(fd,8); + + sd = map_charid2sd( RFIFOL(fd,4) ); + + if (sd == NULL) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_getattach: char not found %d\n",RFIFOL(fd,4)); + return 1; + } + + if (sd->state.finalsave) + return 1; + + if (RFIFOW(fd,2) - 12 != sizeof(struct item)) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_getattach: data size error %d %d\n", RFIFOW(fd,2) - 16, sizeof(struct item)); + return 1; + } + + if (zeny > 0) + { + sd->status.zeny += 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); + + return 0; +} +/*------------------------------------------ + * Delete Message + *------------------------------------------*/ +int intif_Mail_delete(int char_id, int mail_id) +{ + if (CheckForCharServer()) + return 0; + + WFIFOHEAD(inter_fd,10); + WFIFOW(inter_fd,0) = 0x304b; + WFIFOL(inter_fd,2) = char_id; + WFIFOL(inter_fd,6) = mail_id; + WFIFOSET(inter_fd,10); + + return 0; +} + +int intif_parse_Mail_delete(int fd) +{ + struct map_session_data *sd = map_charid2sd(RFIFOL(fd,2)); + int mail_id = RFIFOL(fd,6); + short flag = RFIFOW(fd,10); + + if (sd == NULL) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_delete: char not found %d\n",RFIFOL(fd,2)); + return 1; + } + + if (sd->state.finalsave) + return 1; + + clif_Mail_delete(sd, mail_id, flag); + return 0; +} +/*------------------------------------------ + * Return Message + *------------------------------------------*/ +int intif_Mail_return(int char_id, int mail_id) +{ + if (CheckForCharServer()) + return 0; + + WFIFOHEAD(inter_fd,10); + WFIFOW(inter_fd,0) = 0x304c; + WFIFOL(inter_fd,2) = char_id; + WFIFOL(inter_fd,6) = mail_id; + WFIFOSET(inter_fd,10); + + return 0; +} + +int intif_parse_Mail_return(int fd) +{ + struct map_session_data *sd = map_charid2sd(RFIFOL(fd,2)); + int mail_id = RFIFOL(fd,6), new_mail = RFIFOL(fd,10); + + if (sd == NULL) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_return: char not found %d\n",RFIFOL(fd,2)); + return 1; + } + + if (sd->state.finalsave) + return 1; + + clif_Mail_return(sd, mail_id, new_mail); + return 0; +} +/*------------------------------------------ + * Send Mail + *------------------------------------------*/ +int intif_Mail_send(int account_id, struct mail_message *msg) +{ + int len = sizeof(struct mail_message) + 8; + + if (CheckForCharServer()) + return 0; + + WFIFOHEAD(inter_fd,len); + WFIFOW(inter_fd,0) = 0x304d; + WFIFOW(inter_fd,2) = len; + WFIFOL(inter_fd,4) = account_id; + memcpy(WFIFOP(inter_fd,8), msg, sizeof(struct mail_message)); + WFIFOSET(inter_fd,len); + + return 0; +} + +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); + + if (sd == NULL && mail_id > 0) + { + if (battle_config.error_log) + ShowError("intif_parse_Mail_send: char not found %d\n",RFIFOL(fd,2)); + + // If sd = NULL attachment haven't been removed from sender inventory. + intif_Mail_delete(dest_id, mail_id); + return 0; + } + + if (mail_id > 0) + { + struct map_session_data *rd = map_charid2sd(dest_id); + + mail_removeitem(sd, 1); + mail_removezeny(sd, 1); + + if (rd != NULL) + { + char title[MAIL_TITLE_LENGTH]; + memcpy(title, RFIFOP(fd,16), RFIFOW(fd,2) - 16); + + rd->mail.inbox.changed = 1; + clif_Mail_new(rd->fd, mail_id, sd->status.name, title); + } + } + else + { // Return the items to the owner + mail_removeitem(sd, 0); + mail_removezeny(sd, 0); + } + + clif_Mail_send(sd->fd, (mail_id > 0)?0:1); + + return 0; +} + +#endif + //----------------------------------------------------------------- // inter serverからの通信 // エラーがあれば0(false)を返すこと @@ -1528,6 +1798,15 @@ int intif_parse(int fd) case 0x3841: intif_parse_GuildCastleDataSave(fd); break; case 0x3842: intif_parse_GuildCastleAllDataLoad(fd); break; case 0x3843: intif_parse_GuildMasterChanged(fd); break; +// Mail System +#ifndef TXT_ONLY + case 0x3848: intif_parse_Mail_inboxreceived(fd); break; + case 0x384a: intif_parse_Mail_getattach(fd); break; + case 0x384b: intif_parse_Mail_delete(fd); break; + case 0x384c: intif_parse_Mail_return(fd); break; + case 0x384d: intif_parse_Mail_send(fd); break; +#endif +// End of Mail System case 0x3880: intif_parse_CreatePet(fd); break; case 0x3881: intif_parse_RecvPetData(fd); break; case 0x3882: intif_parse_SavePetOk(fd); break; diff --git a/src/map/intif.h b/src/map/intif.h index 5487d5725..793c6bc3e 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -74,6 +74,15 @@ int intif_homunculus_requestload(int account_id, int homun_id); int intif_homunculus_requestsave(int account_id, struct s_homunculus* sh); int intif_homunculus_requestdelete(int homun_id); +#ifndef TXT_ONLY +// MAIL SYSTEM +int intif_Mail_requestinbox(int char_id, unsigned char flag); +int intif_Mail_read(int mail_id); +int intif_Mail_getattach(int char_id, int mail_id); +int intif_Mail_delete(int char_id, int mail_id); +int intif_Mail_return(int char_id, int mail_id); +int intif_Mail_send(int account_id, struct mail_message *msg); +#endif int CheckForCharServer(void); diff --git a/src/map/mail.c b/src/map/mail.c index 6e6dc0a91..371e11f8e 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -3,365 +3,122 @@ #ifndef TXT_ONLY -#include "../common/strlib.h" -#include "../common/socket.h" -#include "../common/timer.h" #include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "map.h" +#include "mail.h" +#include "itemdb.h" #include "clif.h" -#include "chrif.h" -#include "intif.h" -#include "atcommand.h" #include "pc.h" -#include "mail.h" -#include <stdio.h> -#include <stdlib.h> +#include <time.h> #include <string.h> - -int MAIL_CHECK_TIME = 120000; -int mail_timer; - -/// type: 0 - mail check at login, silent if there aren't any new messages -/// 1 - @checkmail, just print the number of messages -/// 2 - @listmail, shows both read and unread messages -/// 3 - @listnewmail, shows only unread messages -int mail_check(struct map_session_data* sd, int type) +time_t mail_calctimes(void) { - int i = 0, new_ = 0, priority = 0; // counters - char message[80]; - - nullpo_retr (0, sd); - - // retrieve all existing messages for this player - if( SQL_ERROR == Sql_Query(mail_handle, "SELECT `message_id`,`to_account_id`,`from_char_name`,`read_flag`,`priority`,`check_flag` FROM `%s` WHERE `to_account_id` = %d ORDER by `message_id`", mail_db, sd->status.account_id) ) - { - Sql_ShowDebug(mail_handle); - return 0; - } - - if( Sql_NumRows(mail_handle) == 0) - { - clif_displaymessage(sd->fd, msg_txt(516)); // "You have no messages." - Sql_FreeResult(mail_handle); - return 0; - } - - while( SQL_SUCCESS == Sql_NextRow(mail_handle) ) - { - char* data; - int message_id; - int to_account_id; - char from_char_name[NAME_LENGTH]; - bool read_flag, priority_flag, check_flag; - - Sql_GetData(mail_handle, 0, &data, NULL); message_id = atoi(data); - Sql_GetData(mail_handle, 1, &data, NULL); to_account_id = atoi(data); - Sql_GetData(mail_handle, 2, &data, NULL); safestrncpy(from_char_name, data, sizeof(from_char_name)); - Sql_GetData(mail_handle, 3, &data, NULL); read_flag = (bool) atoi(data); - Sql_GetData(mail_handle, 4, &data, NULL); priority_flag = (bool) atoi(data); - Sql_GetData(mail_handle, 5, &data, NULL); check_flag = (bool) atoi(data); - - i++; - - if( !check_flag ) - { - // mark this message as checked - if( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `check_flag` = 1 WHERE `message_id` = %d", mail_db, message_id) ) - Sql_ShowDebug(mail_handle); - } - - if( !read_flag ) - { - new_++; - if(priority_flag) - priority++; - - if( type == 2 || type == 3 ) - { - if( priority_flag ) - { - snprintf(message, 80, msg_txt(511), i, from_char_name); - clif_displaymessage(sd->fd, message); // "%d - From : %s (New - Priority)" - } - else - { - snprintf(message, 80, msg_txt(512), i, from_char_name); - clif_displaymessage(sd->fd, message); // "%d - From : %s (New)" - } - } - } - else if( type == 2 ) - { - snprintf(message, 80, msg_txt(513), i, from_char_name); - clif_displaymessage(sd->fd, message); // "%d - From : %s" - } - } - - Sql_FreeResult(mail_handle); - - if( new_ > 0 && (type == 0 || type == 1) ) - { - sprintf(message, msg_txt(514), new_); - clif_displaymessage(sd->fd, message); // "You have %d unread messages." - if (priority > 0) - { - sprintf(message, msg_txt(515), priority); - clif_displaymessage(sd->fd, message); // "You have %d unread priority messages." - } - } - if( new_ == 0 && type != 0 ) - { - clif_displaymessage(sd->fd, msg_txt(516)); // "You have no unread messages." - } - - return 0; + time_t temp = time(NULL); + return mktime(localtime(&temp)); } -/// displays the selected message -int mail_read(struct map_session_data* sd, int index) +int mail_removeitem(struct map_session_data *sd, short flag) { - char* data; - int message_id; - char from_char_name[NAME_LENGTH]; - char message[80]; - bool read_flag, priority_flag, check_flag; - char output[100]; - - nullpo_retr(0, sd); - - // retrieve the 'index'-th message - if( SQL_ERROR == Sql_Query(mail_handle, "SELECT `message_id`,`from_char_name`,`message`,`read_flag`,`priority`,`check_flag` from `%s` WHERE `to_account_id` = %d ORDER by `message_id` LIMIT %d, 1", mail_db, sd->status.account_id, index-1) ) - { - Sql_ShowDebug(mail_handle); - return 0; - } + nullpo_retr(0,sd); - if( 0 == Sql_NumRows(mail_handle) ) + if( sd->mail.amount ) { - clif_displaymessage(sd->fd, msg_txt(517)); // "Message not found." - Sql_FreeResult(mail_handle); - return 0; + if (flag) + pc_delitem(sd, sd->mail.index, sd->mail.amount, 1); + else + clif_additem(sd, sd->mail.index, sd->mail.amount, 0); } - if( SQL_ERROR == Sql_NextRow(mail_handle) ) - { - Sql_ShowDebug(mail_handle); - Sql_FreeResult(mail_handle); - return 0; - } - - Sql_GetData(mail_handle, 0, &data, NULL); message_id = atoi(data); - Sql_GetData(mail_handle, 1, &data, NULL); safestrncpy(from_char_name, data, sizeof(from_char_name)); - Sql_GetData(mail_handle, 2, &data, NULL); safestrncpy(message, data, sizeof(message)); - Sql_GetData(mail_handle, 3, &data, NULL); read_flag = (bool) atoi(data); - Sql_GetData(mail_handle, 4, &data, NULL); priority_flag = (bool) atoi(data); - Sql_GetData(mail_handle, 5, &data, NULL); check_flag = (bool) atoi(data); - - Sql_FreeResult(mail_handle); + sd->mail.index = 0; + sd->mail.amount = 0; + return 1; +} - // mark mail as checked - if( !check_flag ) - { - if( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `check_flag` = 1 WHERE `message_id` = %d", mail_db, message_id) ) - Sql_ShowDebug(mail_handle); - } +int mail_removezeny(struct map_session_data *sd, short flag) +{ + nullpo_retr(0,sd); - sprintf(output, msg_txt(518), from_char_name); - clif_displaymessage(sd->fd, output); // "Reading message from %s" - clif_displaymessage(sd->fd, message); + if (flag && sd->mail.zeny > 0) + sd->status.zeny -= sd->mail.zeny; - if( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `read_flag` = 1 WHERE `message_id` = %d", mail_db, message_id) ) - { - Sql_ShowDebug(mail_handle); - } + sd->mail.zeny = 0; + clif_updatestatus(sd, SP_ZENY); - return 0; + return 1; } -/// message deletion -int mail_delete(struct map_session_data* sd, int index) +char mail_setitem(struct map_session_data *sd, int idx, int amount) { - char* data; - int message_id; - bool read_flag, priority_flag, check_flag; + nullpo_retr(-1,sd); - nullpo_retr (0, sd); + if (idx == 0) + { // Zeny Transfer + if (amount < 0) + return 2; + if (amount > sd->status.zeny) + amount = sd->status.zeny; - if( SQL_ERROR == Sql_Query(mail_handle, "SELECT `message_id`,`read_flag`,`priority`,`check_flag` from `%s` WHERE `to_account_id` = %d ORDER by `message_id` LIMIT %d, 1", mail_db, sd->status.account_id, index-1) ) - { - Sql_ShowDebug(mail_handle); - return 0; - } - - if( 0 == Sql_NumRows(mail_handle) ) - { - clif_displaymessage(sd->fd, msg_txt(517)); // "Message not found." - Sql_FreeResult(mail_handle); - return 0; + sd->mail.zeny = amount; + clif_updatestatus(sd, SP_ZENY); } + else + { // Item Transfer + idx -= 2; + mail_removeitem(sd, 0); - if( SQL_ERROR == Sql_NextRow(mail_handle) ) - { - Sql_ShowDebug(mail_handle); - Sql_FreeResult(mail_handle); - return 0; - } - - Sql_GetData(mail_handle, 0, &data, NULL); message_id = atoi(data); - Sql_GetData(mail_handle, 1, &data, NULL); read_flag = (bool)atoi(data); - Sql_GetData(mail_handle, 2, &data, NULL); priority_flag = (bool)atoi(data); - Sql_GetData(mail_handle, 3, &data, NULL); check_flag = (bool)atoi(data); - - Sql_FreeResult(mail_handle); + if( idx < 0 || idx > MAX_INVENTORY ) + return 2; + if( amount < 0 || amount > sd->status.inventory[idx].amount ) + return 2; + if( itemdb_isdropable(&sd->status.inventory[idx], pc_isGM(sd)) == 0 ) + return 2; - if( !read_flag && priority_flag ) - { - clif_displaymessage(sd->fd,msg_txt(519)); // "Cannot delete unread priority mail." - return 0; - } + sd->mail.index = idx; + sd->mail.amount = amount; - if( !check_flag ) - { - clif_displaymessage(sd->fd,msg_txt(520)); // "You have received new mail, use @listmail before deleting." - return 0; - } + clif_delitem(sd, idx, amount); - if( SQL_ERROR == Sql_Query(mail_handle, "DELETE FROM `%s` WHERE `message_id` = %d", mail_db, message_id) ) - { - Sql_ShowDebug(mail_handle); return 0; } - clif_displaymessage(sd->fd,msg_txt(521)); // "Message deleted." - - return 0; + return -1; } -/// for sending normal and priority messages -int mail_send(struct map_session_data* sd, char* name, char* message, int flag) +int mail_getattach(struct map_session_data *sd, struct mail_message *msg) { - SqlStmt* stmt; - - nullpo_retr (0, sd); + int n; + + nullpo_retr(0,sd); + nullpo_retr(0,msg); - if( pc_isGM(sd) < 80 && sd->mail_counter > 0 ) - { - clif_displaymessage(sd->fd,msg_txt(522)); // "You must wait 10 minutes before sending another message" + if( sd->mail.zeny < 0 || sd->mail.zeny > sd->status.zeny ) return 0; - } - if( strcmp(name,"*") == 0 && pc_isGM(sd) < 80 ) + n = sd->mail.index; + if( sd->mail.amount ) { - clif_displaymessage(sd->fd, msg_txt(523)); // "Access Denied." - return 0; - } - - if( strcmp(name,"*") == 0 ) - { - if( SQL_ERROR == Sql_Query(mail_handle, "SELECT DISTINCT `account_id` FROM `%s` WHERE `account_id` != '%d' ORDER BY `account_id`", char_db, sd->status.account_id) ) - { - Sql_ShowDebug(mail_handle); - return 0; - } - } - else - { - char name_[2*NAME_LENGTH]; - Sql_EscapeString(mail_handle, name_, name); - if( SQL_ERROR == Sql_Query(mail_handle, "SELECT `account_id` FROM `%s` WHERE `name` = '%s'", char_db, name_) ) - { - Sql_ShowDebug(mail_handle); + if( sd->status.inventory[n].amount < sd->mail.amount ) return 0; - } - } - if( 0 == Sql_NumRows(mail_handle) ) - { - clif_displaymessage(sd->fd,msg_txt(524)); // "Character does not exist." - Sql_FreeResult(mail_handle); - return 0; + memcpy(&msg->item, &sd->status.inventory[n], sizeof(struct item)); + msg->item.amount = sd->mail.amount; } - stmt = SqlStmt_Malloc(mail_handle); - SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`to_account_id`,`to_char_name`,`from_account_id`,`from_char_name`,`message`,`priority`) VALUES (?, ?, '%d', ?, ?, '%d')", mail_db, sd->status.account_id, flag); - SqlStmt_BindParam(stmt, 1, SQLDT_STRING, name, strnlen(name, NAME_LENGTH)); - SqlStmt_BindParam(stmt, 2, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)); - SqlStmt_BindParam(stmt, 3, SQLDT_STRING, message, strnlen(message, 80)); - - while( SQL_SUCCESS == Sql_NextRow(mail_handle) ) - { - int id; - char* data; - Sql_GetData(mail_handle, 0, &data, NULL); id = atoi(data); - SqlStmt_BindParam(stmt, 0, SQLDT_INT, &id, sizeof(id)); - if( SQL_ERROR == SqlStmt_Execute(stmt) ) - SqlStmt_ShowDebug(stmt); - } - Sql_FreeResult(mail_handle); - SqlStmt_Free(stmt); - - if(pc_isGM(sd) < 80) - sd->mail_counter = 5; - - clif_displaymessage(sd->fd,msg_txt(525)); // "Mail has been sent." + msg->zeny = sd->mail.zeny; - return 0; -} - -/// invoked every MAIL_CHECK_TIME ms, decreases the send blocking counter -static int mail_check_timer_sub(struct map_session_data* sd, va_list va) -{ - if(sd->mail_counter > 0) - sd->mail_counter--; - return 0; + return 1; } -/// periodically checks for new messages and notifies about them -int mail_check_timer(int tid, unsigned int tick, int id, int data) +int mail_openmail(struct map_session_data *sd) { - if(mail_timer != tid) - return 0; + nullpo_retr(0,sd); - mail_timer = add_timer(gettick() + MAIL_CHECK_TIME, mail_check_timer, 0, 0); - - // fetch account ids of people who received new mail since the last iteration - if( SQL_ERROR == Sql_Query(mail_handle, "SELECT DISTINCT `to_account_id` FROM `%s` WHERE `read_flag` = '0' AND `check_flag` = '0'", mail_db) ) - { - Sql_ShowDebug(mail_handle); + if( sd->state.finalsave == 1 || sd->state.storage_flag || sd->vender_id || sd->state.trading ) return 0; - } - - while( SQL_SUCCESS == Sql_NextRow(mail_handle) ) - { - char* id; - struct map_session_data* sd; - Sql_GetData(mail_handle, 0, &id, NULL); - if( (sd = map_id2sd(atoi(id))) != NULL ) - clif_displaymessage(sd->fd, msg_txt(526)); // "You have new mail." - } - - Sql_FreeResult(mail_handle); - // decrease the send-blocking counter - clif_foreachclient(mail_check_timer_sub); - - // The 'check_flag' indicates whether the player was informed about the message. - // All online players were notified by the above code, and offline players will get the notice at next login. - // Therefore it is safe to simply set the flag to '1' for all existing mails. - if( SQL_ERROR == Sql_Query(mail_handle, "UPDATE `%s` SET `check_flag` = 1 WHERE `check_flag` = 0", mail_db) ) - Sql_ShowDebug(mail_handle); - - return 0; -} - -int do_init_mail(void) -{ - add_timer_func_list(mail_check_timer, "mail_check_timer"); - mail_timer = add_timer(gettick() + MAIL_CHECK_TIME, mail_check_timer, 0, 0); + clif_Mail_openmail(sd->fd); return 0; } diff --git a/src/map/mail.h b/src/map/mail.h index f753d827b..1f05edfce 100644 --- a/src/map/mail.h +++ b/src/map/mail.h @@ -4,11 +4,14 @@ #ifndef _MAIL_H_ #define _MAIL_H_ -int mail_check(struct map_session_data *sd, int type); -int mail_read(struct map_session_data *sd, int index); -int mail_delete(struct map_session_data *sd, int index); -int mail_send(struct map_session_data *sd, char *name, char *message, int flag); +#include "../common/mmo.h" -int do_init_mail(void); +time_t mail_calctimes(void); + +int mail_removeitem(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); +int mail_openmail(struct map_session_data *sd); #endif /* _MAIL_H_ */ diff --git a/src/map/map.c b/src/map/map.c index db4f7d077..929ee7c36 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -75,16 +75,6 @@ char log_db_pw[32] = "ragnarok"; char log_db[32] = "log"; Sql* logmysql_handle; -// mail system -int mail_server_enable = 0; -char mail_server_ip[32] = "127.0.0.1"; -int mail_server_port = 3306; -char mail_server_id[32] = "ragnarok"; -char mail_server_pw[32] = "ragnarok"; -char mail_server_db[32] = "ragnarok"; -char mail_db[32] = "mail"; -Sql* mail_handle; - #endif /* not TXT_ONLY */ int lowest_gm_level = 1; @@ -1857,6 +1847,21 @@ struct map_session_data * map_nick2sd(const char *nick) return NULL; } +struct map_session_data * map_nick2sd_nocase(const char *nick) +{ + int i, users; + struct map_session_data **pl_allsd; + + pl_allsd = map_getallusers(&users); + for (i = 0; i < users; i++) + { + if ( !strcmp(pl_allsd[i]->status.name, nick) ) + return pl_allsd[i]; + } + + return NULL; +} + /*========================================== * id番?の物を探す * 一三bjectの場合は配列を引くのみ @@ -2888,22 +2893,6 @@ int inter_config_read(char *cfgName) strcpy(log_db_pw, w2); } else if(strcmpi(w1,"log_db_port")==0) { log_db_port = atoi(w2); - // Mail Server SQL - } else if(strcmpi(w1,"mail_server_enable")==0){ - mail_server_enable = config_switch(w2); - ShowStatus ("Using Mail Server: %s\n",w2); - } else if(strcmpi(w1,"mail_server_ip")==0){ - strcpy(mail_server_ip, w2); - } else if(strcmpi(w1,"mail_server_port")==0){ - mail_server_port=atoi(w2); - } else if(strcmpi(w1,"mail_server_id")==0){ - strcpy(mail_server_id, w2); - } else if(strcmpi(w1,"mail_server_pw")==0){ - strcpy(mail_server_pw, w2); - } else if(strcmpi(w1,"mail_server_db")==0){ - strcpy(mail_server_db, w2); - } else if(strcmpi(w1,"mail_db")==0) { - strcpy(mail_db, w2); #endif //support the import command, just like any other config } else if(strcmpi(w1,"import")==0){ @@ -2933,20 +2922,6 @@ int map_sql_init(void) if ( SQL_ERROR == Sql_SetEncoding(mmysql_handle, default_codepage) ) Sql_ShowDebug(mmysql_handle); - if(mail_server_enable) - { - // mail system - mail_handle = Sql_Malloc(); - - ShowInfo("Connecting to the Mail DB Server....\n"); - if( SQL_ERROR == Sql_Connect(mail_handle, mail_server_id, mail_server_pw, mail_server_ip, mail_server_port, mail_server_db) ) - exit(EXIT_FAILURE); - - if( strlen(default_codepage) > 0 ) - if ( SQL_ERROR == Sql_SetEncoding(mail_handle, default_codepage) ) - Sql_ShowDebug(mail_handle); - } - return 0; } @@ -2963,13 +2938,6 @@ int map_sql_close(void) logmysql_handle = NULL; } - if(mail_server_enable) - { - ShowStatus("Close Mail DB Connection....\n"); - Sql_Free(mail_handle); - mail_handle = NULL; - } - return 0; } @@ -2999,8 +2967,6 @@ int map_sql_ping(int tid, unsigned int tick, int id, int data) Sql_Ping(mmysql_handle); if (log_config.sql_logs) Sql_Ping(logmysql_handle); - if(mail_server_enable) - Sql_Ping(mail_handle); return 0; } @@ -3382,9 +3348,6 @@ int do_init(int argc, char *argv[]) do_init_npc(); do_init_unit(); #ifndef TXT_ONLY /* mail system [Valaris] */ - if(mail_server_enable) - do_init_mail(); - if (log_config.sql_logs) log_sql_init(); diff --git a/src/map/map.h b/src/map/map.h index 95c1d120d..b0f823d8e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -633,6 +633,7 @@ struct map_session_data { unsigned int canlog_tick; unsigned int canuseitem_tick; // [Skotlex] unsigned int cantalk_tick; + unsigned int cansendmail_tick; // [Mail System Flood Protection] short weapontype1,weapontype2; short disguise; // [Valaris] @@ -799,15 +800,16 @@ struct map_session_data { char fakename[NAME_LENGTH]; // fake names [Valaris] -#ifndef TXT_ONLY - int mail_counter; // mail counter for mail system (antiflood protection) -#endif - int duel_group; // duel vars [LuzZza] int duel_invite; char away_message[128]; // [LuzZza] + // Mail System [Zephyrus] + struct { + int index, amount, zeny; + struct mail_data inbox; + } mail; }; struct { @@ -1342,6 +1344,7 @@ struct map_session_data** map_getallusers(int *users); void map_foreachpc(int (*func)(DBKey,void*,va_list),...); int map_foreachiddb(int (*)(DBKey,void*,va_list),...); struct map_session_data * map_nick2sd(const char*); +struct map_session_data * map_nick2sd_nocase(const char *); // その他 int map_check_dir(int s_dir,int t_dir); @@ -1412,18 +1415,15 @@ extern char main_chat_nick[16]; #include "../common/sql.h" extern int db_use_sqldbs; -extern int mail_server_enable; extern Sql* mmysql_handle; extern Sql* logmysql_handle; -extern Sql* mail_handle; extern char item_db_db[32]; extern char item_db2_db[32]; extern char mob_db_db[32]; extern char mob_db2_db[32]; extern char char_db[32]; -extern char mail_db[32]; #endif /* not TXT_ONLY */ diff --git a/src/map/pc.c b/src/map/pc.c index 733f31d0a..a984796ae 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -633,6 +633,7 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t sd->canuseitem_tick = tick; sd->cantalk_tick = tick; + sd->cansendmail_tick = tick; for(i = 0; i < MAX_SKILL_LEVEL; i++) sd->spirit_timer[i] = -1; @@ -743,11 +744,6 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t clif_displaymessage(sd->fd, motd_text[i]); } -#ifndef TXT_ONLY - if(mail_server_enable) - mail_check(sd,0); // check mail at login [Valaris] -#endif - // message of the limited time of the account if (connect_until_time != 0) { // don't display if it's unlimited or unknow value char tmpstr[1024]; @@ -886,7 +882,9 @@ int pc_reg_received(struct map_session_data *sd) status_calc_pc(sd,1); chrif_scdata_request(sd->status.account_id, sd->status.char_id); - +#ifndef TXT_ONLY + intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox +#endif if (!sd->state.connect_new && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually. sd->state.connect_new = 1; diff --git a/src/map/script.c b/src/map/script.c index 9de888e31..0e4144605 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -39,6 +39,7 @@ #include "unit.h" #include "irc.h" #include "pet.h" +#include "mail.h" #include "script.h" #include <stdio.h> @@ -4052,6 +4053,10 @@ BUILDIN_FUNC(getmonsterinfo); // [Lupus] BUILDIN_FUNC(checkvending); // check vending [Nab4] BUILDIN_FUNC(checkchatting); // check chatting [Marka] +#ifndef TXT_ONLY +BUILDIN_FUNC(openmail); // [Mail System] +#endif + #ifdef PCRE_SUPPORT BUILDIN_FUNC(defpattern); // MouseJstr BUILDIN_FUNC(activatepset); // MouseJstr @@ -4390,6 +4395,9 @@ struct script_function buildin_func[] = { BUILDIN_DEF(roclass,"i*"), //[Skotlex] BUILDIN_DEF(checkvending,"*"), BUILDIN_DEF(checkchatting,"*"), +#ifndef TXT_ONLY + BUILDIN_DEF(openmail,""), +#endif {NULL,NULL,NULL}, }; @@ -13446,3 +13454,11 @@ BUILDIN_FUNC(warpportal) return 0; } + +#ifndef TXT_ONLY +BUILDIN_FUNC(openmail) +{ + mail_openmail(script_rid2sd(st)); + return 0; +} +#endif diff --git a/vcproj-8/char-server_sql.vcproj b/vcproj-8/char-server_sql.vcproj index 0427e7c27..c8c15893e 100644 --- a/vcproj-8/char-server_sql.vcproj +++ b/vcproj-8/char-server_sql.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="Windows-1252"?> <VisualStudioProject ProjectType="Visual C++" - Version="8.00" + Version="8,00" Name="char-server_sql" ProjectGUID="{D356871D-58E1-450B-967A-E4E9646175AF}" RootNamespace="char-server_sql" @@ -362,6 +362,14 @@ > </File> <File + RelativePath="..\src\char_sql\int_mail.c" + > + </File> + <File + RelativePath="..\src\char_sql\int_mail.h" + > + </File> + <File RelativePath="..\src\char_sql\int_party.c" > </File> |