/** * Handles the packet sent by the client when requesting the current mail list. * It will send a list of all available mails in the players mailbox to the client. */ void WorldSession::HandleGetMailList(WorldPacket & recv_data ) { ObjectGuid mailboxGuid; recv_data >> mailboxGuid; if (!CheckMailBox(mailboxGuid)) return; // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailsCount = 0; // 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); for(PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) { // packet send mail count as uint8, prevent overflow if(mailsCount >= 254) { realCount += 1; continue; } // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->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+4+4+7*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(HIGHGUID_PLAYER, (*itr)->sender); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << uint32((*itr)->sender); // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI data << uint32(0); // item entry break; } data << uint32((*itr)->COD); // COD data << uint32(0); // unknown, probably changed in 3.3.3 data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint32((*itr)->money); // copper data << uint32((*itr)->checked); // flags data << float(float((*itr)->expire_time - time(NULL)) / float(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 << uint32(item ? item->GetGUIDLow() : 0); // entry data << uint32(item ? item->GetEntry() : 0); for(uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) { // unsure data << uint32(item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0); // unsure data << uint32(item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0); // unsure data << uint32(item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0); } // can be negative data << uint32(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); } mailsCount += 1; realCount += 1; } 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); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
/** * Handles the packet sent by the client when requesting the current mail list. * It will send a list of all available mails in the players mailbox to the client. */ void WorldSession::HandleGetMail(WorldPacket & recv_data) { uint64 mailbox; recv_data >> mailbox; if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* pl = _player; //load players mails, and mailed items if (!pl->m_mailsLoaded) pl ->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailsCount = 0; // real send to client mails amount WorldPacket data(SMSG_MAIL_LIST_RESULT, (200)); // guess size data << uint8(0); // mail's count time_t cur_time = time(NULL); for (PlayerMails::iterator itr = pl->GetmailBegin(); itr != pl->GetmailEnd(); ++itr) { // packet send mail count as uint8, prevent overflow if (mailsCount >= 254) break; // skip deleted or not delivered (deliver delay not expired) mails if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) continue; uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) size_t next_mail_size = 2+4+1+8+4*8+((*itr)->subject.size()+1)+1+item_count*(1+4+4+6*3*4+4+4+1+4+4+4); if (data.wpos()+next_mail_size > maxPacketSize) break; 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 << uint64(MAKE_NEW_GUID((*itr)->sender, 0, HIGHGUID_PLAYER)); break; case MAIL_CREATURE: case MAIL_GAMEOBJECT: case MAIL_AUCTION: data << (uint32) (*itr)->sender; // creature/gameobject entry, auction id break; case MAIL_ITEM: // item entry (?) sender = "Unknown", NYI break; } data << uint32((*itr)->COD); // COD data << uint32((*itr)->itemTextId); // item text data << uint32(0); // unknown data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint32((*itr)->money); // copper data << uint32((*itr)->checked); // flags data << 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 << (uint8) item_count; for (uint8 i = 0; i < item_count; ++i) { Item *item = pl->GetMItem((*itr)->items[i].item_guid); // item index (0-6?) data << (uint8) i; // item guid low? data << (uint32) (item ? item->GetGUIDLow() : 0); // entry data << (uint32) (item ? item->GetEntry() : 0); for (uint8 j = 0; j < 6; ++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 << (uint32) (item ? item->GetItemRandomPropertyId() : 0); // unk data << (uint32) (item ? item->GetItemSuffixFactor() : 0); // stack count data << (uint8) (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); } mailsCount += 1; } data.put<uint8>(0, mailsCount); // set real send mails to client SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }
//called when player lists his received mails void WorldSession::HandleGetMailList(WorldPacket& recvData) { ObjectGuid mailbox; mailbox[6] = recvData.ReadBit(); mailbox[3] = recvData.ReadBit(); mailbox[7] = recvData.ReadBit(); mailbox[5] = recvData.ReadBit(); mailbox[4] = recvData.ReadBit(); mailbox[1] = recvData.ReadBit(); mailbox[2] = recvData.ReadBit(); mailbox[0] = recvData.ReadBit(); recvData.ReadByteSeq(mailbox[7]); recvData.ReadByteSeq(mailbox[1]); recvData.ReadByteSeq(mailbox[6]); recvData.ReadByteSeq(mailbox[5]); recvData.ReadByteSeq(mailbox[4]); recvData.ReadByteSeq(mailbox[2]); recvData.ReadByteSeq(mailbox[3]); recvData.ReadByteSeq(mailbox[0]); if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; Player* player = _player; //load players mails, and mailed items if (!player->m_mailsLoaded) player->_LoadMail(); // client can't work with packets > max int16 value const uint32 maxPacketSize = 32767; uint32 mailCount = 0; uint32 realCount = 0; // true mail count (includes any skipped mail) time_t cur_time = time(NULL); ByteBuffer mailData; WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size data << uint32(0); // placeholder size_t mailCountPos = data.bitwpos(); data.WriteBits(0, 18); // placeholder for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) { Mail* mail = *itr; // Only first 50 mails are displayed if (mailCount >= 50) { realCount += 1; continue; } // skip deleted or not delivered (deliver delay not expired) mails if (mail->state == MAIL_STATE_DELETED || cur_time < mail->deliver_time) continue; // skip mail with more than MAX_MAIL_ITEMS items (should not occur) uint8 itemCount = mail->items.size(); if (itemCount > MAX_MAIL_ITEMS) { realCount += 1; continue; } // skip mail if the packet has become too large (should not occur) size_t nextMailSize = 6 + 1 + 8 + itemCount * (4 + 4 + 4 + 4 + 4 + MAX_INSPECTED_ENCHANTMENT_SLOT * (4 + 4 + 4) + 4 + 4 + 4 + 4 + 1 + 4) + mail->body.size() + mail->subject.size() + 4 + 4 + 8 + 4 + 8 + 4 + 4 + 1 + 4; if (data.wpos() + nextMailSize > maxPacketSize) { realCount += 1; continue; } data.WriteBit(mail->messageType != MAIL_NORMAL ? 1 : 0); data.WriteBits(mail->subject.size(), 8); data.WriteBits(mail->body.size(), 13); data.WriteBit(0); data.WriteBit(0); size_t itemCountPos = data.bitwpos(); data.WriteBits(0, 17); // placeholder data.WriteBit(1); // has guid ObjectGuid guid = mail->messageType == MAIL_NORMAL ? MAKE_NEW_GUID(mail->sender, 0, HIGHGUID_PLAYER) : 0; data.WriteBit(guid[2]); data.WriteBit(guid[6]); data.WriteBit(guid[7]); data.WriteBit(guid[0]); data.WriteBit(guid[5]); data.WriteBit(guid[3]); data.WriteBit(guid[1]); data.WriteBit(guid[4]); uint8 trueItemCount = 0; for (uint8 i = 0; i < itemCount; i++) { Item* item = player->GetMItem(mail->items[i].item_guid); if (!item) continue; data.WriteBit(0); mailData << uint32(item->GetGUIDLow()); mailData << uint32(4); // unknown mailData << uint32(item->GetSpellCharges()); mailData << uint32(item->GetUInt32Value(ITEM_FIELD_DURABILITY)); mailData << uint32(0); // unknown for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; j++) { mailData << uint32(item->GetEnchantmentCharges((EnchantmentSlot)j)); mailData << uint32(item->GetEnchantmentDuration((EnchantmentSlot)j)); mailData << uint32(item->GetEnchantmentId((EnchantmentSlot)j)); } mailData << uint32(item->GetItemSuffixFactor()); mailData << int32(item->GetItemRandomPropertyId()); mailData << uint32(item->GetUInt32Value(ITEM_FIELD_MAX_DURABILITY)); mailData << uint32(item->GetCount()); mailData << uint8(i); mailData << uint32(item->GetEntry()); trueItemCount++; } data.PutBits(itemCountPos, trueItemCount, 17); mailData.WriteString(mail->body); mailData << uint32(mail->messageID); mailData.WriteByteSeq(guid[4]); mailData.WriteByteSeq(guid[0]); mailData.WriteByteSeq(guid[5]); mailData.WriteByteSeq(guid[3]); mailData.WriteByteSeq(guid[1]); mailData.WriteByteSeq(guid[7]); mailData.WriteByteSeq(guid[2]); mailData.WriteByteSeq(guid[6]); mailData << uint32(mail->mailTemplateId); mailData << uint64(mail->COD); mailData.WriteString(mail->subject); mailData << uint32(mail->stationery); mailData << float(float(mail->expire_time - time(NULL)) / DAY); mailData << uint64(mail->money); mailData << uint32(mail->checked); if (mail->messageType != MAIL_NORMAL) mailData << uint32(mail->sender); mailData << uint8(mail->messageType); mailData << uint32(0); // unknown realCount++; mailCount++; } data.FlushBits(); data.append(mailData); data.put<uint32>(0, realCount); data.PutBits(mailCountPos, mailCount, 18); SendPacket(&data); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); }