m_anti_amsg.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* Copyright (C) All Rights Reserved
  2. ** Written by Gottem <support@gottem.nl>
  3. ** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
  4. ** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
  5. */
  6. // One include for all cross-platform compatibility thangs
  7. #include "unrealircd.h"
  8. // Command to override
  9. #define OVR_MYCMD "PRIVMSG"
  10. // Muh macros
  11. #define IsMDErr(x, y, z) \
  12. do { \
  13. if(!(x)) { \
  14. config_error("A critical error occurred when registering ModData for %s: %s", MOD_HEADER(y).name, ModuleGetErrorStr((z)->handle)); \
  15. return MOD_FAILED; \
  16. } \
  17. } while(0)
  18. // Big hecks go here
  19. typedef struct t_amsgInfo amsgInfo;
  20. struct t_amsgInfo {
  21. char *target;
  22. char *body;
  23. long tiem;
  24. };
  25. // Quality fowod declarations
  26. void anti_amsg_free(ModData *md);
  27. static int anti_amsg_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
  28. // Muh globals
  29. static ModuleInfo *amsgMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
  30. Cmdoverride *amsgOVR; // Pointer to the override we're gonna add
  31. ModDataInfo *amsgMDI; // To store every user's last message with their client pointer ;3
  32. // Dat dere module header
  33. ModuleHeader MOD_HEADER(m_anti_amsg) = {
  34. "m_anti_amsg", // Module name
  35. "$Id: v1.03 2019/01/06 Gottem$", // Version
  36. "Drop messages originating from /amsg", // Description
  37. "3.2-b8-1", // Modversion, not sure wat do
  38. NULL
  39. };
  40. // Initialisation routine (register hooks, commands and modes or create structs etc)
  41. MOD_INIT(m_anti_amsg) {
  42. amsgMI = modinfo; // Store module info yo
  43. ModDataInfo mreq; // Request that shit
  44. memset(&mreq, 0, sizeof(mreq));
  45. mreq.type = MODDATATYPE_CLIENT; // Apply to users only (CLIENT actually includes servers but we'll disregard that here =])
  46. mreq.name = "amsg_lastmessage"; // Name it
  47. mreq.free = anti_amsg_free; // Function to free 'em
  48. amsgMDI = ModDataAdd(modinfo->handle, mreq);
  49. IsMDErr(amsgMDI, m_anti_amsg, modinfo);
  50. return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
  51. }
  52. // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
  53. MOD_LOAD(m_anti_amsg) {
  54. amsgOVR = CmdoverrideAdd(amsgMI->handle, OVR_MYCMD, anti_amsg_override); // Attempt to add command override
  55. // Did the module throw an error when adding override(s), or is amsgOVR null even?
  56. if(ModuleGetError(amsgMI->handle) != MODERR_NOERROR || !amsgOVR) {
  57. // Display error string kek
  58. config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_anti_amsg).name, ModuleGetErrorStr(amsgMI->handle));
  59. return MOD_FAILED; // No good
  60. }
  61. return MOD_SUCCESS; // We good
  62. }
  63. // Called on unload/rehash obv
  64. MOD_UNLOAD(m_anti_amsg) {
  65. return MOD_SUCCESS; // We good
  66. }
  67. void anti_amsg_free(ModData *md) {
  68. if(md->ptr) {
  69. amsgInfo *amsg = md->ptr;
  70. amsg->tiem = 0;
  71. if(amsg->target)
  72. free(amsg->target);
  73. if(amsg->body)
  74. free(amsg->body);
  75. md->ptr = NULL;
  76. }
  77. }
  78. // Now for the actual override
  79. static int anti_amsg_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
  80. /* Gets args: Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]
  81. **
  82. ** ovr: Pointer to the override we're attached to
  83. ** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
  84. ** sptr: Pointer to user executing command
  85. ** parc: Amount of arguments (also includes the command in the count)
  86. ** parv: Contains the actual args, first one starts at parv[1]
  87. **
  88. ** So "MYCMD test" would result in parc = 2 and parv[1] = "test"
  89. ** Also, parv[0] seems to always be NULL, so better not rely on it fam
  90. */
  91. char *last, *target, *body; // User's last message, accompanying target and stripped body (like colours and shit)
  92. long ltime, tstiem;// Timestamps to go with it
  93. amsgInfo *amsg; // st0re message inf0
  94. size_t targetlen, bodylen; // Lengths to alloc8 the struct vars with in a bit
  95. int bail = 0; // In case we need to droppem but we still need to free some shit before returning
  96. // Inb4duplicate notices =] Also allow U:Lines and servers, just in case
  97. if(parc < 3 || !sptr || !MyConnect(sptr) || IsULine(sptr) || IsServer(sptr) || IsMe(sptr))
  98. return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
  99. // Check for PRIVMSG #chan1,#chan2
  100. if(!BadPtr(parv[1]) && strchr(parv[1], ',')) {
  101. sendnotice(sptr, "*** Multi-target messaging is not allowed");
  102. return 0; // Stop processing yo
  103. }
  104. // Also duplicate messages at the exact same time
  105. if(!BadPtr(parv[2])) {
  106. // Some shitty ass scripts may use different colours/markup across chans, so fuck that
  107. if(!(body = (char *)StripControlCodes(parv[2])))
  108. return CallCmdoverride(ovr, cptr, sptr, parc, parv);
  109. amsg = moddata_client(sptr, amsgMDI).ptr; // Get client data
  110. targetlen = sizeof(char) * (strlen(parv[1]) + 1);
  111. bodylen = sizeof(char) * (strlen(body) + 1);
  112. tstiem = TStime();
  113. target = last = NULL;
  114. // If we have client data (i.e. this is not the first message)
  115. if(amsg) {
  116. target = amsg->target;
  117. last = amsg->body;
  118. ltime = amsg->tiem;
  119. // If 3 seconds have passed since the last message, allow it anyways (in the event of people manually re-sending that shit afterwards)
  120. if(tstiem - ltime > 3)
  121. last = NULL;
  122. }
  123. // Only bail if the current target differs from the last one and the message is the same
  124. if(target && last && ltime && body && strcmp(parv[1], target) && !strcmp(body, last) && ltime <= tstiem) {
  125. sendto_one(sptr, ":%s NOTICE %s :Multi-target messaging is not allowed (%s)", me.name, parv[1], parv[1]);
  126. bail = 1;
  127. }
  128. // This goes after the check cuz cbf fucky pointer hecks =]
  129. if(amsg && amsg->target)
  130. free(amsg->target);
  131. if(amsg && amsg->body)
  132. free(amsg->body);
  133. // Allocate struct mem0ry here
  134. if(!amsg)
  135. amsg = malloc(sizeof(amsgInfo));
  136. // Alloc8 em
  137. amsg->target = malloc(targetlen);
  138. amsg->body = malloc(bodylen);
  139. amsg->tiem = tstiem;
  140. // Copy that shit
  141. strncpy(amsg->target, parv[1], targetlen);
  142. strncpy(amsg->body, body, bodylen);
  143. moddata_client(sptr, amsgMDI).ptr = amsg; // Set client data
  144. }
  145. return bail ? 0 : CallCmdoverride(ovr, cptr, sptr, parc, parv); // Bail or n0 bail?
  146. }