TrinityCore
MailHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "AccountMgr.h"
20#include "BattlenetAccountMgr.h"
21#include "CharacterCache.h"
22#include "DatabaseEnv.h"
23#include "DB2Stores.h"
24#include "GossipDef.h"
25#include "GameTime.h"
26#include "Guild.h"
27#include "GuildMgr.h"
28#include "Item.h"
29#include "Language.h"
30#include "Log.h"
31#include "Mail.h"
32#include "MailPackets.h"
33#include "ObjectAccessor.h"
34#include "ObjectMgr.h"
35#include "Player.h"
36#include "World.h"
37
39{
40 if (guid == _player->GetGUID())
41 {
43 {
44 TC_LOG_WARN("cheat", "{} attempted to open mailbox by using a cheat.", _player->GetName());
45 return false;
46 }
47 }
48 else if (guid.IsGameObject())
49 {
51 return false;
52 }
53 else if (guid.IsAnyTypeCreature())
54 {
56 return false;
57 }
58 else
59 return false;
60
61 return true;
62}
63
65{
66 if (sendMail.Info.Attachments.size() > MAX_CLIENT_MAIL_ITEMS) // client limit
67 {
69 return;
70 }
71
72 if (!CanOpenMailBox(sendMail.Info.Mailbox))
73 return;
74
75 if (sendMail.Info.Target.empty())
76 return;
77
79 return;
80
81 Player* player = _player;
82
83 if (player->GetLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ))
84 {
86 return;
87 }
88
89 ObjectGuid receiverGuid;
90 if (normalizePlayerName(sendMail.Info.Target))
91 receiverGuid = sCharacterCache->GetCharacterGuidByName(sendMail.Info.Target);
92
93 if (!receiverGuid)
94 {
95 TC_LOG_INFO("network", "Player {} is sending mail to {} (GUID: non-existing!) with subject {} "
96 "and body {} includes {} items, {} copper and {} COD copper with StationeryID = {}",
97 GetPlayerInfo(), sendMail.Info.Target, sendMail.Info.Subject, sendMail.Info.Body,
98 sendMail.Info.Attachments.size(), sendMail.Info.SendMoney, sendMail.Info.Cod, sendMail.Info.StationeryID);
100 return;
101 }
102
103 if (sendMail.Info.SendMoney < 0)
104 {
106 TC_LOG_WARN("cheat", "Player {} attempted to send mail to {} ({}) with negative money value (SendMoney: {})",
107 GetPlayerInfo(), sendMail.Info.Target, receiverGuid.ToString(), sendMail.Info.SendMoney);
108 return;
109 }
110
111 if (sendMail.Info.Cod < 0)
112 {
114 TC_LOG_WARN("cheat", "Player {} attempted to send mail to {} ({}) with negative COD value (Cod: {})",
115 GetPlayerInfo(), sendMail.Info.Target, receiverGuid.ToString(), sendMail.Info.Cod);
116 return;
117 }
118
119 TC_LOG_INFO("network", "Player {} is sending mail to {} ({}) with subject {} and body {} "
120 "includes {} items, {} copper and " SI64FMTD " COD copper with StationeryID = {}",
121 GetPlayerInfo(), sendMail.Info.Target, receiverGuid.ToString(), sendMail.Info.Subject,
122 sendMail.Info.Body, sendMail.Info.Attachments.size(), sendMail.Info.SendMoney, sendMail.Info.Cod, sendMail.Info.StationeryID);
123
124 if (player->GetGUID() == receiverGuid)
125 {
127 return;
128 }
129
130 uint32 cost = !sendMail.Info.Attachments.empty() ? 30 * sendMail.Info.Attachments.size() : 30; // price hardcoded in client
131
132 int64 reqmoney = cost + sendMail.Info.SendMoney;
133
134 // Check for overflow
135 if (reqmoney < sendMail.Info.SendMoney)
136 {
138 return;
139 }
140
141 auto mailCountCheckContinuation = [this, player = _player, receiverGuid, mailInfo = std::move(sendMail.Info), reqmoney, cost](Team receiverTeam, uint64 mailsCount, uint8 receiverLevel, uint32 receiverAccountId, uint32 receiverBnetAccountId) mutable
142 {
143 if (_player != player)
144 return;
145
146 if (!player->HasEnoughMoney(reqmoney) && !player->IsGameMaster())
147 {
149 return;
150 }
151
152 // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255..
153 if (mailsCount > 100)
154 {
156 return;
157 }
158
159 // test the receiver's Faction... or all items are account bound
160 bool accountBound = !mailInfo.Attachments.empty();
161 for (WorldPackets::Mail::SendMail::StructSendMail::MailAttachment const& att : mailInfo.Attachments)
162 {
163 if (Item* item = player->GetItemByGuid(att.ItemGUID))
164 {
165 ItemTemplate const* itemProto = item->GetTemplate();
166 if (!itemProto || !itemProto->HasFlag(ITEM_FLAG_IS_BOUND_TO_ACCOUNT))
167 {
168 accountBound = false;
169 break;
170 }
171 }
172 }
173
174 if (!accountBound && player->GetTeam() != receiverTeam && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL))
175 {
177 return;
178 }
179
180 if (receiverLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ))
181 {
183 return;
184 }
185
186 std::vector<Item*> items;
187
188 for (WorldPackets::Mail::SendMail::StructSendMail::MailAttachment const& att : mailInfo.Attachments)
189 {
190 if (att.ItemGUID.IsEmpty())
191 {
193 return;
194 }
195
196 Item* item = player->GetItemByGuid(att.ItemGUID);
197
198 // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)
199 if (!item)
200 {
202 return;
203 }
204
205 // handle empty bag before CanBeTraded, since that func already has that check
206 if (item->IsNotEmptyBag())
207 {
209 return;
210 }
211
212 if (!item->CanBeTraded(true))
213 {
215 return;
216 }
217
218 if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId)
219 {
220 if (!item->IsBattlenetAccountBound() || !player->GetSession()->GetBattlenetAccountId() || player->GetSession()->GetBattlenetAccountId() != receiverBnetAccountId)
221 {
223 return;
224 }
225 }
226
227 if (item->GetTemplate()->HasFlag(ITEM_FLAG_CONJURED) || *item->m_itemData->Expiration)
228 {
230 return;
231 }
232
233 if (mailInfo.Cod && item->IsWrapped())
234 {
236 return;
237 }
238
239 items.push_back(item);
240 }
241
242 player->SendMailResult(0, MAIL_SEND, MAIL_OK);
243
244 player->ModifyMoney(-reqmoney);
246
247 bool needItemDelay = false;
248
249 MailDraft draft(mailInfo.Subject, mailInfo.Body);
250
251 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
252
253 if (!mailInfo.Attachments.empty() || mailInfo.SendMoney > 0)
254 {
256 if (!mailInfo.Attachments.empty())
257 {
258 for (auto const& item : items)
259 {
260 if (log)
261 {
262 sLog->OutCommand(GetAccountId(), "GM {} ({}) (Account: {}) mail item: {} (Entry: {} Count: {}) "
263 "to: {} ({}) (Account: {})", GetPlayerName(), _player->GetGUID().ToString(), GetAccountId(),
264 item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount(),
265 mailInfo.Target, receiverGuid.ToString(), receiverAccountId);
266 }
267
268 item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable
269 player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
270
271 item->DeleteFromInventoryDB(trans); // deletes item from character's inventory
272 item->SetOwnerGUID(receiverGuid);
273 item->SetState(ITEM_CHANGED);
274 item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
275
276 draft.AddItem(item);
277 }
278
279 // if item send to character at another account, then apply item delivery delay
280 needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId;
281 }
282
283 if (log && mailInfo.SendMoney > 0)
284 {
285 sLog->OutCommand(GetAccountId(), "GM {} ({}) (Account: {}) mail money: {} to: {} ({}) (Account: {})",
286 GetPlayerName(), _player->GetGUID().ToString(), GetAccountId(), mailInfo.SendMoney, mailInfo.Target, receiverGuid.ToString(), receiverAccountId);
287 }
288 }
289
290 // If theres is an item, there is a one hour delivery delay if sent to another account's character.
291 uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0;
292
293 // Mail sent between guild members arrives instantly
294 if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId()))
295 if (guild->IsMember(receiverGuid))
296 deliver_delay = 0;
297
298 // don't ask for COD if there are no items
299 if (mailInfo.Attachments.empty())
300 mailInfo.Cod = 0;
301
302 // will delete item or place to receiver mail list
303 draft
304 .AddMoney(mailInfo.SendMoney)
305 .AddCOD(mailInfo.Cod)
306 .SendMailTo(trans, MailReceiver(ObjectAccessor::FindConnectedPlayer(receiverGuid), receiverGuid.GetCounter()), MailSender(player), mailInfo.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay);
307
308 player->SaveInventoryAndGoldToDB(trans);
309 CharacterDatabase.CommitTransaction(trans);
310 };
311
312 if (Player* receiver = ObjectAccessor::FindConnectedPlayer(receiverGuid))
313 {
314 mailCountCheckContinuation(receiver->GetTeam(), receiver->GetMailSize(), receiver->GetLevel(), receiver->GetSession()->GetAccountId(), receiver->GetSession()->GetBattlenetAccountId());
315 }
316 else
317 {
319 stmt->setUInt64(0, receiverGuid.GetCounter());
320
322 .WithChainingPreparedCallback([continuation = std::move(mailCountCheckContinuation), receiverGuid](QueryCallback& queryCallback, PreparedQueryResult mailCountResult) mutable
323 {
324 if (CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(receiverGuid))
325 queryCallback.WithPreparedCallback([continuation = std::move(continuation), characterInfo, mailCountResult](PreparedQueryResult bnetAccountResult) mutable
326 {
327 continuation(Player::TeamForRace(characterInfo->Race), mailCountResult ? (*mailCountResult)[0].GetUInt64() : UI64LIT(0),
328 characterInfo->Level, characterInfo->AccountId, bnetAccountResult ? (*bnetAccountResult)[0].GetUInt32() : 0);
329 }).SetNextQuery(Battlenet::AccountMgr::GetIdByGameAccountAsync(characterInfo->AccountId));
330 }));
331 }
332}
333
334//called when mail is read
336{
337 if (!CanOpenMailBox(markAsRead.Mailbox))
338 return;
339
340 Player* player = _player;
341 Mail* m = player->GetMail(markAsRead.MailID);
342 if (m && m->state != MAIL_STATE_DELETED)
343 {
344 if (player->unReadMails)
345 --player->unReadMails;
347 player->m_mailsUpdated = true;
349 }
350}
351
352//called when client deletes mail
354{
355 Mail* m = _player->GetMail(mailDelete.MailID);
356 Player* player = _player;
357 player->m_mailsUpdated = true;
358 if (m)
359 {
360 // delete shouldn't show up for COD mails
361 if (m->COD)
362 {
364 return;
365 }
366
368 }
369 player->SendMailResult(mailDelete.MailID, MAIL_DELETED, MAIL_OK);
370}
371
373{
374 if (!CanOpenMailBox(_player->PlayerTalkClass->GetInteractionData().SourceGuid))
375 return;
376
377 Player* player = _player;
378 Mail* m = player->GetMail(returnToSender.MailID);
379 if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime() || m->sender != returnToSender.SenderGUID.GetCounter())
380 {
382 return;
383 }
384 //we can return mail now, so firstly delete the old one
385 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
386
388 stmt->setUInt64(0, returnToSender.MailID);
389 trans->Append(stmt);
390
391 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
392 stmt->setUInt64(0, returnToSender.MailID);
393 trans->Append(stmt);
394
395 player->RemoveMail(returnToSender.MailID);
396
397 // only return mail if the player exists (and delete if not existing)
398 if (m->messageType == MAIL_NORMAL && m->sender)
399 {
400 MailDraft draft(m->subject, m->body);
401 if (m->mailTemplateId)
402 draft = MailDraft(m->mailTemplateId, false); // items already included
403
404 if (m->HasItems())
405 {
406 for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
407 {
408 if (Item* const item = player->GetMItem(itr2->item_guid))
409 draft.AddItem(item);
410 player->RemoveMItem(itr2->item_guid);
411 }
412 }
413 draft.AddMoney(m->money).SendReturnToSender(GetAccountId(), m->receiver, m->sender, trans);
414 }
415
416 CharacterDatabase.CommitTransaction(trans);
417
418 delete m; //we can deallocate old mail
419 player->SendMailResult(returnToSender.MailID, MAIL_RETURNED_TO_SENDER, MAIL_OK);
420}
421
422//called when player takes item attached in mail
424{
425 uint64 AttachID = takeItem.AttachID;
426
427 if (!CanOpenMailBox(takeItem.Mailbox))
428 return;
429
430 Player* player = _player;
431
432 Mail* m = player->GetMail(takeItem.MailID);
434 {
436 return;
437 }
438
439 // verify that the mail has the item to avoid cheaters taking COD items without paying
440 if (std::find_if(m->items.begin(), m->items.end(), [AttachID](MailItemInfo info){ return info.item_guid == AttachID; }) == m->items.end())
441 {
443 return;
444 }
445
446 // prevent cheating with skip client money check
447 if (!player->HasEnoughMoney(m->COD))
448 {
450 return;
451 }
452
453 Item* it = player->GetMItem(takeItem.AttachID);
454
455 ItemPosCountVec dest;
456 uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false);
457 if (msg == EQUIP_ERR_OK)
458 {
459 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
460 m->RemoveItem(takeItem.AttachID);
461 m->removedItems.push_back(takeItem.AttachID);
462
463 if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail
464 {
465 ObjectGuid sender_guid = ObjectGuid::Create<HighGuid::Player>(m->sender);
466 Player* receiver = ObjectAccessor::FindConnectedPlayer(sender_guid);
467
468 uint32 sender_accId = 0;
469
471 {
472 std::string sender_name;
473 if (receiver)
474 {
475 sender_accId = receiver->GetSession()->GetAccountId();
476 sender_name = receiver->GetName();
477 }
478 else
479 {
480 // can be calculated early
481 sender_accId = sCharacterCache->GetCharacterAccountIdByGuid(sender_guid);
482
483 if (!sCharacterCache->GetCharacterNameByGuid(sender_guid, sender_name))
484 sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN);
485 }
486 sLog->OutCommand(GetAccountId(), "GM {} (Account: {}) receiver mail item: {} (Entry: {} Count: {}) and send COD money: {} to player: {} (Account: {})",
487 GetPlayerName(), GetAccountId(), it->GetTemplate()->GetDefaultLocaleName(), it->GetEntry(), it->GetCount(), m->COD, sender_name, sender_accId);
488 }
489 else if (!receiver)
490 sender_accId = sCharacterCache->GetCharacterAccountIdByGuid(sender_guid);
491
492 // check player existence
493 if (receiver || sender_accId)
494 {
495 MailDraft(m->subject, "")
496 .AddMoney(m->COD)
498 }
499
500 player->ModifyMoney(-int64(m->COD));
501 }
502 m->COD = 0;
504 player->m_mailsUpdated = true;
505 player->RemoveMItem(it->GetGUID().GetCounter());
506
507 uint32 count = it->GetCount(); // save counts before store and possible merge with deleting
508 it->SetState(ITEM_UNCHANGED); // need to set this state, otherwise item cannot be removed later, if neccessary
509 player->MoveItemToInventory(dest, it, true);
510
511 player->SaveInventoryAndGoldToDB(trans);
512 player->_SaveMail(trans);
513 CharacterDatabase.CommitTransaction(trans);
514
515 player->SendMailResult(takeItem.MailID, MAIL_ITEM_TAKEN, MAIL_OK, 0, takeItem.AttachID, count);
516 }
517 else
519}
520
522{
523 if (!CanOpenMailBox(takeMoney.Mailbox))
524 return;
525
526 Player* player = _player;
527
528 Mail* m = player->GetMail(takeMoney.MailID);
529 if ((!m || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime()) ||
530 (takeMoney.Money > 0 && m->money != uint64(takeMoney.Money)))
531 {
533 return;
534 }
535
536 if (!player->ModifyMoney(m->money, false))
537 {
539 return;
540 }
541
542 m->money = 0;
544 player->m_mailsUpdated = true;
545
546 player->SendMailResult(takeMoney.MailID, MAIL_MONEY_TAKEN, MAIL_OK);
547
548 // save money and mail to prevent cheating
549 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
550 player->SaveInventoryAndGoldToDB(trans);
551 player->_SaveMail(trans);
552 CharacterDatabase.CommitTransaction(trans);
553}
554
555//called when player lists his received mails
557{
558 if (!CanOpenMailBox(getList.Mailbox))
559 return;
560
561 Player* player = _player;
562
564 time_t curTime = GameTime::GetGameTime();
565
566 for (Mail* m : player->GetMails())
567 {
568 // skip deleted or not delivered (deliver delay not expired) mails
569 if (m->state == MAIL_STATE_DELETED || curTime < m->deliver_time)
570 continue;
571
572 // max. 100 mails can be sent
573 if (response.Mails.size() < 100)
574 response.Mails.emplace_back(m, player);
575
576 ++response.TotalNumRecords;
577 }
578
579 player->PlayerTalkClass->GetInteractionData().Reset();
580 player->PlayerTalkClass->GetInteractionData().SourceGuid = getList.Mailbox;
581 SendPacket(response.Write());
582
583 // recalculate m_nextMailDelivereTime and unReadMails
585}
586
587//used when player copies mail body to his inventory
589{
590 if (!CanOpenMailBox(createTextItem.Mailbox))
591 return;
592
593 Player* player = _player;
594
595 Mail* m = player->GetMail(createTextItem.MailID);
596 if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > GameTime::GetGameTime() || (m->checked & MAIL_CHECK_MASK_COPIED))
597 {
599 return;
600 }
601
603 if (!bodyItem)
604 return;
605
606 // in mail template case we need create new item text
607 if (m->mailTemplateId)
608 {
609 MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId);
610 ASSERT(mailTemplateEntry);
611 bodyItem->SetText(mailTemplateEntry->Body[GetSessionDbcLocale()]);
612 }
613 else
614 bodyItem->SetText(m->body);
615
616 if (m->messageType == MAIL_NORMAL)
617 bodyItem->SetCreator(ObjectGuid::Create<HighGuid::Player>(m->sender));
618
620
621 ItemPosCountVec dest;
622 uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false);
623 if (msg == EQUIP_ERR_OK)
624 {
627 player->m_mailsUpdated = true;
628
629 player->StoreItem(dest, bodyItem, true);
630 player->SendMailResult(createTextItem.MailID, MAIL_MADE_PERMANENT, MAIL_OK);
631 }
632 else
633 {
634 player->SendMailResult(createTextItem.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg);
635 delete bodyItem;
636 }
637}
638
640{
642
643 if (_player->unReadMails > 0)
644 {
645 result.NextMailTime = 0.0f;
646
647 time_t now = GameTime::GetGameTime();
648 std::set<ObjectGuid::LowType> sentSenders;
649
650 for (Mail* mail : _player->GetMails())
651 {
652 if (mail->checked & MAIL_CHECK_MASK_READ)
653 continue;
654
655 // already delivered
656 if (now < mail->deliver_time)
657 continue;
658
659 // only send each mail sender once
660 if (sentSenders.count(mail->sender))
661 continue;
662
663 result.Next.emplace_back(mail);
664
665 sentSenders.insert(mail->sender);
666
667 // do not send more than 2 mails
668 if (sentSenders.size() > 2)
669 break;
670 }
671 }
672 else
673 result.NextMailTime = -DAY;
674
675 SendPacket(result.Write());
676}
#define sCharacterCache
@ CHAR_DEL_MAIL_BY_ID
@ CHAR_DEL_MAIL_ITEM_BY_ID
@ CHAR_SEL_MAIL_COUNT
@ DAY
Definition: Common.h:31
DB2Storage< MailTemplateEntry > sMailTemplateStore("MailTemplate.db2", &MailTemplateLoadInfo::Instance)
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
uint64_t uint64
Definition: Define.h:141
#define SI64FMTD
Definition: Define.h:129
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define sGuildMgr
Definition: GuildMgr.h:70
@ EQUIP_ERR_TOO_MUCH_GOLD
Definition: ItemDefines.h:104
@ EQUIP_ERR_MAIL_BOUND_ITEM
Definition: ItemDefines.h:99
@ EQUIP_ERR_DESTROY_NONEMPTY_BAG
Definition: ItemDefines.h:58
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
@ EQUIP_ERR_NOT_SAME_ACCOUNT
Definition: ItemDefines.h:109
@ ITEM_FIELD_FLAG_READABLE
Definition: ItemTemplate.h:140
@ ITEM_FLAG_IS_BOUND_TO_ACCOUNT
Definition: ItemTemplate.h:203
@ ITEM_FLAG_CONJURED
Definition: ItemTemplate.h:177
@ ITEM_CHANGED
Definition: Item.h:55
@ ITEM_UNCHANGED
Definition: Item.h:54
@ LANG_UNKNOWN
Definition: Language.h:77
@ LANG_MAIL_RECEIVER_REQ
Definition: Language.h:1166
@ LANG_MAIL_SENDER_REQ
Definition: Language.h:1165
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define sLog
Definition: Log.h:130
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ MAIL_CHECK_MASK_HAS_BODY
Definition: Mail.h:57
@ MAIL_CHECK_MASK_READ
Definition: Mail.h:53
@ MAIL_CHECK_MASK_COD_PAYMENT
This mail was copied. Do not allow making a copy of items in mail.
Definition: Mail.h:56
@ MAIL_CHECK_MASK_COPIED
This mail was returned. Do not allow returning mail back again.
Definition: Mail.h:55
@ MAIL_STATE_DELETED
Definition: Mail.h:76
@ MAIL_STATE_CHANGED
Definition: Mail.h:75
#define MAIL_BODY_ITEM_TEMPLATE
Definition: Mail.h:33
#define MAX_CLIENT_MAIL_ITEMS
Definition: Mail.h:34
@ MAIL_NORMAL
Definition: Mail.h:39
bool normalizePlayerName(std::string &name)
Definition: ObjectMgr.cpp:154
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ GAMEOBJECT_TYPE_MAILBOX
@ MAIL_MONEY_TAKEN
@ MAIL_DELETED
@ MAIL_RETURNED_TO_SENDER
@ MAIL_MADE_PERMANENT
@ MAIL_ITEM_TAKEN
@ MAIL_SEND
@ MAIL_ERR_NOT_ENOUGH_MONEY
@ MAIL_ERR_NOT_YOUR_TEAM
@ MAIL_ERR_CANT_SEND_WRAPPED_COD
@ MAIL_ERR_RECIPIENT_CAP_REACHED
@ MAIL_ERR_EQUIP_ERROR
@ MAIL_ERR_RECIPIENT_NOT_FOUND
@ MAIL_OK
@ MAIL_ERR_TOO_MANY_ATTACHMENTS
@ MAIL_ERR_MAIL_ATTACHMENT_INVALID
@ MAIL_ERR_INTERNAL_ERROR
@ MAIL_ERR_CANNOT_SEND_TO_SELF
Team
@ UNIT_NPC_FLAG_MAILBOX
Definition: UnitDefines.h:323
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
Definition: Guild.h:329
Definition: Item.h:170
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition: Item.cpp:1166
void SetItemFlag(ItemFieldFlags flags)
Definition: Item.h:209
bool IsWrapped() const
Definition: Item.h:250
void SetText(std::string const &text)
Definition: Item.h:305
bool IsBoundAccountWide() const
Definition: Item.h:219
bool CanBeTraded(bool mail=false, bool trade=false) const
Definition: Item.cpp:1250
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1141
bool IsSoulBound() const
Definition: Item.h:218
bool IsBattlenetAccountBound() const
Definition: Item.h:220
void SetCreator(ObjectGuid guid)
Definition: Item.h:193
bool IsNotEmptyBag() const
Definition: Item.cpp:535
uint32 GetCount() const
Definition: Item.h:273
UF::UpdateField< UF::ItemData, 0, TYPEID_ITEM > m_itemData
Definition: Item.h:449
static Item * CreateItem(uint32 itemEntry, uint32 count, ItemContext context, Player const *player=nullptr, bool addDefaultBonuses=true)
Definition: Item.cpp:1625
void SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const &receiver, MailSender const &sender, MailCheckMask checked=MAIL_CHECK_MASK_NONE, uint32 deliver_delay=0)
Definition: Mail.cpp:192
MailDraft & AddCOD(uint64 COD)
Definition: Mail.h:146
void SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, CharacterDatabaseTransaction trans)
Definition: Mail.cpp:149
MailDraft & AddItem(Item *item)
Definition: Mail.cpp:99
MailDraft & AddMoney(uint64 money)
Definition: Mail.h:145
LowType GetCounter() const
Definition: ObjectGuid.h:293
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
bool IsGameObject() const
Definition: ObjectGuid.h:329
bool IsAnyTypeCreature() const
Definition: ObjectGuid.h:325
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void UpdateNextMailTimeAndUnreads()
Definition: Player.cpp:2648
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
Item * GetMItem(ObjectGuid::LowType id)
Definition: Player.cpp:21856
void SendMailResult(uint64 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError=0, ObjectGuid::LowType itemGuid=UI64LIT(0), uint32 itemCount=0) const
Definition: Player.cpp:2621
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition: Player.cpp:10037
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20364
GameObject * GetGameObjectIfCanInteractWith(ObjectGuid const &guid) const
Definition: Player.cpp:2004
uint8 unReadMails
Definition: Player.h:1775
bool m_mailsUpdated
Definition: Player.h:1727
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition: Player.cpp:11612
WorldSession * GetSession() const
Definition: Player.h:2101
PlayerMails const & GetMails() const
Definition: Player.h:1767
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12134
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Definition: Player.cpp:12152
void _SaveMail(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20742
ObjectGuid::LowType GetGuildId() const
Definition: Player.h:1993
bool RemoveMItem(ObjectGuid::LowType id)
Definition: Player.cpp:21869
bool IsGameMaster() const
Definition: Player.h:1178
Mail * GetMail(uint64 id)
Definition: Player.cpp:3605
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
void RemoveMail(uint64 id)
Definition: Player.cpp:2608
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition: Player.h:2380
Team GetTeam() const
Definition: Player.h:2235
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void setUInt64(const uint8 index, const uint64 value)
uint8 GetLevel() const
Definition: Unit.h:746
std::string const & GetName() const
Definition: Object.h:555
WorldPacket const * Write() override
std::vector< MailListEntry > Mails
Definition: MailPackets.h:85
WorldPacket const * Write() override
std::vector< MailNextTimeEntry > Next
Definition: MailPackets.h:226
char const * GetTrinityString(uint32 entry) const
void SendNotification(char const *format,...) ATTR_PRINTF(2
LocaleConstant GetSessionDbcLocale() const
std::string GetPlayerInfo() const
void HandleSendMail(WorldPackets::Mail::SendMail &sendMail)
Definition: MailHandler.cpp:64
Player * GetPlayer() const
bool CanOpenMailBox(ObjectGuid guid)
Definition: MailHandler.cpp:38
void HandleMailDelete(WorldPackets::Mail::MailDelete &mailDelete)
QueryCallbackProcessor & GetQueryProcessor()
void HandleMailTakeItem(WorldPackets::Mail::MailTakeItem &takeItem)
void HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime &queryNextMailTime)
void HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead &markAsRead)
bool HasPermission(uint32 permissionId)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetBattlenetAccountId() const
void HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender &returnToSender)
uint32 GetAccountId() const
Player * _player
void HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem &createTextItem)
void HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney &takeMoney)
void HandleGetMailList(WorldPackets::Mail::MailGetList &getList)
std::string const & GetPlayerName() const
bool ValidateHyperlinksAndMaybeKick(std::string const &str)
#define sWorld
Definition: World.h:931
@ CONFIG_MAIL_LEVEL_REQ
Definition: World.h:329
@ CONFIG_MAIL_DELIVERY_DELAY
Definition: World.h:296
TC_GAME_API QueryCallback GetIdByGameAccountAsync(uint32 gameAccountId)
time_t GetGameTime()
Definition: GameTime.cpp:44
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
@ RBAC_PERM_TWO_SIDE_INTERACTION_MAIL
Definition: RBAC.h:80
@ RBAC_PERM_COMMAND_MAILBOX
Definition: RBAC.h:649
@ RBAC_PERM_LOG_GM_TRADE
Definition: RBAC.h:64
bool HasFlag(ItemFlags flag) const
Definition: ItemTemplate.h:871
char const * GetDefaultLocaleName() const
LocalizedString Body
Definition: Mail.h:175
bool HasItems() const
Definition: Mail.h:214
ObjectGuid::LowType receiver
Definition: Mail.h:181
uint8 messageType
Definition: Mail.h:177
uint64 money
Definition: Mail.h:188
uint64 COD
Definition: Mail.h:189
ObjectGuid::LowType sender
Definition: Mail.h:180
std::string subject
Definition: Mail.h:182
std::vector< ObjectGuid::LowType > removedItems
Definition: Mail.h:185
std::string body
Definition: Mail.h:183
std::vector< MailItemInfo > items
Definition: Mail.h:184
bool RemoveItem(ObjectGuid::LowType item_guid)
Definition: Mail.h:201
time_t deliver_time
Definition: Mail.h:187
uint32 checked
Definition: Mail.h:190
MailState state
Definition: Mail.h:191
uint16 mailTemplateId
Definition: Mail.h:179
std::vector< MailAttachment > Attachments
Definition: MailPackets.h:117