aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Handlers/MailHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Handlers/MailHandler.cpp')
-rw-r--r--src/server/game/Handlers/MailHandler.cpp461
1 files changed, 134 insertions, 327 deletions
diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp
index d173b409008..136f998b308 100644
--- a/src/server/game/Handlers/MailHandler.cpp
+++ b/src/server/game/Handlers/MailHandler.cpp
@@ -24,6 +24,7 @@
#include "World.h"
#include "ObjectMgr.h"
#include "Player.h"
+#include "MailPackets.h"
#include "Language.h"
#include "DBCStores.h"
#include "Item.h"
@@ -57,91 +58,18 @@ bool WorldSession::CanOpenMailBox(ObjectGuid guid)
return true;
}
-void WorldSession::HandleSendMail(WorldPacket& recvData)
+void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet)
{
- ObjectGuid mailbox;
- uint64 money, COD;
- std::string receiverName, subject, body;
- uint32 bodyLength, subjectLength, receiverLength;
- uint32 package, stationery;
-
- recvData >> package;
- recvData >> stationery;
-
- recvData >> COD >> money; // money and cod
- bodyLength = recvData.ReadBits(12);
- subjectLength = recvData.ReadBits(9);
-
- uint8 items_count = recvData.ReadBits(5); // attached items count
-
- if (items_count > MAX_MAIL_ITEMS) // client limit
+ if (packet.Info.Attachments.size() > MAX_MAIL_ITEMS) // client limit
{
GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS);
- recvData.rfinish(); // set to end to avoid warnings spam
return;
}
- mailbox[0] = recvData.ReadBit();
-
- ObjectGuid itemGUIDs[MAX_MAIL_ITEMS];
-
- for (uint8 i = 0; i < items_count; ++i)
- {
- itemGUIDs[i][2] = recvData.ReadBit();
- itemGUIDs[i][6] = recvData.ReadBit();
- itemGUIDs[i][3] = recvData.ReadBit();
- itemGUIDs[i][7] = recvData.ReadBit();
- itemGUIDs[i][1] = recvData.ReadBit();
- itemGUIDs[i][0] = recvData.ReadBit();
- itemGUIDs[i][4] = recvData.ReadBit();
- itemGUIDs[i][5] = recvData.ReadBit();
- }
-
- mailbox[3] = recvData.ReadBit();
- mailbox[4] = recvData.ReadBit();
- receiverLength = recvData.ReadBits(7);
- mailbox[2] = recvData.ReadBit();
- mailbox[6] = recvData.ReadBit();
- mailbox[1] = recvData.ReadBit();
- mailbox[7] = recvData.ReadBit();
- mailbox[5] = recvData.ReadBit();
-
- recvData.ReadByteSeq(mailbox[4]);
-
- for (uint8 i = 0; i < items_count; ++i)
- {
- recvData.ReadByteSeq(itemGUIDs[i][6]);
- recvData.ReadByteSeq(itemGUIDs[i][1]);
- recvData.ReadByteSeq(itemGUIDs[i][7]);
- recvData.ReadByteSeq(itemGUIDs[i][2]);
- recvData.read_skip<uint8>(); // item slot in mail, not used
- recvData.ReadByteSeq(itemGUIDs[i][3]);
- recvData.ReadByteSeq(itemGUIDs[i][0]);
- recvData.ReadByteSeq(itemGUIDs[i][4]);
- recvData.ReadByteSeq(itemGUIDs[i][5]);
- }
-
- recvData.ReadByteSeq(mailbox[7]);
- recvData.ReadByteSeq(mailbox[3]);
- recvData.ReadByteSeq(mailbox[6]);
- recvData.ReadByteSeq(mailbox[5]);
-
- subject = recvData.ReadString(subjectLength);
- receiverName = recvData.ReadString(receiverLength);
-
- recvData.ReadByteSeq(mailbox[2]);
- recvData.ReadByteSeq(mailbox[0]);
-
- body = recvData.ReadString(bodyLength);
-
- recvData.ReadByteSeq(mailbox[1]);
-
- // packet read complete, now do check
-
- if (!CanOpenMailBox(mailbox))
+ if (!CanOpenMailBox(packet.Info.Mailbox))
return;
- if (receiverName.empty())
+ if (packet.Info.Target.empty())
return;
Player* player = _player;
@@ -153,23 +81,39 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
}
ObjectGuid receiverGuid;
- if (normalizePlayerName(receiverName))
- receiverGuid = ObjectMgr::GetPlayerGUIDByName(receiverName);
+ if (normalizePlayerName(packet.Info.Target))
+ receiverGuid = ObjectMgr::GetPlayerGUIDByName(packet.Info.Target);
if (!receiverGuid)
{
TC_LOG_INFO("network", "Player %s is sending mail to %s (GUID: not existed!) with subject %s "
- "and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u",
- player->GetGUID().ToString().c_str(), receiverName.c_str(), subject.c_str(), body.c_str(),
- items_count, money, COD, stationery, package);
+ "and body %s includes " SZFMTD " items, " SI64FMTD " copper and " SI64FMTD " COD copper with StationeryID = %d, PackageID = %d",
+ GetPlayerInfo().c_str(), packet.Info.Target.c_str(), packet.Info.Subject.c_str(), packet.Info.Body.c_str(),
+ packet.Info.Attachments.size(), packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID, packet.Info.PackageID);
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND);
return;
}
+ if (packet.Info.SendMoney < 0)
+ {
+ GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR);
+ TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative money value (SendMoney: " SI64FMTD ")",
+ GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.SendMoney);
+ return;
+ }
+
+ if (packet.Info.Cod < 0)
+ {
+ GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR);
+ TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative COD value (Cod: " SI64FMTD ")",
+ GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.Cod);
+ return;
+ }
+
TC_LOG_INFO("network", "Player %s is sending mail to %s (%s) with subject %s and body %s "
- "includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u",
- player->GetGUID().ToString().c_str(), receiverName.c_str(), receiverGuid.ToString().c_str(), subject.c_str(),
- body.c_str(), items_count, money, COD, stationery, package);
+ "includes " SZFMTD " items, " SI64FMTD " copper and " SI64FMTD " COD copper with StationeryID = %d, PackageID = %d",
+ GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.Subject.c_str(),
+ packet.Info.Body.c_str(), packet.Info.Attachments.size(), packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID, packet.Info.PackageID);
if (player->GetGUID() == receiverGuid)
{
@@ -177,12 +121,12 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
return;
}
- uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client
+ uint32 cost = !packet.Info.Attachments.empty() ? 30 * packet.Info.Attachments.size() : 30; // price hardcoded in client
- uint64 reqmoney = cost + money;
+ int64 reqmoney = cost + packet.Info.SendMoney;
// Check for overflow
- if (reqmoney < money)
+ if (reqmoney < packet.Info.SendMoney)
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY);
return;
@@ -246,10 +190,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
}
// test the receiver's Faction... or all items are account bound
- bool accountBound = items_count ? true : false;
- for (uint8 i = 0; i < items_count; ++i)
+ bool accountBound = !packet.Info.Attachments.empty();
+ for (auto const& att : packet.Info.Attachments)
{
- if (Item* item = player->GetItemByGuid(itemGUIDs[i]))
+ if (Item* item = player->GetItemByGuid(att.ItemGUID))
{
ItemTemplate const* itemProto = item->GetTemplate();
if (!itemProto || !(itemProto->GetFlags() & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT))
@@ -272,17 +216,17 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
return;
}
- Item* items[MAX_MAIL_ITEMS];
+ std::vector<Item*> items;
- for (uint8 i = 0; i < items_count; ++i)
+ for (auto const& att : packet.Info.Attachments)
{
- if (!itemGUIDs[i])
+ if (att.ItemGUID.IsEmpty())
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID);
return;
}
- Item* item = player->GetItemByGuid(itemGUIDs[i]);
+ Item* item = player->GetItemByGuid(att.ItemGUID);
// prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)
if (!item)
@@ -312,7 +256,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
return;
}
- if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
+ if (packet.Info.Cod && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD);
return;
@@ -324,38 +268,37 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
return;
}
- items[i] = item;
+ items.push_back(item);
}
player->SendMailResult(0, MAIL_SEND, MAIL_OK);
- player->ModifyMoney(-int64(reqmoney));
+ player->ModifyMoney(-reqmoney);
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost);
bool needItemDelay = false;
- MailDraft draft(subject, body);
+ MailDraft draft(packet.Info.Subject, packet.Info.Body);
SQLTransaction trans = CharacterDatabase.BeginTransaction();
- if (items_count > 0 || money > 0)
+ if (!packet.Info.Attachments.empty() || packet.Info.SendMoney > 0)
{
bool log = HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE);
- if (items_count > 0)
+ if (!packet.Info.Attachments.empty())
{
- for (uint8 i = 0; i < items_count; ++i)
+ for (auto const& item : items)
{
- Item* item = items[i];
if (log)
{
sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail item: %s (Entry: %u Count: %u) "
"to: %s (%s) (Account: %u)", GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(),
item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount(),
- receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId);
+ packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId);
}
item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable
- player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true);
+ player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
item->DeleteFromInventoryDB(trans); // deletes item from character's inventory
item->SetOwnerGUID(receiverGuid);
@@ -368,10 +311,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId;
}
- if (log && money > 0)
+ if (log && packet.Info.SendMoney > 0)
{
- sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail money: " UI64FMTD " to: %s (%s) (Account: %u)",
- GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), money, receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId);
+ sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail money: " SI64FMTD " to: %s (%s) (Account: %u)",
+ GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), packet.Info.SendMoney, packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId);
}
}
@@ -384,32 +327,27 @@ void WorldSession::HandleSendMail(WorldPacket& recvData)
deliver_delay = 0;
// don't ask for COD if there are no items
- if (items_count == 0)
- COD = 0;
+ if (packet.Info.Attachments.empty())
+ packet.Info.Cod = 0;
// will delete item or place to receiver mail list
draft
- .AddMoney(money)
- .AddCOD(COD)
- .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay);
+ .AddMoney(packet.Info.SendMoney)
+ .AddCOD(packet.Info.Cod)
+ .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), packet.Info.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay);
player->SaveInventoryAndGoldToDB(trans);
CharacterDatabase.CommitTransaction(trans);
}
//called when mail is read
-void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData)
+void WorldSession::HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead& packet)
{
- ObjectGuid mailbox;
- uint32 mailId;
- recvData >> mailbox;
- recvData >> mailId;
-
- if (!CanOpenMailBox(mailbox))
+ if (!CanOpenMailBox(packet.Mailbox))
return;
Player* player = _player;
- Mail* m = player->GetMail(mailId);
+ Mail* m = player->GetMail(packet.MailID);
if (m && m->state != MAIL_STATE_DELETED)
{
if (player->unReadMails)
@@ -421,18 +359,9 @@ void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData)
}
//called when client deletes mail
-void WorldSession::HandleMailDelete(WorldPacket& recvData)
+void WorldSession::HandleMailDelete(WorldPackets::Mail::MailDelete& packet)
{
- ObjectGuid mailbox;
- uint32 mailId;
- recvData >> mailbox;
- recvData >> mailId;
- recvData.read_skip<uint32>(); // mailTemplateId
-
- if (!CanOpenMailBox(mailbox))
- return;
-
- Mail* m = _player->GetMail(mailId);
+ Mail* m = _player->GetMail(packet.MailID);
Player* player = _player;
player->m_mailsUpdated = true;
if (m)
@@ -440,45 +369,40 @@ void WorldSession::HandleMailDelete(WorldPacket& recvData)
// delete shouldn't show up for COD mails
if (m->COD)
{
- player->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR);
return;
}
m->state = MAIL_STATE_DELETED;
}
- player->SendMailResult(mailId, MAIL_DELETED, MAIL_OK);
+ player->SendMailResult(packet.MailID, MAIL_DELETED, MAIL_OK);
}
-void WorldSession::HandleMailReturnToSender(WorldPacket& recvData)
+void WorldSession::HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender& packet)
{
- ObjectGuid mailbox;
- uint32 mailId;
- recvData >> mailbox;
- recvData >> mailId;
- recvData.read_skip<uint64>(); // original sender GUID for return to, not used
-
- if (!CanOpenMailBox(mailbox))
- return;
+ //TODO: find a proper way to replace this check. Idea: Save Guid form MailGetList until CMSG_CLOSE_INTERACTION is sent
+ /*if (!CanOpenMailBox(mailbox))
+ return;*/
Player* player = _player;
- Mail* m = player->GetMail(mailId);
- if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
+ Mail* m = player->GetMail(packet.MailID);
+ if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr) || m->sender != packet.SenderGUID.GetCounter())
{
- player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR);
return;
}
//we can return mail now, so firstly delete the old one
SQLTransaction trans = CharacterDatabase.BeginTransaction();
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
- stmt->setUInt32(0, mailId);
+ stmt->setUInt32(0, packet.MailID);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
- stmt->setUInt32(0, mailId);
+ stmt->setUInt32(0, packet.MailID);
trans->Append(stmt);
- player->RemoveMail(mailId);
+ player->RemoveMail(packet.MailID);
// only return mail if the player exists (and delete if not existing)
if (m->messageType == MAIL_NORMAL && m->sender)
@@ -502,54 +426,49 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recvData)
CharacterDatabase.CommitTransaction(trans);
delete m; //we can deallocate old mail
- player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK);
+ player->SendMailResult(packet.MailID, MAIL_RETURNED_TO_SENDER, MAIL_OK);
}
//called when player takes item attached in mail
-void WorldSession::HandleMailTakeItem(WorldPacket& recvData)
+void WorldSession::HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& packet)
{
- ObjectGuid mailbox;
- uint32 mailId;
- ObjectGuid::LowType itemId;
- recvData >> mailbox;
- recvData >> mailId;
- recvData >> itemId; // item guid low
-
- if (!CanOpenMailBox(mailbox))
+ uint32 AttachID = packet.AttachID;
+
+ if (!CanOpenMailBox(packet.Mailbox))
return;
Player* player = _player;
- Mail* m = player->GetMail(mailId);
- if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL))
+ Mail* m = player->GetMail(packet.MailID);
+ if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr))
{
- player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
// verify that the mail has the item to avoid cheaters taking COD items without paying
- if (std::find_if(m->items.begin(), m->items.end(), [itemId](MailItemInfo info){ return info.item_guid == itemId; }) == m->items.end())
+ if (std::find_if(m->items.begin(), m->items.end(), [AttachID](MailItemInfo info){ return info.item_guid == AttachID; }) == m->items.end())
{
- player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
// prevent cheating with skip client money check
if (!player->HasEnoughMoney(uint64(m->COD)))
{
- player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY);
+ player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY);
return;
}
- Item* it = player->GetMItem(itemId);
+ Item* it = player->GetMItem(packet.AttachID);
ItemPosCountVec dest;
uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false);
if (msg == EQUIP_ERR_OK)
{
SQLTransaction trans = CharacterDatabase.BeginTransaction();
- m->RemoveItem(itemId);
- m->removedItems.push_back(itemId);
+ m->RemoveItem(packet.AttachID);
+ m->removedItems.push_back(packet.AttachID);
if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail
{
@@ -603,38 +522,30 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData)
player->_SaveMail(trans);
CharacterDatabase.CommitTransaction(trans);
- player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count);
+ player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_OK, 0, packet.AttachID, count);
}
else
- player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg);
+ player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg);
}
-void WorldSession::HandleMailTakeMoney(WorldPacket& recvData)
+void WorldSession::HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney& packet)
{
- ObjectGuid mailbox;
- uint64 money;
- uint32 mailId;
-
- recvData >> mailbox;
- recvData >> mailId;
- recvData >> money;
-
- if (!CanOpenMailBox(mailbox))
+ if (!CanOpenMailBox(packet.Mailbox))
return;
Player* player = _player;
- Mail* m = player->GetMail(mailId);
+ Mail* m = player->GetMail(packet.MailID);
if ((!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) ||
- (money > 0 && m->money != money))
+ (packet.Money > 0 && m->money != uint64(packet.Money)))
{
- player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR);
return;
}
if (!player->ModifyMoney(m->money, false))
{
- player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD);
+ player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD);
return;
}
@@ -642,7 +553,7 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData)
m->state = MAIL_STATE_CHANGED;
player->m_mailsUpdated = true;
- player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK);
+ player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_OK);
// save money and mail to prevent cheating
SQLTransaction trans = CharacterDatabase.BeginTransaction();
@@ -652,12 +563,9 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData)
}
//called when player lists his received mails
-void WorldSession::HandleGetMailList(WorldPacket& recvData)
+void WorldSession::HandleGetMailList(WorldPackets::Mail::MailGetList& packet)
{
- ObjectGuid mailbox;
- recvData >> mailbox;
-
- if (!CanOpenMailBox(mailbox))
+ if (!CanOpenMailBox(packet.Mailbox))
return;
Player* player = _player;
@@ -666,130 +574,42 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData)
if (!player->m_mailsLoaded)
player->_LoadMail();
- // client can't work with packets > max int16 value
- const uint32 maxPacketSize = 32767;
-
- uint32 mailsCount = 0; // real send to client mails amount
- uint32 realCount = 0; // real mails amount
-
- WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size
- data << uint32(0); // real mail's count
- data << uint8(0); // mail's count
- time_t cur_time = time(NULL);
+ WorldPackets::Mail::MailListResult response;
+ response.TotalNumRecords = player->GetMailSize();
- for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr)
+ time_t cur_time = time(nullptr);
+
+ for (Mail* m : player->GetMails())
{
- // Only first 50 mails are displayed
- if (mailsCount >= 50)
- {
- realCount += 1;
- continue;
- }
-
// skip deleted or not delivered (deliver delay not expired) mails
- if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time)
+ if (m->state == MAIL_STATE_DELETED || cur_time < m->deliver_time)
continue;
- uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12)
-
- size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+((*itr)->body.size()+1)+1+item_count*(1+8+4+MAX_INSPECTED_ENCHANTMENT_SLOT*3*4+4+4+4+4+4+4+1);
-
- if (data.wpos()+next_mail_size > maxPacketSize)
- {
- realCount += 1;
- continue;
- }
-
- data << uint16(next_mail_size); // Message size
- data << uint32((*itr)->messageID); // Message ID
- data << uint8((*itr)->messageType); // Message Type
-
- switch ((*itr)->messageType)
- {
- case MAIL_NORMAL: // sender guid
- data << ObjectGuid::Create<HighGuid::Player>((*itr)->sender);
- break;
- case MAIL_CREATURE:
- case MAIL_GAMEOBJECT:
- case MAIL_AUCTION:
- case MAIL_CALENDAR:
- data << uint32((*itr)->sender); // creature/gameobject entry, auction id, calendar event id?
- break;
- }
-
- data << uint64((*itr)->COD); // COD
- data << uint32(0); // Package.dbc ID ?
- data << uint32((*itr)->stationery); // stationery (Stationery.dbc)
- data << uint64((*itr)->money); // Gold
- data << uint32((*itr)->checked); // flags
- data << float(float((*itr)->expire_time-time(NULL))/DAY); // Time
- data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc)
- data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256
- data << (*itr)->body; // message? max 8000
- data << uint8(item_count); // client limit is 0x10
-
- for (uint8 i = 0; i < item_count; ++i)
- {
- Item* item = player->GetMItem((*itr)->items[i].item_guid);
- // item index (0-6?)
- data << uint8(i);
- // item guid low?
- data << uint64((item ? item->GetGUID().GetCounter() : UI64LIT(0)));
- // entry
- data << uint32((item ? item->GetEntry() : 0));
- for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j)
- {
- data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0));
- data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0));
- data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0));
- }
-
- // can be negative
- data << int32((item ? item->GetItemRandomPropertyId() : 0));
- // unk
- data << uint32((item ? item->GetItemSuffixFactor() : 0));
- // stack count
- data << uint32((item ? item->GetCount() : 0));
- // charges
- data << uint32((item ? item->GetSpellCharges() : 0));
- // durability
- data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0));
- // durability
- data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0));
- // unknown wotlk
- data << uint8(0);
- }
+ response.Mails.emplace_back(m, player);
- ++realCount;
- ++mailsCount;
+ // max. 50 mails can be sent
+ if (response.Mails.size() >= 50)
+ break;
}
- data.put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount
- data.put<uint8>(4, mailsCount); // set real send mails to client
- SendPacket(&data);
+ SendPacket(response.Write());
// recalculate m_nextMailDelivereTime and unReadMails
_player->UpdateNextMailTimeAndUnreads();
}
//used when player copies mail body to his inventory
-void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData)
+void WorldSession::HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem& packet)
{
- ObjectGuid mailbox;
- uint32 mailId;
-
- recvData >> mailbox;
- recvData >> mailId;
-
- if (!CanOpenMailBox(mailbox))
+ if (!CanOpenMailBox(packet.Mailbox))
return;
Player* player = _player;
- Mail* m = player->GetMail(mailId);
- if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL) || (m->checked & MAIL_CHECK_MASK_COPIED))
+ Mail* m = player->GetMail(packet.MailID);
+ if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr) || (m->checked & MAIL_CHECK_MASK_COPIED))
{
- player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
return;
}
@@ -806,7 +626,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData)
MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId);
if (!mailTemplateEntry)
{
- player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
+ player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR);
return;
}
@@ -820,8 +640,6 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData)
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK);
- TC_LOG_INFO("network", "HandleMailCreateTextItem mailid=%u", mailId);
-
ItemPosCountVec dest;
uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false);
if (msg == EQUIP_ERR_OK)
@@ -831,65 +649,54 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData)
player->m_mailsUpdated = true;
player->StoreItem(dest, bodyItem, true);
- player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK);
+ player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_OK);
}
else
{
- player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg);
+ player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg);
delete bodyItem;
}
}
/// @todo Fix me! ... this void has probably bad condition, but good data are sent
-void WorldSession::HandleQueryNextMailTime(WorldPacket& /*recvData*/)
+void WorldSession::HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime& /*packet*/)
{
- WorldPacket data(SMSG_MAIL_QUERY_NEXT_TIME_RESULT, 8);
+ WorldPackets::Mail::MailQueryNextTimeResult result;
if (!_player->m_mailsLoaded)
_player->_LoadMail();
if (_player->unReadMails > 0)
{
- data << float(0); // float
- data << uint32(0); // count
+ result.NextMailTime = 0.0f;
- uint32 count = 0;
- time_t now = time(NULL);
+ time_t now = time(nullptr);
std::set<ObjectGuid::LowType> sentSenders;
- for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr)
+
+ for (Mail* mail : _player->GetMails())
{
- Mail* m = (*itr);
- // must be not checked yet
- if (m->checked & MAIL_CHECK_MASK_READ)
+ if (mail->checked & MAIL_CHECK_MASK_READ)
continue;
- // and already delivered
- if (now < m->deliver_time)
+ // already delivered
+ if (now < mail->deliver_time)
continue;
// only send each mail sender once
- if (sentSenders.count(m->sender))
+ if (sentSenders.count(mail->sender))
continue;
- data << (m->messageType == MAIL_NORMAL ? ObjectGuid::Create<HighGuid::Player>(m->sender) : ObjectGuid::Empty); // player guid
- data << uint32(m->messageType != MAIL_NORMAL ? m->sender : 0); // non-player entries
- data << uint32(m->messageType);
- data << uint32(m->stationery);
- data << float(m->deliver_time - now);
+ result.Next.emplace_back(mail);
- sentSenders.insert(m->sender);
- ++count;
- if (count == 2) // do not display more than 2 mails
+ sentSenders.insert(mail->sender);
+
+ // do not send more than 2 mails
+ if (sentSenders.size() > 2)
break;
}
-
- data.put<uint32>(4, count);
}
else
- {
- data << float(-DAY);
- data << uint32(0);
- }
+ result.NextMailTime = -DAY;
- SendPacket(&data);
+ SendPacket(result.Write());
}