ManaPlus
mail2recv.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2011-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "net/eathena/mail2recv.h"
23 
24 #include "itemcolormanager.h"
25 #include "notifymanager.h"
26 
27 #include "const/net/inventory.h"
28 
29 #include "being/playerinfo.h"
30 
32 
33 #include "gui/mailmessage.h"
34 
37 #include "gui/windows/mailwindow.h"
38 
39 #include "net/mail2handler.h"
40 #include "net/messagein.h"
41 
42 #include "resources/mailqueue.h"
43 
45 
46 #include "resources/item/item.h"
48 
49 #include "utils/checkutils.h"
50 #include "utils/gettext.h"
51 #include "utils/stringutils.h"
52 #include "utils/timer.h"
53 
54 #include "debug.h"
55 
56 extern int packetVersion;
57 
58 namespace EAthena
59 {
60 
61 namespace Mail2Recv
62 {
63  std::queue<MailQueue*> mMailQueue;
64  std::string mCheckedName;
65 } // namespace Mail2Recv
66 
68 {
69  // ignored, because if has new mail, server send chat message already.
70  msg.readUInt8("has new mail");
71 }
72 
74 {
76  msg.readString(24, "receiver");
77  msg.readUInt8("result");
78 }
79 
81 {
82  const int res = msg.readUInt8("result");
83  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
84  const int amount = msg.readInt16("amount");
85  const int itemId = msg.readItemId("item id");
86  const ItemTypeT itemType = static_cast<ItemTypeT>(
87  msg.readUInt8("item type"));
88  const uint8_t identify = msg.readUInt8("identify");
89  const Damaged damaged = fromBool(msg.readUInt8("attribute"), Damaged);
90  const uint8_t refine = msg.readUInt8("refine");
91  int cards[maxCards];
92  for (int f = 0; f < maxCards; f++)
93  cards[f] = msg.readItemId("card");
94  ItemOptionsList *options = new ItemOptionsList(5);
95  for (int f = 0; f < 5; f ++)
96  {
97  const uint16_t idx = msg.readInt16("option index");
98  const uint16_t val = msg.readInt16("option value");
99  msg.readUInt8("option param");
100  options->add(idx, val);
101  }
102  msg.readInt16("weight");
103  Favorite favorite = fromBool(msg.readUInt8("favorite"), Favorite);
104  msg.readInt32("location");
105 
106  if (mailEditWindow == nullptr)
107  {
108  reportAlways("Mail edit window not created")
109  delete options;
110  return;
111  }
112  Inventory *const inventory = mailEditWindow->getInventory();
113  if (inventory == nullptr)
114  {
115  reportAlways("Mail edit window inventory not exists")
116  delete options;
117  return;
118  }
119 
120  if (res != 0)
121  {
122  switch (res)
123  {
124  case 1:
127  break;
128  case 2:
131  break;
132  case 3:
135  break;
136  case 4:
139  break;
140  default:
144  break;
145  }
146  delete options;
147  return;
148  }
149 
150  Item *const item = inventory->findItemByTag(index);
151  if (item == nullptr)
152  {
153  const int slot = inventory->addItem(itemId,
154  itemType,
155  amount,
156  refine,
158  fromBool(identify, Identified),
159  damaged,
160  favorite,
161  Equipm_false,
163  if (slot == -1)
164  {
165  delete options;
166  return;
167  }
168  inventory->setCards(slot, cards, maxCards);
169  inventory->setOptions(slot, options);
170  inventory->setTag(slot, index);
171  }
172  else
173  {
174  item->increaseQuantity(amount);
175  }
176 
178  delete options;
179 }
180 
182 {
183  const int result = msg.readUInt8("result");
184  const int index = msg.readInt16("index") - INVENTORY_OFFSET;
185  const int amount = msg.readInt16("count");
186  msg.readInt16("weight");
187 
188  if (result == 0)
189  {
190  const Inventory *const inv = PlayerInfo::getInventory();
191  if (inv == nullptr)
192  {
193  reportAlways("Player inventory not exists")
194  return;
195  }
196  std::string itemName;
197  const Item *const item = inv->getItem(index);
198  if (item != nullptr)
199  {
200  itemName = item->getName();
201  }
202  else
203  {
204  // TRANSLATORS: unknown item name
205  itemName = _("Unknown item");
206  }
207 
210  itemName);
211  return;
212  }
213  if (mailEditWindow == nullptr)
214  {
215  reportAlways("Mail edit window not created")
216  return;
217  }
218  Inventory *const inventory = mailEditWindow->getInventory();
219  if (inventory == nullptr)
220  {
221  reportAlways("Mail edit window inventory not exists")
222  return;
223  }
224  const int index2 = inventory->findIndexByTag(index);
225  if (index2 == -1)
226  {
227  reportAlways("Item not exists in mail edit window.")
228  return;
229  }
230  Item *const item = inventory->getItem(index2);
231  if (item == nullptr)
232  {
233  reportAlways("Item not exists.")
234  return;
235  }
236 
237  item->increaseQuantity(-amount);
239 }
240 
242 {
243  const int charId = msg.readInt32("char id");
244  msg.readInt16("class");
245  msg.readInt16("level");
246  if (msg.getVersion() >= 20160316)
247  msg.readString(24, "name");
248  // +++ in future if name received, need use it in map
249  if (mMailQueue.empty())
250  {
251  reportAlways("Mail2Recv::processCheckNameResult no names in queue."
252  "Char id: %d", charId)
253  return;
254  }
255  MailQueue *const mail = mMailQueue.front();
256  mMailQueue.pop();
257  if (charId == 0)
258  {
260  mail->to);
261  delete mail;
262  return;
263  }
264  mCheckedName = mail->to;
265  switch (mail->type)
266  {
268  mail2Handler->sendMail(mail->to,
269  mail->title,
270  mail->body,
271  mail->money);
272  break;
274  if (mailWindow == nullptr)
275  {
276  reportAlways("Mail window not created")
277  }
278  else
279  {
280  MailWindow::createMail(mail->to);
281  }
282  break;
284  if (mailEditWindow == nullptr)
285  {
286  reportAlways("Mail edit window not created")
287  }
288  else
289  {
291  }
292  break;
294  default:
295  reportAlways("Not implemented yet.")
296  break;
297  }
298  delete mail;
299 }
300 
302 {
303  const int res = msg.readUInt8("result");
304  switch (res)
305  {
306  case 0:
308  if (mailEditWindow != nullptr)
310  break;
311  case 1:
313  break;
314  case 2:
316  break;
317  case 3:
319  break;
320  case 4:
322  break;
323  default:
325  break;
326  }
327 }
328 
330 {
331  if (mailWindow == nullptr)
332  {
333  reportAlways("mail window not created")
334  return;
335  }
336  msg.readInt16("len");
337  bool isEnd = true;
338 
339  if (packetVersion < 20170419)
340  {
341  mailWindow->setOpenType(fromInt(msg.readUInt8("open type"),
342  MailOpenTypeT));
343  const int cnt = msg.readUInt8("cnt");
344  isEnd = msg.readUInt8("isEnd") != 0;
345  for (int f = 0; f < cnt; f ++)
346  {
347  MailMessage *const mail = new MailMessage;
348  mail->id = msg.readInt64("mail id");
349  mail->read = msg.readUInt8("is read") != 0U ? true : false;
350  mail->type = static_cast<MailMessageType::Type>(
351  msg.readUInt8("type"));
352  mail->sender = msg.readString(24, "sender name");
353  if (packetVersion < 20170419)
354  {
355  mail->time = CAST_S32(cur_time - msg.readInt32("reg time"));
356  mail->strTime = timeToStr(mail->time);
357  }
358  mail->expireTime = msg.readInt32("expire time") + cur_time;
359  mail->expired = mail->expireTime <= 0;
360  mail->title = msg.readString(-1, "title");
361  mailWindow->addMail(mail);
362  }
363  }
364  else
365  {
366  isEnd = msg.readUInt8("isEnd") != 0;
367  while (msg.getUnreadLength() > 0)
368  {
369  MailMessage *const mail = new MailMessage;
370  // +++ need save open type into MailMessage
371  msg.readUInt8("open type");
372  mail->id = msg.readInt64("mail id");
373  mail->read = msg.readUInt8("is read") != 0U ? true : false;
374  mail->type = static_cast<MailMessageType::Type>(
375  msg.readUInt8("type"));
376  mail->sender = msg.readString(24, "sender name");
377  mail->strTime = "-";
378  mail->expireTime = msg.readInt32("expire time") + cur_time;
379  mail->expired = mail->expireTime <= 0;
380  mail->title = msg.readString(-1, "title");
381  mailWindow->addMail(mail);
382  }
383  }
384 
385  if (isEnd)
387 }
388 
390 {
391  msg.readInt16("len");
392  const MailOpenTypeT openType = static_cast<MailOpenTypeT>(
393  msg.readUInt8("open type"));
394  const int64_t mailId = msg.readInt64("mail id");
395  const int textLen = msg.readInt16("text len");
396  const int64_t money = msg.readInt64("money");
397  const int itemsCount = msg.readUInt8("item count");
398  const std::string text = msg.readString(textLen, "text message");
399  MailMessage *mail = nullptr;
400 
401  if (mailWindow != nullptr &&
402  openType == mailWindow->getOpenType())
403  {
404  mail = mailWindow->findMail(mailId);
405  }
406 
407  if (mail == nullptr)
408  {
409  reportAlways("Mail message not found")
410  for (int f = 0; f < itemsCount; f ++)
411  {
412  msg.readInt16("amount");
413  msg.readItemId("item id");
414  msg.readUInt8("identify");
415  msg.readUInt8("damaged");
416  msg.readUInt8("refine");
417  for (int d = 0; d < maxCards; d ++)
418  msg.readItemId("card");
419  msg.readInt32("location");
420  msg.readUInt8("type");
421  msg.readInt16("view sprite");
422  msg.readInt16("bind on equip");
423  for (int d = 0; d < 5; d ++)
424  {
425  msg.readInt16("option index");
426  msg.readInt16("option value");
427  msg.readUInt8("option param");
428  }
429  }
430  return;
431  }
432 
433  mail->money = money;
434  mail->text = text;
435  mailWindow->showMessage(mail, itemsCount);
436 
437  Inventory *const inventory = mailViewWindow->getInventory();
438 
439  for (int f = 0; f < itemsCount; f ++)
440  {
441  // server may send wrong items count, if items was removed from mail
442  if (msg.getUnreadLength() == 0)
443  break;
444  const int amount = msg.readInt16("amount");
445  const int itemId = msg.readItemId("item id");
446  const uint8_t identify = msg.readUInt8("identify");
447  const Damaged damaged = fromBool(msg.readUInt8("attribute"), Damaged);
448  const uint8_t refine = msg.readUInt8("refine");
449  int cards[maxCards];
450  for (int d = 0; d < maxCards; d ++)
451  cards[d] = msg.readItemId("card");
452  msg.readInt32("location");
453  const ItemTypeT itemType = static_cast<ItemTypeT>(
454  msg.readUInt8("item type"));
455  msg.readInt16("view sprite");
456  msg.readInt16("bind on equip");
457  ItemOptionsList *options = new ItemOptionsList(5);
458  for (int d = 0; d < 5; d ++)
459  {
460  const uint16_t idx = msg.readInt16("option index");
461  const uint16_t val = msg.readInt16("option value");
462  msg.readUInt8("option param");
463  options->add(idx, val);
464  }
465 
466  const int slot = inventory->addItem(itemId,
467  itemType,
468  amount,
469  refine,
471  fromBool(identify, Identified),
472  damaged,
474  Equipm_false,
476  if (slot == -1)
477  {
478  delete options;
479  continue;
480  }
481  inventory->setCards(slot, cards, maxCards);
482  inventory->setOptions(slot, options);
483  delete options;
484  }
486 }
487 
489 {
490  msg.readUInt8("open type");
491  const int64_t mailId = msg.readInt64("mail id");
492  if (mailWindow == nullptr)
493  {
494  reportAlways("Mail window not created.")
495  return;
496  }
497  mailWindow->removeMail(mailId);
498 }
499 
501 {
502  const int64_t mailId = msg.readInt64("mail id");
503  msg.readUInt8("open type");
504  const int res = msg.readUInt8("result");
505  switch (res)
506  {
507  case 0:
510  if (mailViewWindow != nullptr)
511  mailViewWindow->removeMoney(mailId);
512  break;
513  case 1:
516  break;
517  case 2:
520  break;
521  default:
525  break;
526  }
527 }
528 
530 {
531  const int64_t mailId = msg.readInt64("mail id");
532  msg.readUInt8("open type");
533  const int res = msg.readUInt8("result");
534  switch (res)
535  {
536  case 0:
539  if (mailViewWindow != nullptr)
540  mailViewWindow->removeItems(mailId);
541  break;
542  case 1:
545  break;
546  case 2:
549  break;
550  default:
554  break;
555  }
556 }
557 
558 } // namespace EAthena
volatile time_t cur_time
Definition: timer.cpp:58
#define fromBool(val, name)
Definition: booldefines.h:49
#define maxCards
Definition: cards.h:25
#define CAST_S32
Definition: cast.h:30
#define reportAlways(...)
Definition: checkutils.h:253
void setCards(const int index, const int *const cards, const int size) const
Definition: inventory.cpp:194
int findIndexByTag(const int tag) const
Definition: inventory.cpp:412
Item * getItem(const int index) const
Definition: inventory.cpp:83
void setTag(const int index, const int tag)
Definition: inventory.cpp:224
Item * findItemByTag(const int tag) const
Definition: inventory.cpp:424
void setOptions(const int index, const ItemOptionsList *const options)
Definition: inventory.cpp:210
int addItem(const int id, const ItemTypeT type, const int quantity, const uint8_t refine, const ItemColor color, const Identified identified, const Damaged damaged, const Favorite favorite, const Equipm equipment, const Equipped equipped)
Definition: inventory.cpp:115
static ItemColor getColorFromCards(const int *const cards)
Definition: item.h:50
std::string getName() const
Definition: item.cpp:140
void increaseQuantity(const int amount)
Definition: item.h:99
Inventory * getInventory() const
void removeItems(const int64_t mailId)
void removeMoney(const int64_t mailId)
Inventory * getInventory() const
void setOpenType(const MailOpenTypeT &type)
Definition: mailwindow.h:76
void removeMail(const int64_t id)
Definition: mailwindow.cpp:233
void addMail(MailMessage *const message)
Definition: mailwindow.cpp:224
MailMessage * findMail(const int64_t id)
Definition: mailwindow.cpp:376
void showMessage(MailMessage *const mail, const int itemsCount)
Definition: mailwindow.cpp:260
static void createMail(const std::string &to)
Definition: mailwindow.cpp:367
MailOpenTypeT getOpenType() const
Definition: mailwindow.h:79
void setLastPage()
Definition: mailwindow.cpp:384
virtual void sendMail(const std::string &to, const std::string &title, const std::string &body, const int64_t &money) const =0
static const int INVENTORY_OFFSET
Definition: inventory.h:27
bool Damaged
Definition: damaged.h:30
const bool Equipm_false
Definition: equipm.h:30
const bool Equipped_false
Definition: equipped.h:30
bool Favorite
Definition: favorite.h:30
const bool Favorite_false
Definition: favorite.h:30
#define _(s)
Definition: gettext.h:35
bool Identified
Definition: identified.h:30
#define fromInt(val, name)
Definition: intdefines.h:46
ItemType ::T ItemTypeT
Definition: itemtype.h:43
#define UNIMPLEMENTEDPACKETFIELD(field)
Definition: logger.h:59
#define UNIMPLEMENTEDPACKET
Definition: logger.h:56
Net::Mail2Handler * mail2Handler
Definition: net.cpp:113
int packetVersion
Definition: client.cpp:125
MailEditWindow * mailEditWindow
MailOpenType ::T MailOpenTypeT
Definition: mailopentype.h:33
MailViewWindow * mailViewWindow
MailWindow * mailWindow
Definition: mailwindow.cpp:54
bool msg(InputEvent &event)
Definition: chat.cpp:39
void processMailDelete(Net::MessageIn &msg)
Definition: mail2recv.cpp:488
void processRequestItems(Net::MessageIn &msg)
Definition: mail2recv.cpp:529
void processAddItemResult(Net::MessageIn &msg)
Definition: mail2recv.cpp:80
void processMailIcon(Net::MessageIn &msg)
Definition: mail2recv.cpp:67
void processSendResult(Net::MessageIn &msg)
Definition: mail2recv.cpp:301
void processReadMail(Net::MessageIn &msg)
Definition: mail2recv.cpp:389
void processCheckNameResult(Net::MessageIn &msg)
Definition: mail2recv.cpp:241
void processMailListPage(Net::MessageIn &msg)
Definition: mail2recv.cpp:329
void processRequestMoney(Net::MessageIn &msg)
Definition: mail2recv.cpp:500
std::string mCheckedName
Definition: mail2recv.cpp:64
void processRemoveItemResult(Net::MessageIn &msg)
Definition: mail2recv.cpp:181
std::queue< MailQueue * > mMailQueue
Definition: mail2recv.cpp:63
void processOpenNewMailWindow(Net::MessageIn &msg)
Definition: mail2recv.cpp:73
void notify(const unsigned int message)
@ MAIL_SEND_RECEIVER_ERROR
Definition: notifytypes.h:248
@ MAIL_SEND_COUNT_ERROR
Definition: notifytypes.h:246
@ MAIL_GET_ATTACH_ERROR
Definition: notifytypes.h:175
@ MAIL_ATTACH_ITEM_NO_SPACE
Definition: notifytypes.h:241
@ MAIL_SEND_ITEM_ERROR
Definition: notifytypes.h:247
@ MAIL_ATTACH_ITEM_WEIGHT_ERROR
Definition: notifytypes.h:239
@ MAIL_GET_MONEY_ERROR
Definition: notifytypes.h:251
@ MAIL_REMOVE_ITEM_ERROR
Definition: notifytypes.h:244
@ MAIL_NAME_VALIDATION_ERROR
Definition: notifytypes.h:238
@ MAIL_ATTACH_ITEM_FATAL_ERROR
Definition: notifytypes.h:240
@ MAIL_GET_MONEY_LIMIT_ERROR
Definition: notifytypes.h:252
@ MAIL_SEND_FATAL_ERROR
Definition: notifytypes.h:245
@ MAIL_GET_ATTACH_FULL_ERROR
Definition: notifytypes.h:249
@ MAIL_GET_ATTACH_OK
Definition: notifytypes.h:174
@ MAIL_ATTACH_ITEM_NOT_TRADEABLE
Definition: notifytypes.h:242
@ MAIL_ATTACH_ITEM_UNKNOWN_ERROR
Definition: notifytypes.h:243
Inventory * getInventory()
Definition: playerinfo.cpp:195
std::string timeToStr(const uint32_t time)
void add(const uint16_t index, const uint16_t value)
int64_t money
Definition: mailmessage.h:57
std::string sender
Definition: mailmessage.h:51
int64_t expireTime
Definition: mailmessage.h:56
int64_t id
Definition: mailmessage.h:54
MailMessageType::Type type
Definition: mailmessage.h:58
std::string strTime
Definition: mailmessage.h:52
std::string title
Definition: mailmessage.h:50
std::string text
Definition: mailmessage.h:53
bool expired
Definition: mailmessage.h:60
std::string title
Definition: mailqueue.h:44
int64_t money
Definition: mailqueue.h:46
std::string body
Definition: mailqueue.h:45
MailQueueTypeT type
Definition: mailqueue.h:47
std::string to
Definition: mailqueue.h:43