mail.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/nullpo.h"
  4. #include "../common/showmsg.h"
  5. #include "../common/strlib.h"
  6. #include "mail.h"
  7. #include "atcommand.h"
  8. #include "itemdb.h"
  9. #include "clif.h"
  10. #include "pc.h"
  11. #include "log.h"
  12. #include "intif.h"
  13. #include <time.h>
  14. #include <string.h>
  15. void mail_clear(struct map_session_data *sd)
  16. {
  17. sd->mail.nameid = 0;
  18. sd->mail.index = 0;
  19. sd->mail.amount = 0;
  20. sd->mail.zeny = 0;
  21. return;
  22. }
  23. int mail_removeitem(struct map_session_data *sd, short flag)
  24. {
  25. nullpo_ret(sd);
  26. if( sd->mail.amount )
  27. {
  28. if (flag) // Item send
  29. pc_delitem(sd, sd->mail.index, sd->mail.amount, 1, 0, LOG_TYPE_MAIL);
  30. else
  31. clif_additem(sd, sd->mail.index, sd->mail.amount, 0);
  32. }
  33. sd->mail.nameid = 0;
  34. sd->mail.index = 0;
  35. sd->mail.amount = 0;
  36. return 1;
  37. }
  38. int mail_removezeny(struct map_session_data *sd, short flag)
  39. {
  40. nullpo_ret(sd);
  41. if (flag && sd->mail.zeny > 0)
  42. { //Zeny send
  43. pc_payzeny(sd,sd->mail.zeny,LOG_TYPE_MAIL, NULL);
  44. }
  45. sd->mail.zeny = 0;
  46. return 1;
  47. }
  48. /**
  49. * Attempt to set item or zeny
  50. * @param sd
  51. * @param idx 0 - Zeny; >= 2 - Inventory item
  52. * @param amount
  53. * @return True if item/zeny can be set, False if failed
  54. */
  55. bool mail_setitem(struct map_session_data *sd, short idx, int amount) {
  56. if( pc_istrading(sd) )
  57. return false;
  58. if( idx == 0 ) { // Zeny Transfer
  59. if( !pc_can_give_items(sd) )
  60. return false;
  61. if( amount > sd->status.zeny )
  62. amount = sd->status.zeny;
  63. sd->mail.zeny = amount;
  64. // clif_updatestatus(sd, SP_ZENY);
  65. return true;
  66. } else { // Item Transfer
  67. idx -= 2;
  68. mail_removeitem(sd, 0);
  69. if( idx < 0 || idx >= MAX_INVENTORY )
  70. return false;
  71. if( amount > sd->status.inventory[idx].amount )
  72. return false;
  73. if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time
  74. || !itemdb_available(sd->status.inventory[idx].nameid)
  75. || !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd))
  76. || (sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) )
  77. return false;
  78. sd->mail.index = idx;
  79. sd->mail.nameid = sd->status.inventory[idx].nameid;
  80. sd->mail.amount = amount;
  81. return true;
  82. }
  83. }
  84. bool mail_setattachment(struct map_session_data *sd, struct mail_message *msg)
  85. {
  86. int n;
  87. nullpo_retr(false,sd);
  88. nullpo_retr(false,msg);
  89. if( sd->mail.zeny < 0 || sd->mail.zeny > sd->status.zeny )
  90. return false;
  91. n = sd->mail.index;
  92. if( sd->mail.amount )
  93. {
  94. if( sd->status.inventory[n].nameid != sd->mail.nameid )
  95. return false;
  96. if( sd->status.inventory[n].amount < sd->mail.amount )
  97. return false;
  98. if( sd->weight > sd->max_weight )
  99. return false;
  100. memcpy(&msg->item, &sd->status.inventory[n], sizeof(struct item));
  101. msg->item.amount = sd->mail.amount;
  102. }
  103. else
  104. memset(&msg->item, 0x00, sizeof(struct item));
  105. msg->zeny = sd->mail.zeny;
  106. // Removes the attachment from sender
  107. mail_removeitem(sd,1);
  108. mail_removezeny(sd,1);
  109. return true;
  110. }
  111. void mail_getattachment(struct map_session_data* sd, int zeny, struct item* item)
  112. {
  113. if( item->nameid > 0 && item->amount > 0 )
  114. {
  115. pc_additem(sd, item, item->amount, LOG_TYPE_MAIL);
  116. clif_Mail_getattachment(sd->fd, 0);
  117. }
  118. if( zeny > 0 )
  119. { //Zeny receive
  120. pc_getzeny(sd, zeny,LOG_TYPE_MAIL, NULL);
  121. }
  122. }
  123. int mail_openmail(struct map_session_data *sd)
  124. {
  125. nullpo_ret(sd);
  126. if( sd->state.storage_flag || sd->state.vending || sd->state.buyingstore || sd->state.trading )
  127. return 0;
  128. clif_Mail_window(sd->fd, 0);
  129. return 1;
  130. }
  131. void mail_deliveryfail(struct map_session_data *sd, struct mail_message *msg)
  132. {
  133. nullpo_retv(sd);
  134. nullpo_retv(msg);
  135. if( msg->item.amount > 0 )
  136. {
  137. // Item receive (due to failure)
  138. pc_additem(sd, &msg->item, msg->item.amount, LOG_TYPE_MAIL);
  139. }
  140. if( msg->zeny > 0 )
  141. {
  142. pc_getzeny(sd,msg->zeny,LOG_TYPE_MAIL, NULL); //Zeny receive (due to failure)
  143. }
  144. clif_Mail_send(sd->fd, true);
  145. }
  146. // This function only check if the mail operations are valid
  147. bool mail_invalid_operation(struct map_session_data *sd)
  148. {
  149. if( !map[sd->bl.m].flag.town && !pc_can_use_command(sd, "mail", COMMAND_ATCOMMAND) )
  150. {
  151. ShowWarning("clif_parse_Mail: char '%s' trying to do invalid mail operations.\n", sd->status.name);
  152. return true;
  153. }
  154. return false;
  155. }
  156. /**
  157. * Attempt to send mail
  158. * @param sd Sender
  159. * @param dest_name Destination name
  160. * @param title Mail title
  161. * @param body_msg Mail message
  162. * @param body_len Message's length
  163. */
  164. void mail_send(struct map_session_data *sd, const char *dest_name, const char *title, const char *body_msg, int body_len) {
  165. struct mail_message msg;
  166. nullpo_retv(sd);
  167. if( sd->state.trading )
  168. return;
  169. if( DIFF_TICK(sd->cansendmail_tick, gettick()) > 0 ) {
  170. clif_displaymessage(sd->fd,msg_txt(sd,675)); //"Cannot send mails too fast!!."
  171. clif_Mail_send(sd->fd, true); // fail
  172. return;
  173. }
  174. if( body_len > MAIL_BODY_LENGTH )
  175. body_len = MAIL_BODY_LENGTH;
  176. if( !mail_setattachment(sd, &msg) ) { // Invalid Append condition
  177. clif_Mail_send(sd->fd, true); // fail
  178. mail_removeitem(sd,0);
  179. mail_removezeny(sd,0);
  180. return;
  181. }
  182. msg.id = 0; // id will be assigned by charserver
  183. msg.send_id = sd->status.char_id;
  184. msg.dest_id = 0; // will attempt to resolve name
  185. safestrncpy(msg.send_name, sd->status.name, NAME_LENGTH);
  186. safestrncpy(msg.dest_name, (char*)dest_name, NAME_LENGTH);
  187. safestrncpy(msg.title, (char*)title, MAIL_TITLE_LENGTH);
  188. if (msg.title[0] == '\0') {
  189. return; // Message has no length and somehow client verification was skipped.
  190. }
  191. if (body_len)
  192. safestrncpy(msg.body, (char*)body_msg, body_len + 1);
  193. else
  194. memset(msg.body, 0x00, MAIL_BODY_LENGTH);
  195. msg.timestamp = time(NULL);
  196. if( !intif_Mail_send(sd->status.account_id, &msg) )
  197. mail_deliveryfail(sd, &msg);
  198. sd->cansendmail_tick = gettick() + battle_config.mail_delay; // Flood Protection
  199. }