saprivmsg.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* Copyright (C) All Rights Reserved
  2. ** Written by Gottem <support@gottem.nl>
  3. ** Website: https://gottem.nl/unreal
  4. ** License: https://gottem.nl/unreal/license
  5. */
  6. /*** <<<MODULE MANAGER START>>>
  7. module {
  8. documentation "https://gottem.nl/unreal/man/saprivmsg";
  9. troubleshooting "In case of problems, check the FAQ at https://gottem.nl/unreal/halp or e-mail me at support@gottem.nl";
  10. min-unrealircd-version "5.*";
  11. //max-unrealircd-version "5.*";
  12. post-install-text {
  13. "The module is installed, now all you need to do is add a 'loadmodule' line to your config file:";
  14. "loadmodule \"third/saprivmsg\";";
  15. "Then /rehash the IRCd.";
  16. "For usage information, refer to the module's documentation found at: https://gottem.nl/unreal/man/saprivmsg";
  17. }
  18. }
  19. *** <<<MODULE MANAGER END>>>
  20. */
  21. // One include for all cross-platform compatibility thangs
  22. #include "unrealircd.h"
  23. // Command strings
  24. #define MSG_SAPRIVMSG "SAPRIVMSG"
  25. #define MSG_SAPRIVMSG2 "SASAY"
  26. // Dem macros yo
  27. CMD_FUNC(cmd_saprivmsg); // Register command function
  28. #define CheckAPIError(apistr, apiobj) \
  29. do { \
  30. if(!(apiobj)) { \
  31. config_error("A critical error occurred on %s for %s: %s", (apistr), MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle)); \
  32. return MOD_FAILED; \
  33. } \
  34. } while(0)
  35. // Quality fowod declarations
  36. static void dumpit(Client *client, char **p);
  37. // Help string in case someone does just /SAPRIVMSG
  38. static char *halpstr[] = {
  39. /* Special characters:
  40. ** \002 = bold -- \x02
  41. ** \037 = underlined -- \x1F
  42. */
  43. "*** \002Help on /SAPRIVMSG\002 ***",
  44. "Similar to SAJOIN etc, but instead make people say shit (inside channels)",
  45. "It checks if the channel even exists, also if the nick is in thur",
  46. "Syntax:",
  47. " \002/SAPRIVMSG\002 \037target channel/nick\037 \037victim\037 \037message\037",
  48. " I think that pretty much speaks for itself =]",
  49. " There's also a shorter command (same args obv): \002/SASAY\002",
  50. NULL
  51. };
  52. // Dat dere module header
  53. ModuleHeader MOD_HEADER = {
  54. "third/saprivmsg", // Module name
  55. "2.0", // Version
  56. "Similar to SAJOIN etc, but instead make people say shit", // Description
  57. "Gottem", // Author
  58. "unrealircd-5", // Modversion
  59. };
  60. // Initialisation routine (register hooks, commands and modes or create structs etc)
  61. MOD_INIT() {
  62. CheckAPIError("CommandAdd(SAPRIVMSG)", CommandAdd(modinfo->handle, MSG_SAPRIVMSG, cmd_saprivmsg, MAXPARA, CMD_USER));
  63. CheckAPIError("CommandAdd(SASAY)", CommandAdd(modinfo->handle, MSG_SAPRIVMSG2, cmd_saprivmsg, MAXPARA, CMD_USER));
  64. MARK_AS_GLOBAL_MODULE(modinfo);
  65. return MOD_SUCCESS;
  66. }
  67. // Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
  68. MOD_LOAD() {
  69. return MOD_SUCCESS; // We good
  70. }
  71. // Called on unload/rehash obv
  72. MOD_UNLOAD() {
  73. return MOD_SUCCESS; // We good
  74. }
  75. // Dump a NULL-terminated array of strings to the user (taken from DarkFire IRCd)
  76. static void dumpit(Client *client, char **p) {
  77. if(IsServer(client)) // Bail out early and silently if it's a server =]
  78. return;
  79. // Using sendto_one() instead of sendnumericfmt() because the latter strips indentation and stuff ;]
  80. for(; *p != NULL; p++)
  81. sendto_one(client, NULL, ":%s %03d %s :%s", me.name, RPL_TEXT, client->name, *p);
  82. // Let user take 8 seconds to read it
  83. client->local->since += 8;
  84. }
  85. CMD_FUNC(cmd_saprivmsg) {
  86. // Gets args: Client *client, MessageTag *recv_mtags, int parc, char *parv[]
  87. char *msg; // We'll just let Unreal handle the limit for this one
  88. char *target; // Get either the target channel or client's name for quikk axx
  89. Client *victim; // Client pointer for the "sayer"
  90. Client *acptr; // Muh target client
  91. Channel *channel; // Muh target channel
  92. int i; // iter8or
  93. size_t len; // Message length kek
  94. if(!ValidatePermissionsForPath("saprivmsg", client, NULL, NULL, NULL)) {
  95. sendnumeric(client, ERR_NOPRIVILEGES); // Check ur privilege fam
  96. return; // No good
  97. }
  98. if(BadPtr(parv[1])) { // If first argument is a bad pointer, don't proceed and return halp instead
  99. dumpit(client, halpstr); // Return help string instead
  100. return;
  101. }
  102. // Need more args lol
  103. if(BadPtr(parv[2]) || BadPtr(parv[3]) || !strlen(parv[3])) {
  104. sendnumeric(client, ERR_NEEDMOREPARAMS, MSG_SAPRIVMSG); // Show "needs more parameters" error string
  105. return; // "Critical" error
  106. }
  107. // Attempt to find da target chanul/nick
  108. acptr = NULL;
  109. channel = NULL;
  110. if(*parv[1] != '#') {
  111. // Attempt to find da niqq
  112. if(!(acptr = find_person(parv[1], NULL))) {
  113. sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
  114. return; // Nope
  115. }
  116. if(!IsULine(acptr)) {
  117. sendnotice(client, "*** [%s] No can do, target nick %s must be U-Lined", MSG_SAPRIVMSG, acptr->name);
  118. return; // Nope
  119. }
  120. }
  121. else {
  122. if(!(channel = find_channel(parv[1], NULL))) {
  123. sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]);
  124. return; // Nope
  125. }
  126. }
  127. target = (channel ? channel->chname : acptr->name);
  128. // Attempt to find da niqq
  129. if(!(victim = find_person(parv[2], NULL))) {
  130. sendnumeric(client, ERR_NOSUCHNICK, parv[2]);
  131. return; // Nope
  132. }
  133. // Disallow cab00sing of opers and U-Lines lol
  134. if(IsOper(victim) || IsULine(victim)) {
  135. sendnotice(client, "*** [%s] No can do, victim nick %s is U-Lined or an IRC oper", MSG_SAPRIVMSG, victim->name);
  136. return; // Kbai
  137. }
  138. // Victim on channel?
  139. if(channel && !find_membership_link(victim->user->channel, channel)) {
  140. sendnumeric(client, ERR_USERNOTINCHANNEL, victim->name, channel->chname);
  141. return; // Nope
  142. }
  143. // Create one pointer from parv[] args kek
  144. msg = NULL;
  145. for(i = 3, len = 0; i < parc; i++) {
  146. len += strlen(parv[i]);
  147. if(i == 3) {
  148. msg = safe_alloc((len + 1) * sizeof(char));
  149. strncpy(msg, parv[i], len);
  150. }
  151. else {
  152. msg = realloc(msg, (++len + 1) * sizeof(char));
  153. strncat(msg, " ", len);
  154. strncat(msg, parv[i], len);
  155. }
  156. msg[len] = '\0'; // Yay dirty
  157. }
  158. // If not our local client, pass it on to the "home server"
  159. if(!MyConnect(victim))
  160. sendto_one(victim->srvptr, NULL, ":%s %s %s %s %s", client->name, MSG_SAPRIVMSG, target, victim->name, msg);
  161. // Is een loqal client, proceed
  162. else {
  163. // Fix up parv[] array
  164. parv[2] = msg; // Msg is just one arg due to a magic colon (PRIVMSG #chan :this is a message)
  165. parv[3] = NULL; // Required
  166. do_cmd(victim, NULL, "PRIVMSG", 3, parv);
  167. sendto_one(victim, NULL, ":%s PRIVMSG %s :%s", victim->name, target, msg); // Send PRIVMSG back to target, required so they can see it too
  168. sendto_snomask_global(SNO_EYES, "*** %s (%s@%s) used %s %s %s :%s", client->name, client->user->username, client->user->realhost, MSG_SAPRIVMSG, target, victim->name, msg);
  169. }
  170. safe_free(msg); // Ayyyy
  171. }