- Added the new mail system. Requires optimization and tests.

- Updated the maildb sql structure.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11548 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
zephyrus 2007-10-22 20:38:26 +00:00
parent 0e39094a11
commit c34325a53b
24 changed files with 1474 additions and 528 deletions

View File

@ -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]

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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"))

View File

@ -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]

476
src/char_sql/int_mail.c Normal file
View File

@ -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;
}

12
src/char_sql/int_mail.h Normal file
View File

@ -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_ */

View File

@ -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

View File

@ -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);

View File

@ -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];

View File

@ -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;
}

View File

@ -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

View File

@ -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
/*==========================================
* ƒpƒPƒbƒgƒfƒoƒbƒO
*------------------------------------------*/
@ -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}
};

View File

@ -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_ */

View File

@ -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;

View File

@ -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);

View File

@ -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 "clif.h"
#include "chrif.h"
#include "intif.h"
#include "atcommand.h"
#include "pc.h"
#include "mail.h"
#include "itemdb.h"
#include "clif.h"
#include "pc.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);
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) )
if( sd->mail.amount )
{
Sql_ShowDebug(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( 0 == Sql_NumRows(mail_handle) )
{
clif_displaymessage(sd->fd, msg_txt(517)); // "Message not found."
Sql_FreeResult(mail_handle);
return 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);
// 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);
}
sprintf(output, msg_txt(518), from_char_name);
clif_displaymessage(sd->fd, output); // "Reading message from %s"
clif_displaymessage(sd->fd, message);
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);
}
return 0;
sd->mail.index = 0;
sd->mail.amount = 0;
return 1;
}
/// message deletion
int mail_delete(struct map_session_data* sd, int index)
int mail_removezeny(struct map_session_data *sd, short flag)
{
char* data;
int message_id;
bool read_flag, priority_flag, check_flag;
nullpo_retr(0,sd);
nullpo_retr (0, sd);
if (flag && sd->mail.zeny > 0)
sd->status.zeny -= sd->mail.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;
}
sd->mail.zeny = 0;
clif_updatestatus(sd, SP_ZENY);
if( 0 == Sql_NumRows(mail_handle) )
{
clif_displaymessage(sd->fd, msg_txt(517)); // "Message not found."
Sql_FreeResult(mail_handle);
return 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( !read_flag && priority_flag )
{
clif_displaymessage(sd->fd,msg_txt(519)); // "Cannot delete unread priority mail."
return 0;
}
if( !check_flag )
{
clif_displaymessage(sd->fd,msg_txt(520)); // "You have received new mail, use @listmail before deleting."
return 0;
}
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)
char mail_setitem(struct map_session_data *sd, int idx, int amount)
{
SqlStmt* stmt;
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( pc_isGM(sd) < 80 && sd->mail_counter > 0 )
{
clif_displaymessage(sd->fd,msg_txt(522)); // "You must wait 10 minutes before sending another message"
return 0;
}
if( strcmp(name,"*") == 0 && pc_isGM(sd) < 80 )
{
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;
}
sd->mail.zeny = amount;
clif_updatestatus(sd, SP_ZENY);
}
else
{ // Item Transfer
idx -= 2;
mail_removeitem(sd, 0);
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;
sd->mail.index = idx;
sd->mail.amount = amount;
clif_delitem(sd, idx, amount);
return 0;
}
return -1;
}
int mail_getattach(struct map_session_data *sd, struct mail_message *msg)
{
int n;
nullpo_retr(0,sd);
nullpo_retr(0,msg);
if( sd->mail.zeny < 0 || sd->mail.zeny > sd->status.zeny )
return 0;
n = sd->mail.index;
if( sd->mail.amount )
{
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;
}
memcpy(&msg->item, &sd->status.inventory[n], sizeof(struct item));
msg->item.amount = sd->mail.amount;
}
if( 0 == Sql_NumRows(mail_handle) )
{
clif_displaymessage(sd->fd,msg_txt(524)); // "Character does not exist."
Sql_FreeResult(mail_handle);
return 0;
}
msg->zeny = sd->mail.zeny;
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."
return 0;
return 1;
}
/// 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)
int mail_openmail(struct map_session_data *sd)
{
if(sd->mail_counter > 0)
sd->mail_counter--;
return 0;
}
nullpo_retr(0,sd);
/// periodically checks for new messages and notifies about them
int mail_check_timer(int tid, unsigned int tick, int id, int data)
{
if(mail_timer != tid)
if( sd->state.finalsave == 1 || sd->state.storage_flag || sd->vender_id || sd->state.trading )
return 0;
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);
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;
}

View File

@ -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_ */

View File

@ -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();

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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"
@ -361,6 +361,14 @@
RelativePath="..\src\char_sql\int_homun.h"
>
</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"
>