// Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #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 #include #include 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) { 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; } /// displays the selected message int mail_read(struct map_session_data* sd, int index) { 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; } 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; } /// message deletion int mail_delete(struct map_session_data* sd, int index) { char* data; int message_id; bool read_flag, priority_flag, check_flag; nullpo_retr (0, sd); 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; } 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; } /// for sending normal and priority messages int mail_send(struct map_session_data* sd, char* name, char* message, int flag) { SqlStmt* stmt; nullpo_retr (0, sd); 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; } } 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); 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; } 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; } /// 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; } /// 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) 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); return 0; } #endif