| 1 | /* |
|---|
| 2 | * ArcEmu MMORPG Server |
|---|
| 3 | * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/> |
|---|
| 4 | * Copyright (C) 2008-2010 <http://www.ArcEmu.org/> |
|---|
| 5 | * |
|---|
| 6 | * This program is free software: you can redistribute it and/or modify |
|---|
| 7 | * it under the terms of the GNU Affero General Public License as published by |
|---|
| 8 | * the Free Software Foundation, either version 3 of the License, or |
|---|
| 9 | * any later version. |
|---|
| 10 | * |
|---|
| 11 | * This program is distributed in the hope that it will be useful, |
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | * GNU Affero General Public License for more details. |
|---|
| 15 | * |
|---|
| 16 | * You should have received a copy of the GNU Affero General Public License |
|---|
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 18 | * |
|---|
| 19 | */ |
|---|
| 20 | |
|---|
| 21 | #include "StdAfx.h" |
|---|
| 22 | initialiseSingleton(MailSystem); |
|---|
| 23 | |
|---|
| 24 | void MailSystem::StartMailSystem() |
|---|
| 25 | { |
|---|
| 26 | |
|---|
| 27 | } |
|---|
| 28 | |
|---|
| 29 | MailError MailSystem::DeliverMessage(uint64 recipent, MailMessage* message) |
|---|
| 30 | { |
|---|
| 31 | // assign a new id |
|---|
| 32 | message->message_id = Generate_Message_Id(); |
|---|
| 33 | |
|---|
| 34 | Player * plr = objmgr.GetPlayer((uint32)recipent); |
|---|
| 35 | if(plr != NULL) |
|---|
| 36 | { |
|---|
| 37 | plr->m_mailBox.AddMessage(message); |
|---|
| 38 | if((uint32)UNIXTIME >= message->delivery_time) |
|---|
| 39 | { |
|---|
| 40 | uint32 v = 0; |
|---|
| 41 | plr->GetSession()->OutPacket(SMSG_RECEIVED_MAIL, 4, &v); |
|---|
| 42 | } |
|---|
| 43 | } |
|---|
| 44 | |
|---|
| 45 | SaveMessageToSQL(message); |
|---|
| 46 | return MAIL_OK; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | void Mailbox::AddMessage(MailMessage* Message) |
|---|
| 50 | { |
|---|
| 51 | Messages[Message->message_id] = *Message; |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | void Mailbox::DeleteMessage(uint32 MessageId, bool sql) |
|---|
| 55 | { |
|---|
| 56 | Messages.erase(MessageId); |
|---|
| 57 | if(sql) |
|---|
| 58 | CharacterDatabase.WaitExecute("DELETE FROM mailbox WHERE message_id = %u", MessageId); |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | WorldPacket * Mailbox::BuildMailboxListingPacket() |
|---|
| 62 | { |
|---|
| 63 | WorldPacket * data = new WorldPacket(SMSG_MAIL_LIST_RESULT, 500); |
|---|
| 64 | MessageMap::iterator itr; |
|---|
| 65 | uint32 realcount = 0; |
|---|
| 66 | uint32 count = 0; |
|---|
| 67 | uint32 t = (uint32)UNIXTIME; |
|---|
| 68 | *data << uint32(0); // realcount - this can be used to tell the client we have more mail than that fits into this packet |
|---|
| 69 | *data << uint8(0); // size placeholder |
|---|
| 70 | |
|---|
| 71 | for(itr = Messages.begin(); itr != Messages.end(); ++itr) |
|---|
| 72 | { |
|---|
| 73 | if(itr->second.expire_time && t > itr->second.expire_time) |
|---|
| 74 | continue; // expired mail -> skip it |
|---|
| 75 | |
|---|
| 76 | if((uint32)UNIXTIME < itr->second.delivery_time) |
|---|
| 77 | continue; // undelivered |
|---|
| 78 | |
|---|
| 79 | if(count >= 50) //VLack: We could calculate message sizes instead of this, but the original code did a break at 50, so I won't fix this up if no one felt the need to do so before ;-) |
|---|
| 80 | { |
|---|
| 81 | ++realcount; |
|---|
| 82 | continue; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | if(itr->second.AddMessageDataToPacket(*data)) |
|---|
| 86 | { |
|---|
| 87 | ++count; |
|---|
| 88 | ++realcount; |
|---|
| 89 | } |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | data->put<uint32>(0, realcount); |
|---|
| 93 | data->put<uint8>(4, static_cast< uint8 >( count )); |
|---|
| 94 | |
|---|
| 95 | // do cleanup on request mail |
|---|
| 96 | CleanupExpiredMessages(); |
|---|
| 97 | return data; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | void Mailbox::CleanupExpiredMessages() |
|---|
| 101 | { |
|---|
| 102 | MessageMap::iterator itr, it2; |
|---|
| 103 | uint32 curtime = (uint32)UNIXTIME; |
|---|
| 104 | |
|---|
| 105 | for(itr = Messages.begin(); itr != Messages.end();) |
|---|
| 106 | { |
|---|
| 107 | it2 = itr++; |
|---|
| 108 | if(it2->second.expire_time && it2->second.expire_time < curtime) |
|---|
| 109 | { |
|---|
| 110 | Messages.erase(it2); |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | bool MailMessage::AddMessageDataToPacket(WorldPacket& data) |
|---|
| 116 | { |
|---|
| 117 | uint8 i = 0; |
|---|
| 118 | uint32 j; |
|---|
| 119 | size_t pos; |
|---|
| 120 | vector<uint64>::iterator itr; |
|---|
| 121 | Item * pItem; |
|---|
| 122 | |
|---|
| 123 | // add stuff |
|---|
| 124 | if(deleted_flag) |
|---|
| 125 | return false; |
|---|
| 126 | |
|---|
| 127 | data << uint16(0x0032); |
|---|
| 128 | data << message_id; |
|---|
| 129 | data << uint8(message_type); |
|---|
| 130 | if(message_type) |
|---|
| 131 | data << uint32(sender_guid); |
|---|
| 132 | else |
|---|
| 133 | data << sender_guid; |
|---|
| 134 | |
|---|
| 135 | data << cod; // cod |
|---|
| 136 | data << message_id; // itempageid |
|---|
| 137 | data << uint32(0); |
|---|
| 138 | data << stationery; |
|---|
| 139 | data << money; // money |
|---|
| 140 | data << uint32(0x10); |
|---|
| 141 | data << float(float(expire_time - (uint32)UNIXTIME) / 86400.0f); |
|---|
| 142 | data << uint32(0); // mail template |
|---|
| 143 | data << subject; |
|---|
| 144 | pos = data.wpos(); |
|---|
| 145 | data << uint8(items.size()); // item count |
|---|
| 146 | |
|---|
| 147 | if( !items.empty( ) ) |
|---|
| 148 | { |
|---|
| 149 | for( itr = items.begin( ); itr != items.end( ); ++itr ) |
|---|
| 150 | { |
|---|
| 151 | pItem = objmgr.LoadItem( *itr ); |
|---|
| 152 | if( pItem == NULL ) |
|---|
| 153 | continue; |
|---|
| 154 | |
|---|
| 155 | data << uint8(i++); |
|---|
| 156 | data << pItem->GetLowGUID(); |
|---|
| 157 | data << pItem->GetEntry(); |
|---|
| 158 | |
|---|
| 159 | for( j = 0; j < 6; ++j ) |
|---|
| 160 | { |
|---|
| 161 | /* Don't remove this please - dfighter |
|---|
| 162 | data << pItem->GetUInt32Value( ITEM_FIELD_ENCHANTMENT_1_1 + ( j * 3 ) ); |
|---|
| 163 | data << pItem->GetUInt32Value( ITEM_FIELD_ENCHANTMENT_2_1 + ( j * 3 ) ); |
|---|
| 164 | data << pItem->GetUInt32Value( ITEM_FIELD_ENCHANTMENT_3_1 + ( j * 3 ) ); |
|---|
| 165 | */ |
|---|
| 166 | |
|---|
| 167 | data << uint32( pItem->GetEnchantmentId( j ) ); |
|---|
| 168 | data << uint32( pItem->GetEnchantmentId( j + 1 * 3 ) ); |
|---|
| 169 | data << uint32( pItem->GetEnchantmentId( j + 2 * 3 ) ); |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | data << uint32( pItem->GetItemRandomPropertyId() ); |
|---|
| 173 | if( ( (int32)pItem->GetItemRandomPropertyId() ) < 0 ) |
|---|
| 174 | data << uint32( pItem->GetItemRandomSuffixFactor() ); |
|---|
| 175 | else |
|---|
| 176 | data << uint32( 0 ); |
|---|
| 177 | |
|---|
| 178 | data << uint8( pItem->GetStackCount() ); |
|---|
| 179 | data << uint32( pItem->GetChargesLeft() ); |
|---|
| 180 | data << uint32( pItem->GetDurabilityMax() ); |
|---|
| 181 | data << uint32( pItem->GetDurability() ); |
|---|
| 182 | data << uint32( 0 ); |
|---|
| 183 | data << uint32( 0 ); |
|---|
| 184 | data << uint32( 0 ); |
|---|
| 185 | data << uint32( 0 ); |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | data.put< uint8 >( pos, i ); |
|---|
| 189 | } |
|---|
| 190 | |
|---|
| 191 | return true; |
|---|
| 192 | |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | void MailSystem::SaveMessageToSQL(MailMessage * message) |
|---|
| 196 | { |
|---|
| 197 | stringstream ss; |
|---|
| 198 | |
|---|
| 199 | |
|---|
| 200 | ss << "DELETE FROM mailbox WHERE message_id = "; |
|---|
| 201 | ss << message->message_id; |
|---|
| 202 | ss << ";"; |
|---|
| 203 | |
|---|
| 204 | CharacterDatabase.ExecuteNA( ss.str().c_str() ); |
|---|
| 205 | |
|---|
| 206 | ss.rdbuf()->str(""); |
|---|
| 207 | |
|---|
| 208 | vector< uint64 >::iterator itr; |
|---|
| 209 | ss << "INSERT INTO mailbox VALUES(" |
|---|
| 210 | << message->message_id << "," |
|---|
| 211 | << message->message_type << "," |
|---|
| 212 | << message->player_guid << "," |
|---|
| 213 | << message->sender_guid << ",\'" |
|---|
| 214 | << CharacterDatabase.EscapeString(message->subject) << "\',\'" |
|---|
| 215 | << CharacterDatabase.EscapeString(message->body) << "\'," |
|---|
| 216 | << message->money << ",'"; |
|---|
| 217 | |
|---|
| 218 | for( itr = message->items.begin( ); itr != message->items.end( ); ++itr ) |
|---|
| 219 | ss << (*itr) << ","; |
|---|
| 220 | |
|---|
| 221 | ss << "'," |
|---|
| 222 | << message->cod << "," |
|---|
| 223 | << message->stationery << "," |
|---|
| 224 | << message->expire_time << "," |
|---|
| 225 | << message->delivery_time << "," |
|---|
| 226 | << message->copy_made << "," |
|---|
| 227 | << message->read_flag << "," |
|---|
| 228 | << message->deleted_flag << ");"; |
|---|
| 229 | |
|---|
| 230 | CharacterDatabase.Execute(ss.str().c_str()); |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | void WorldSession::HandleSendMail(WorldPacket & recv_data ) |
|---|
| 234 | { |
|---|
| 235 | MailMessage msg; |
|---|
| 236 | uint64 gameobject; |
|---|
| 237 | uint32 unk2; |
|---|
| 238 | uint8 itemcount; |
|---|
| 239 | uint8 itemslot; |
|---|
| 240 | uint8 i; |
|---|
| 241 | uint64 itemguid; |
|---|
| 242 | vector< Item* > items; |
|---|
| 243 | vector< Item* >::iterator itr; |
|---|
| 244 | string recepient; |
|---|
| 245 | Item * pItem; |
|---|
| 246 | //uint32 err = MAIL_OK; |
|---|
| 247 | |
|---|
| 248 | recv_data >> gameobject >> recepient; |
|---|
| 249 | recv_data >> msg.subject >> msg.body >> msg.stationery; |
|---|
| 250 | recv_data >> unk2 >> itemcount; |
|---|
| 251 | |
|---|
| 252 | if( itemcount > 12 || msg.body.find("%") != string::npos || msg.subject.find("%") != string::npos) |
|---|
| 253 | { |
|---|
| 254 | //SystemMessage("Sorry, Ascent does not support sending multiple items at this time. (don't want to lose your item do you) Remove some items, and try again."); |
|---|
| 255 | SendMailError(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 256 | return; |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | // Search for the recipient |
|---|
| 260 | PlayerInfo* player = ObjectMgr::getSingleton().GetPlayerInfoByName(recepient.c_str()); |
|---|
| 261 | if( player == NULL ) |
|---|
| 262 | { |
|---|
| 263 | SendMailError( MAIL_ERR_RECIPIENT_NOT_FOUND ); |
|---|
| 264 | return; |
|---|
| 265 | } |
|---|
| 266 | |
|---|
| 267 | for( i = 0; i < itemcount; ++i ) |
|---|
| 268 | { |
|---|
| 269 | recv_data >> itemslot; |
|---|
| 270 | recv_data >> itemguid; |
|---|
| 271 | |
|---|
| 272 | pItem = _player->GetItemInterface()->GetItemByGUID( itemguid ); |
|---|
| 273 | if( pItem == NULL || pItem->IsSoulbound() || pItem->IsConjured() ) |
|---|
| 274 | { |
|---|
| 275 | SendMailError( MAIL_ERR_INTERNAL_ERROR ); |
|---|
| 276 | return; |
|---|
| 277 | } |
|---|
| 278 | if(pItem->IsAccountbound() && GetAccountId() != player->acct) // don't mail account-bound items to another account |
|---|
| 279 | { |
|---|
| 280 | SendMailError( MAIL_ERR_INTERNAL_ERROR ); |
|---|
| 281 | return; |
|---|
| 282 | } |
|---|
| 283 | |
|---|
| 284 | items.push_back( pItem ); |
|---|
| 285 | } |
|---|
| 286 | |
|---|
| 287 | recv_data >> msg.money; |
|---|
| 288 | recv_data >> msg.cod; |
|---|
| 289 | // left over: (TODO- FIX ME BURLEX!) |
|---|
| 290 | // uint32 |
|---|
| 291 | // uint32 |
|---|
| 292 | // uint8 |
|---|
| 293 | |
|---|
| 294 | bool interfaction = false; |
|---|
| 295 | if( sMailSystem.MailOption( MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION ) || (HasGMPermissions() && sMailSystem.MailOption( MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM ) ) ) |
|---|
| 296 | { |
|---|
| 297 | interfaction = true; |
|---|
| 298 | } |
|---|
| 299 | |
|---|
| 300 | // Check we're sending to the same faction (disable this for testing) |
|---|
| 301 | if( player->team != _player->GetTeam() && !interfaction ) |
|---|
| 302 | { |
|---|
| 303 | SendMailError( MAIL_ERR_NOT_YOUR_ALLIANCE ); |
|---|
| 304 | return; |
|---|
| 305 | } |
|---|
| 306 | |
|---|
| 307 | // Check if we're sending mail to ourselves |
|---|
| 308 | if( strcmp(player->name, _player->GetName()) == 0 && !GetPermissionCount()) |
|---|
| 309 | { |
|---|
| 310 | SendMailError(MAIL_ERR_CANNOT_SEND_TO_SELF); |
|---|
| 311 | return; |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | if( msg.stationery == MAIL_STATIONERY_GM && !HasGMPermissions()) |
|---|
| 315 | { |
|---|
| 316 | SendMailError(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 317 | return; |
|---|
| 318 | } |
|---|
| 319 | |
|---|
| 320 | // Instant delivery time by default. |
|---|
| 321 | msg.delivery_time = (uint32)UNIXTIME; |
|---|
| 322 | |
|---|
| 323 | // Set up the cost |
|---|
| 324 | int32 cost = 0; |
|---|
| 325 | |
|---|
| 326 | // Check for attached money |
|---|
| 327 | if( msg.money > 0 ) |
|---|
| 328 | cost += msg.money; |
|---|
| 329 | |
|---|
| 330 | if( cost < 0 ) |
|---|
| 331 | { |
|---|
| 332 | SendMailError(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 333 | return; |
|---|
| 334 | } |
|---|
| 335 | |
|---|
| 336 | if( !sMailSystem.MailOption( MAIL_FLAG_DISABLE_POSTAGE_COSTS ) && !( GetPermissionCount() && sMailSystem.MailOption( MAIL_FLAG_NO_COST_FOR_GM ) ) ) |
|---|
| 337 | { |
|---|
| 338 | cost += 30; |
|---|
| 339 | if( cost < 30 )//Overflow prevention for those silly WPE hoez. |
|---|
| 340 | { |
|---|
| 341 | SendMailError(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 342 | return; |
|---|
| 343 | } |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | // check that we have enough in our backpack |
|---|
| 347 | if( !_player->HasGold(cost) ) |
|---|
| 348 | { |
|---|
| 349 | SendMailError( MAIL_ERR_NOT_ENOUGH_MONEY ); |
|---|
| 350 | return; |
|---|
| 351 | } |
|---|
| 352 | |
|---|
| 353 | // Check for the item, and required item. |
|---|
| 354 | if( !items.empty( ) ) |
|---|
| 355 | { |
|---|
| 356 | for( itr = items.begin(); itr != items.end(); ++itr ) |
|---|
| 357 | { |
|---|
| 358 | pItem = *itr; |
|---|
| 359 | if( _player->GetItemInterface()->SafeRemoveAndRetreiveItemByGuid(pItem->GetGUID(), false) != pItem ) |
|---|
| 360 | continue; // should never be hit. |
|---|
| 361 | |
|---|
| 362 | pItem->RemoveFromWorld(); |
|---|
| 363 | pItem->SetOwner( NULL ); |
|---|
| 364 | pItem->SaveToDB( INVENTORY_SLOT_NOT_SET, 0, true, NULL ); |
|---|
| 365 | msg.items.push_back( pItem->GetLowGUID() ); |
|---|
| 366 | |
|---|
| 367 | if( GetPermissionCount() > 0 ) |
|---|
| 368 | { |
|---|
| 369 | /* log the message */ |
|---|
| 370 | sGMLog.writefromsession(this, "sent mail with item entry %u to %s, with gold %u.", pItem->GetEntry(), player->name, msg.money); |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | pItem->DeleteMe(); |
|---|
| 374 | } |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | if(msg.money != 0 || msg.cod != 0 || ( !msg.items.size() && player->acct != _player->GetSession()->GetAccountId()) ) |
|---|
| 378 | { |
|---|
| 379 | if(!sMailSystem.MailOption(MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS)) |
|---|
| 380 | msg.delivery_time += 3600; // 1hr |
|---|
| 381 | } |
|---|
| 382 | |
|---|
| 383 | // take the money |
|---|
| 384 | _player->ModGold( -cost ); |
|---|
| 385 | |
|---|
| 386 | // Fill in the rest of the info |
|---|
| 387 | msg.player_guid = player->guid; |
|---|
| 388 | msg.sender_guid = _player->GetGUID(); |
|---|
| 389 | |
|---|
| 390 | // 30 day expiry time for unread mail |
|---|
| 391 | if(!sMailSystem.MailOption(MAIL_FLAG_NO_EXPIRY)) |
|---|
| 392 | msg.expire_time = (uint32)UNIXTIME + (TIME_DAY * MAIL_DEFAULT_EXPIRATION_TIME); |
|---|
| 393 | else |
|---|
| 394 | msg.expire_time = 0; |
|---|
| 395 | |
|---|
| 396 | msg.copy_made = false; |
|---|
| 397 | msg.read_flag = false; |
|---|
| 398 | msg.deleted_flag = false; |
|---|
| 399 | msg.message_type = 0; |
|---|
| 400 | |
|---|
| 401 | // Great, all our info is filled in. Now we can add it to the other players mailbox. |
|---|
| 402 | sMailSystem.DeliverMessage(player->guid, &msg); |
|---|
| 403 | // Save/Update character's gold if they've received gold that is. This prevents a rollback. |
|---|
| 404 | CharacterDatabase.Execute("UPDATE characters SET gold = %u WHERE guid = %u", _player->GetGold(), _player->m_playerInfo->guid); |
|---|
| 405 | // Success packet :) |
|---|
| 406 | SendMailError(MAIL_OK); |
|---|
| 407 | } |
|---|
| 408 | |
|---|
| 409 | void WorldSession::HandleMarkAsRead(WorldPacket & recv_data ) |
|---|
| 410 | { |
|---|
| 411 | uint64 mailbox; |
|---|
| 412 | uint32 message_id; |
|---|
| 413 | recv_data >> mailbox >> message_id; |
|---|
| 414 | |
|---|
| 415 | MailMessage * message = _player->m_mailBox.GetMessage(message_id); |
|---|
| 416 | if(message == 0) return; |
|---|
| 417 | |
|---|
| 418 | // mark the message as read |
|---|
| 419 | message->read_flag = 1; |
|---|
| 420 | |
|---|
| 421 | // mail now has a 30 day expiry time |
|---|
| 422 | if(!sMailSystem.MailOption(MAIL_FLAG_NO_EXPIRY)) |
|---|
| 423 | message->expire_time = (uint32)UNIXTIME + (TIME_DAY * 30); |
|---|
| 424 | |
|---|
| 425 | // update it in sql |
|---|
| 426 | CharacterDatabase.WaitExecute("UPDATE mailbox SET read_flag = 1, expiry_time = %u WHERE message_id = %u", message->message_id, message->expire_time); |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | void WorldSession::HandleMailDelete(WorldPacket & recv_data ) |
|---|
| 430 | { |
|---|
| 431 | uint64 mailbox; |
|---|
| 432 | uint32 message_id; |
|---|
| 433 | recv_data >> mailbox >> message_id; |
|---|
| 434 | |
|---|
| 435 | WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); |
|---|
| 436 | data << message_id << uint32(MAIL_RES_DELETED); |
|---|
| 437 | |
|---|
| 438 | MailMessage * message = _player->m_mailBox.GetMessage(message_id); |
|---|
| 439 | if(message == 0) |
|---|
| 440 | { |
|---|
| 441 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 442 | SendPacket(&data); |
|---|
| 443 | |
|---|
| 444 | return; |
|---|
| 445 | } |
|---|
| 446 | |
|---|
| 447 | if(message->copy_made) |
|---|
| 448 | { |
|---|
| 449 | // we have the message as a copy on the item. we can't delete it or this item |
|---|
| 450 | // will no longer function. |
|---|
| 451 | |
|---|
| 452 | // deleted_flag prevents it from being shown in the mail list. |
|---|
| 453 | message->deleted_flag = 1; |
|---|
| 454 | |
|---|
| 455 | // update in sql |
|---|
| 456 | CharacterDatabase.WaitExecute("UPDATE mailbox SET deleted_flag = 1 WHERE message_id = %u", message_id); |
|---|
| 457 | } |
|---|
| 458 | else |
|---|
| 459 | { |
|---|
| 460 | // delete the message, there are no other references to it. |
|---|
| 461 | _player->m_mailBox.DeleteMessage(message_id, true); |
|---|
| 462 | } |
|---|
| 463 | |
|---|
| 464 | data << uint32(MAIL_OK); |
|---|
| 465 | SendPacket(&data); |
|---|
| 466 | } |
|---|
| 467 | |
|---|
| 468 | void WorldSession::HandleTakeItem(WorldPacket & recv_data ) |
|---|
| 469 | { |
|---|
| 470 | uint64 mailbox; |
|---|
| 471 | uint32 message_id; |
|---|
| 472 | uint32 lowguid; |
|---|
| 473 | vector< uint64 >::iterator itr; |
|---|
| 474 | |
|---|
| 475 | recv_data >> mailbox >> message_id >> lowguid; |
|---|
| 476 | |
|---|
| 477 | WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); |
|---|
| 478 | data << message_id << uint32(MAIL_RES_ITEM_TAKEN); |
|---|
| 479 | |
|---|
| 480 | MailMessage * message = _player->m_mailBox.GetMessage(message_id); |
|---|
| 481 | if(message == 0 || message->items.empty()) |
|---|
| 482 | { |
|---|
| 483 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 484 | SendPacket(&data); |
|---|
| 485 | |
|---|
| 486 | return; |
|---|
| 487 | } |
|---|
| 488 | |
|---|
| 489 | for( itr = message->items.begin( ); itr != message->items.end( ); ++itr ) |
|---|
| 490 | { |
|---|
| 491 | if ( (*itr) == lowguid ) |
|---|
| 492 | break; |
|---|
| 493 | } |
|---|
| 494 | |
|---|
| 495 | if( itr == message->items.end( ) ) |
|---|
| 496 | { |
|---|
| 497 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 498 | SendPacket(&data); |
|---|
| 499 | |
|---|
| 500 | return; |
|---|
| 501 | } |
|---|
| 502 | |
|---|
| 503 | // check for cod credit |
|---|
| 504 | if(message->cod > 0) |
|---|
| 505 | { |
|---|
| 506 | if( !_player->HasGold(message->cod) ) |
|---|
| 507 | { |
|---|
| 508 | data << uint32(MAIL_ERR_NOT_ENOUGH_MONEY); |
|---|
| 509 | SendPacket(&data); |
|---|
| 510 | return; |
|---|
| 511 | } |
|---|
| 512 | } |
|---|
| 513 | |
|---|
| 514 | // grab the item |
|---|
| 515 | Item * item = objmgr.LoadItem( *itr ); |
|---|
| 516 | if(item == 0) |
|---|
| 517 | { |
|---|
| 518 | // doesn't exist |
|---|
| 519 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 520 | SendPacket(&data); |
|---|
| 521 | |
|---|
| 522 | return; |
|---|
| 523 | } |
|---|
| 524 | |
|---|
| 525 | //Find free slot |
|---|
| 526 | SlotResult result = _player->GetItemInterface()->FindFreeInventorySlot(item->GetProto()); |
|---|
| 527 | if(result.Result == 0) |
|---|
| 528 | { |
|---|
| 529 | //End of slots |
|---|
| 530 | data << uint32(MAIL_ERR_BAG_FULL); |
|---|
| 531 | SendPacket(&data); |
|---|
| 532 | |
|---|
| 533 | item->DeleteMe(); |
|---|
| 534 | return; |
|---|
| 535 | } |
|---|
| 536 | item->m_isDirty = true; |
|---|
| 537 | |
|---|
| 538 | if( !_player->GetItemInterface()->SafeAddItem(item, result.ContainerSlot, result.Slot) ) |
|---|
| 539 | { |
|---|
| 540 | if( !_player->GetItemInterface()->AddItemToFreeSlot(item) ) |
|---|
| 541 | { |
|---|
| 542 | //End of slots |
|---|
| 543 | data << uint32(MAIL_ERR_BAG_FULL); |
|---|
| 544 | SendPacket(&data); |
|---|
| 545 | item->DeleteMe(); |
|---|
| 546 | return; |
|---|
| 547 | } |
|---|
| 548 | } |
|---|
| 549 | else |
|---|
| 550 | item->SaveToDB(result.ContainerSlot, result.Slot, true, NULL); |
|---|
| 551 | |
|---|
| 552 | // send complete packet |
|---|
| 553 | data << uint32(MAIL_OK); |
|---|
| 554 | data << item->GetLowGUID(); |
|---|
| 555 | data << item->GetStackCount(); |
|---|
| 556 | |
|---|
| 557 | message->items.erase( itr ); |
|---|
| 558 | |
|---|
| 559 | // re-save (update the items field) |
|---|
| 560 | sMailSystem.SaveMessageToSQL( message); |
|---|
| 561 | SendPacket(&data); |
|---|
| 562 | |
|---|
| 563 | if( message->cod > 0 ) |
|---|
| 564 | { |
|---|
| 565 | _player->ModGold( -(int32)message->cod ); |
|---|
| 566 | string subject = "COD Payment: "; |
|---|
| 567 | subject += message->subject; |
|---|
| 568 | sMailSystem.SendAutomatedMessage(NORMAL, message->player_guid, message->sender_guid, subject, "", message->cod, 0, 0, MAIL_STATIONERY_TEST1 ); |
|---|
| 569 | |
|---|
| 570 | message->cod = 0; |
|---|
| 571 | CharacterDatabase.Execute("UPDATE mailbox SET cod = 0 WHERE message_id = %u", message->message_id); |
|---|
| 572 | } |
|---|
| 573 | |
|---|
| 574 | // probably need to send an item push here |
|---|
| 575 | } |
|---|
| 576 | |
|---|
| 577 | void WorldSession::HandleTakeMoney(WorldPacket & recv_data ) |
|---|
| 578 | { |
|---|
| 579 | uint64 mailbox; |
|---|
| 580 | uint32 message_id; |
|---|
| 581 | recv_data >> mailbox >> message_id; |
|---|
| 582 | |
|---|
| 583 | WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); |
|---|
| 584 | data << message_id << uint32(MAIL_RES_MONEY_TAKEN); |
|---|
| 585 | |
|---|
| 586 | MailMessage * message = _player->m_mailBox.GetMessage(message_id); |
|---|
| 587 | if(message == 0 || !message->money) |
|---|
| 588 | { |
|---|
| 589 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 590 | SendPacket(&data); |
|---|
| 591 | |
|---|
| 592 | return; |
|---|
| 593 | } |
|---|
| 594 | |
|---|
| 595 | // Check they don't have more than the max gold |
|---|
| 596 | if(sWorld.GoldCapEnabled) |
|---|
| 597 | { |
|---|
| 598 | if( (_player->GetGold() + message->money) > sWorld.GoldLimit ) |
|---|
| 599 | { |
|---|
| 600 | _player->GetItemInterface()->BuildInventoryChangeError(NULL, NULL, INV_ERR_TOO_MUCH_GOLD); |
|---|
| 601 | return; |
|---|
| 602 | } |
|---|
| 603 | } |
|---|
| 604 | |
|---|
| 605 | // add the money to the player |
|---|
| 606 | _player->ModGold( message->money ); |
|---|
| 607 | |
|---|
| 608 | // message no longer has any money |
|---|
| 609 | message->money = 0; |
|---|
| 610 | |
|---|
| 611 | // update in sql! |
|---|
| 612 | CharacterDatabase.WaitExecute("UPDATE mailbox SET money = 0 WHERE message_id = %u", message->message_id); |
|---|
| 613 | |
|---|
| 614 | // send result |
|---|
| 615 | data << uint32(MAIL_OK); |
|---|
| 616 | SendPacket(&data); |
|---|
| 617 | } |
|---|
| 618 | |
|---|
| 619 | void WorldSession::HandleReturnToSender(WorldPacket & recv_data ) |
|---|
| 620 | { |
|---|
| 621 | uint64 mailbox; |
|---|
| 622 | uint32 message_id; |
|---|
| 623 | recv_data >> mailbox >> message_id; |
|---|
| 624 | |
|---|
| 625 | WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); |
|---|
| 626 | data << message_id << uint32(MAIL_RES_RETURNED_TO_SENDER); |
|---|
| 627 | |
|---|
| 628 | MailMessage * msg = _player->m_mailBox.GetMessage(message_id); |
|---|
| 629 | if(msg == 0) |
|---|
| 630 | { |
|---|
| 631 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 632 | SendPacket(&data); |
|---|
| 633 | |
|---|
| 634 | return; |
|---|
| 635 | } |
|---|
| 636 | |
|---|
| 637 | // copy into a new struct |
|---|
| 638 | MailMessage message = *msg; |
|---|
| 639 | |
|---|
| 640 | // remove the old message |
|---|
| 641 | _player->m_mailBox.DeleteMessage(message_id, true); |
|---|
| 642 | |
|---|
| 643 | // re-assign the owner/sender |
|---|
| 644 | message.player_guid = message.sender_guid; |
|---|
| 645 | message.sender_guid = _player->GetGUID(); |
|---|
| 646 | |
|---|
| 647 | // turn off the read flag |
|---|
| 648 | message.read_flag = false; |
|---|
| 649 | message.deleted_flag = false; |
|---|
| 650 | message.copy_made = false; |
|---|
| 651 | |
|---|
| 652 | // null out the cod charges. (the sender doesn't want to have to pay for his own item |
|---|
| 653 | // that he got nothing for.. :p) |
|---|
| 654 | message.cod = 0; |
|---|
| 655 | |
|---|
| 656 | // assign new delivery time |
|---|
| 657 | message.delivery_time = message.items.empty() ? (uint32)UNIXTIME : (uint32)UNIXTIME + 3600; |
|---|
| 658 | |
|---|
| 659 | // add to the senders mailbox |
|---|
| 660 | sMailSystem.DeliverMessage(message.player_guid, &message); |
|---|
| 661 | |
|---|
| 662 | // finish the packet |
|---|
| 663 | data << uint32(MAIL_OK); |
|---|
| 664 | SendPacket(&data); |
|---|
| 665 | } |
|---|
| 666 | |
|---|
| 667 | void WorldSession::HandleMailCreateTextItem(WorldPacket & recv_data ) |
|---|
| 668 | { |
|---|
| 669 | uint64 mailbox; |
|---|
| 670 | uint32 message_id; |
|---|
| 671 | recv_data >> mailbox >> message_id; |
|---|
| 672 | |
|---|
| 673 | WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); |
|---|
| 674 | data << message_id << uint32(MAIL_RES_MADE_PERMANENT); |
|---|
| 675 | |
|---|
| 676 | |
|---|
| 677 | ItemPrototype * proto = ItemPrototypeStorage.LookupEntry(8383); |
|---|
| 678 | MailMessage * message = _player->m_mailBox.GetMessage(message_id); |
|---|
| 679 | if(message == 0 || !proto) |
|---|
| 680 | { |
|---|
| 681 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 682 | SendPacket(&data); |
|---|
| 683 | |
|---|
| 684 | return; |
|---|
| 685 | } |
|---|
| 686 | |
|---|
| 687 | SlotResult result = _player->GetItemInterface()->FindFreeInventorySlot(proto); |
|---|
| 688 | if(result.Result == 0) |
|---|
| 689 | { |
|---|
| 690 | data << uint32(MAIL_ERR_INTERNAL_ERROR); |
|---|
| 691 | SendPacket(&data); |
|---|
| 692 | |
|---|
| 693 | return; |
|---|
| 694 | } |
|---|
| 695 | |
|---|
| 696 | Item * pItem = objmgr.CreateItem(8383, _player); |
|---|
| 697 | if (pItem== NULL) |
|---|
| 698 | return; |
|---|
| 699 | |
|---|
| 700 | pItem->SetTextId(message_id); |
|---|
| 701 | if( _player->GetItemInterface()->AddItemToFreeSlot(pItem) ) |
|---|
| 702 | { |
|---|
| 703 | // mail now has an item after it |
|---|
| 704 | message->copy_made = true; |
|---|
| 705 | |
|---|
| 706 | // update in sql |
|---|
| 707 | CharacterDatabase.WaitExecute("UPDATE mailbox SET copy_made = 1 WHERE message_id = %u", message_id); |
|---|
| 708 | |
|---|
| 709 | data << uint32(MAIL_OK); |
|---|
| 710 | SendPacket(&data); |
|---|
| 711 | } |
|---|
| 712 | else |
|---|
| 713 | { |
|---|
| 714 | pItem->DeleteMe(); |
|---|
| 715 | } |
|---|
| 716 | } |
|---|
| 717 | |
|---|
| 718 | void WorldSession::HandleItemTextQuery(WorldPacket & recv_data) |
|---|
| 719 | { |
|---|
| 720 | uint32 message_id; |
|---|
| 721 | recv_data >> message_id; |
|---|
| 722 | |
|---|
| 723 | string body = "Internal Error"; |
|---|
| 724 | |
|---|
| 725 | MailMessage * msg = _player->m_mailBox.GetMessage(message_id); |
|---|
| 726 | if(msg) |
|---|
| 727 | body = msg->body; |
|---|
| 728 | |
|---|
| 729 | WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, body.length() + 5); |
|---|
| 730 | data << message_id << body; |
|---|
| 731 | SendPacket(&data); |
|---|
| 732 | } |
|---|
| 733 | |
|---|
| 734 | void Mailbox::FillTimePacket(WorldPacket& data) |
|---|
| 735 | { |
|---|
| 736 | uint32 c = 0; |
|---|
| 737 | MessageMap::iterator iter = Messages.begin(); |
|---|
| 738 | data << uint32(0) << uint32(0); |
|---|
| 739 | |
|---|
| 740 | for(; iter != Messages.end(); ++iter) |
|---|
| 741 | { |
|---|
| 742 | if(iter->second.deleted_flag == 0 && iter->second.read_flag == 0 && (uint32)UNIXTIME >= iter->second.delivery_time) |
|---|
| 743 | { |
|---|
| 744 | // unread message, w00t. |
|---|
| 745 | ++c; |
|---|
| 746 | data << uint64(iter->second.sender_guid); |
|---|
| 747 | data << uint32(0); |
|---|
| 748 | data << uint32(0);// money or something? |
|---|
| 749 | data << uint32(iter->second.stationery); |
|---|
| 750 | //data << float(UNIXTIME-iter->second.delivery_time); |
|---|
| 751 | data << float(-9.0f); // maybe the above? |
|---|
| 752 | } |
|---|
| 753 | } |
|---|
| 754 | |
|---|
| 755 | if(c== 0) |
|---|
| 756 | { |
|---|
| 757 | |
|---|
| 758 | *(uint32*)(&data.contents()[0])= 0xc7a8c000; |
|---|
| 759 | } |
|---|
| 760 | else |
|---|
| 761 | { |
|---|
| 762 | |
|---|
| 763 | *(uint32*)(&data.contents()[4])=c; |
|---|
| 764 | } |
|---|
| 765 | } |
|---|
| 766 | |
|---|
| 767 | void WorldSession::HandleMailTime(WorldPacket & recv_data) |
|---|
| 768 | { |
|---|
| 769 | WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 100); |
|---|
| 770 | _player->m_mailBox.FillTimePacket(data); |
|---|
| 771 | SendPacket(&data); |
|---|
| 772 | } |
|---|
| 773 | |
|---|
| 774 | void WorldSession::SendMailError(uint32 error) |
|---|
| 775 | { |
|---|
| 776 | WorldPacket data(SMSG_SEND_MAIL_RESULT, 12); |
|---|
| 777 | data << uint32(0); |
|---|
| 778 | data << uint32(MAIL_RES_MAIL_SENT); |
|---|
| 779 | data << error; |
|---|
| 780 | SendPacket(&data); |
|---|
| 781 | } |
|---|
| 782 | |
|---|
| 783 | void WorldSession::HandleGetMail(WorldPacket & recv_data ) |
|---|
| 784 | { |
|---|
| 785 | WorldPacket * data = _player->m_mailBox.BuildMailboxListingPacket(); |
|---|
| 786 | SendPacket(data); |
|---|
| 787 | delete data; |
|---|
| 788 | } |
|---|
| 789 | |
|---|
| 790 | void MailSystem::RemoveMessageIfDeleted(uint32 message_id, Player * plr) |
|---|
| 791 | { |
|---|
| 792 | MailMessage * msg = plr->m_mailBox.GetMessage(message_id); |
|---|
| 793 | if(msg == 0) return; |
|---|
| 794 | |
|---|
| 795 | if(msg->deleted_flag) // we've deleted from inbox |
|---|
| 796 | plr->m_mailBox.DeleteMessage(message_id, true); // wipe the message |
|---|
| 797 | } |
|---|
| 798 | |
|---|
| 799 | void MailSystem::SendAutomatedMessage(uint32 type, uint64 sender, uint64 receiver, string subject, string body, |
|---|
| 800 | uint32 money, uint32 cod, uint64 item_guid, uint32 stationery) |
|---|
| 801 | { |
|---|
| 802 | // This is for sending automated messages, for example from an auction house. |
|---|
| 803 | MailMessage msg; |
|---|
| 804 | msg.message_type = type; |
|---|
| 805 | msg.sender_guid = sender; |
|---|
| 806 | msg.player_guid = receiver; |
|---|
| 807 | msg.subject = subject; |
|---|
| 808 | msg.body = body; |
|---|
| 809 | msg.money = money; |
|---|
| 810 | msg.cod = cod; |
|---|
| 811 | if( Arcemu::Util::GUID_LOPART(item_guid) != 0 ) |
|---|
| 812 | msg.items.push_back( Arcemu::Util::GUID_LOPART(item_guid) ); |
|---|
| 813 | |
|---|
| 814 | msg.stationery = stationery; |
|---|
| 815 | msg.delivery_time = (uint32)UNIXTIME; |
|---|
| 816 | msg.expire_time = 0; |
|---|
| 817 | msg.read_flag = false; |
|---|
| 818 | msg.copy_made = false; |
|---|
| 819 | msg.deleted_flag = false; |
|---|
| 820 | |
|---|
| 821 | // Send the message. |
|---|
| 822 | DeliverMessage(receiver, &msg); |
|---|
| 823 | } |
|---|
| 824 | |
|---|
| 825 | uint32 MailSystem::Generate_Message_Id() |
|---|
| 826 | { |
|---|
| 827 | /** I know this is horrible. But when you have external mail sources unfortunately this is the only way to do this. |
|---|
| 828 | * - Burlex |
|---|
| 829 | */ |
|---|
| 830 | |
|---|
| 831 | uint32 id = 1; |
|---|
| 832 | QueryResult * result = CharacterDatabase.Query("SELECT MAX(message_id) FROM mailbox"); |
|---|
| 833 | if(result) |
|---|
| 834 | { |
|---|
| 835 | id = result->Fetch()[0].GetUInt32()+1; |
|---|
| 836 | delete result; |
|---|
| 837 | } |
|---|
| 838 | |
|---|
| 839 | return id; |
|---|
| 840 | } |
|---|
| 841 | |
|---|
| 842 | void Mailbox::Load(QueryResult * result) |
|---|
| 843 | { |
|---|
| 844 | if(!result) |
|---|
| 845 | return; |
|---|
| 846 | |
|---|
| 847 | Field * fields; |
|---|
| 848 | MailMessage msg; |
|---|
| 849 | uint32 i; |
|---|
| 850 | char * str; |
|---|
| 851 | char * p; |
|---|
| 852 | uint64 itemguid; |
|---|
| 853 | |
|---|
| 854 | do |
|---|
| 855 | { |
|---|
| 856 | fields = result->Fetch(); |
|---|
| 857 | |
|---|
| 858 | // Create message struct |
|---|
| 859 | i = 0; |
|---|
| 860 | msg.items.clear(); |
|---|
| 861 | msg.message_id = fields[i++].GetUInt32(); |
|---|
| 862 | msg.message_type = fields[i++].GetUInt32(); |
|---|
| 863 | msg.player_guid = fields[i++].GetUInt32(); |
|---|
| 864 | msg.sender_guid = fields[i++].GetUInt32(); |
|---|
| 865 | msg.subject = fields[i++].GetString(); |
|---|
| 866 | msg.body = fields[i++].GetString(); |
|---|
| 867 | msg.money = fields[i++].GetUInt32(); |
|---|
| 868 | str = (char*)fields[i++].GetString(); |
|---|
| 869 | p = strchr(str, ','); |
|---|
| 870 | if( p == NULL ) |
|---|
| 871 | { |
|---|
| 872 | itemguid = atoi(str); |
|---|
| 873 | if( itemguid != 0 ) |
|---|
| 874 | msg.items.push_back( itemguid ); |
|---|
| 875 | } |
|---|
| 876 | else |
|---|
| 877 | { |
|---|
| 878 | while( p ) |
|---|
| 879 | { |
|---|
| 880 | *p = 0; |
|---|
| 881 | p++; |
|---|
| 882 | |
|---|
| 883 | itemguid = atoi( str ); |
|---|
| 884 | if( itemguid != 0 ) |
|---|
| 885 | msg.items.push_back( itemguid ); |
|---|
| 886 | |
|---|
| 887 | str = p; |
|---|
| 888 | p = strchr( str, ',' ); |
|---|
| 889 | } |
|---|
| 890 | } |
|---|
| 891 | |
|---|
| 892 | msg.cod = fields[i++].GetUInt32(); |
|---|
| 893 | msg.stationery = fields[i++].GetUInt32(); |
|---|
| 894 | msg.expire_time = fields[i++].GetUInt32(); |
|---|
| 895 | msg.delivery_time = fields[i++].GetUInt32(); |
|---|
| 896 | msg.copy_made = fields[i++].GetBool(); |
|---|
| 897 | msg.read_flag = fields[i++].GetBool(); |
|---|
| 898 | msg.deleted_flag = fields[i++].GetBool(); |
|---|
| 899 | |
|---|
| 900 | /*if( msg.copy_made ) |
|---|
| 901 | { |
|---|
| 902 | QueryResult * result = CharacterDatabase.Query( "SELECT * FROM playeritems WHERE itemtext = %u", msg.message_id ); |
|---|
| 903 | if( result == NULL ) |
|---|
| 904 | { |
|---|
| 905 | if( msg.deleted_flag ) |
|---|
| 906 | CharacterDatabase.WaitExecute( "DELETE FROM mailbox WHERE message_id = %u", msg.message_id ); |
|---|
| 907 | else |
|---|
| 908 | { |
|---|
| 909 | msg.copy_made = false; |
|---|
| 910 | CharacterDatabase.WaitExecute( "UPDATE mailbox SET copy_made = 0 WHERE message_id = %u", msg.message_id ); |
|---|
| 911 | } |
|---|
| 912 | } |
|---|
| 913 | else |
|---|
| 914 | delete result; |
|---|
| 915 | }*/ |
|---|
| 916 | |
|---|
| 917 | // Add to the mailbox |
|---|
| 918 | AddMessage(&msg); |
|---|
| 919 | |
|---|
| 920 | } while(result->NextRow()); |
|---|
| 921 | } |
|---|