m_mafiareturns.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. // Config block
  9. #define MYCONF "mafiareturns"
  10. #define MCHAN_DELIMS ", \t"
  11. // Commands to override
  12. #define OVR_NICK "NICK"
  13. #define OVR_PART "PART"
  14. // Quality fowod declarations
  15. unsigned short int mafiareturns_matchnick(aClient *sptr);
  16. int mafiareturns_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
  17. int mafiareturns_configposttest(int *errs); // You may not need this
  18. int mafiareturns_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
  19. static int mafiareturns_nick_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
  20. static int mafiareturns_part_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
  21. // Muh globals
  22. static ModuleInfo *mafiaMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
  23. Cmdoverride *mafiaNickOVR, *mafiaPartOVR; // Pointers to the overrides we're gonna add
  24. // Big hecks go here
  25. typedef struct t_mafiachan MChan;
  26. struct t_mafiachan {
  27. char *name;
  28. MChan *next;
  29. };
  30. struct {
  31. MChan *channels; // List of channels to "protect"
  32. char *tag; // If the nick ends/starts with this, we gotta do some shit
  33. char position; // 'f'ront and 'b'ack lol
  34. unsigned int num_chans; // How many chans we got
  35. // These are just for setting to 0 or 1 to see if we got em config directives ;]
  36. unsigned short int got_channels;
  37. unsigned short int got_tag;
  38. unsigned short int got_position;
  39. } muhcfg;
  40. // Dat dere module header
  41. ModuleHeader MOD_HEADER(m_mafiareturns) = {
  42. "m_mafiareturns", // Module name
  43. "$Id: v1.0 2018/01/11 Gottem$", // Version
  44. "Improves MafiaReturns chat functionality", // Description
  45. "3.2-b8-1", // Modversion, not sure wat do
  46. NULL
  47. };
  48. // Configuration testing-related hewks go in testing phase obv
  49. MOD_TEST(m_mafiareturns) {
  50. // We have our own config block so we need to checkem config obv m9
  51. // Priorities don't really matter here
  52. HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, mafiareturns_configtest);
  53. HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, mafiareturns_configposttest);
  54. return MOD_SUCCESS;
  55. }
  56. // Initialisation routine (register hooks, commands and modes or create structs etc)
  57. MOD_INIT(m_mafiareturns) {
  58. mafiaMI = modinfo; // Store module info yo
  59. HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, mafiareturns_configrun);
  60. return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
  61. }
  62. MOD_LOAD(m_mafiareturns) {
  63. // Attempt to add command overrides
  64. mafiaNickOVR = CmdoverrideAdd(mafiaMI->handle, OVR_NICK, mafiareturns_nick_override);
  65. mafiaPartOVR = CmdoverrideAdd(mafiaMI->handle, OVR_PART, mafiareturns_part_override);
  66. // Check if module handle is available, also check for commands/hooks/overrides that weren't added for some raisin
  67. if(ModuleGetError(mafiaMI->handle) != MODERR_NOERROR || !mafiaNickOVR || !mafiaPartOVR) {
  68. // Display error string kek
  69. config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_mafiareturns).name, ModuleGetErrorStr(mafiaMI->handle));
  70. return MOD_FAILED; // No good
  71. }
  72. return MOD_SUCCESS; // We good
  73. }
  74. // Called on unload/rehash obv
  75. MOD_UNLOAD(m_mafiareturns) {
  76. MChan *chan; // Iterat0r
  77. if(muhcfg.num_chans) { // inb4rip
  78. // This shit is a bit convoluted to prevent memory issues obv famalmalmalmlmalm
  79. while((chan = muhcfg.channels) != NULL) {
  80. muhcfg.channels = muhcfg.channels->next;
  81. if(chan->name) free(chan->name);
  82. free(chan);
  83. }
  84. muhcfg.channels = NULL; // Let's be explicit lol
  85. }
  86. muhcfg.num_chans = 0; // Just to maek shur
  87. if(muhcfg.tag) // inb4rip
  88. free(muhcfg.tag); // Let's free this lol
  89. muhcfg.position = 0;
  90. return MOD_SUCCESS; // We good
  91. }
  92. int mafiareturns_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
  93. int errors = 0; // Error count
  94. ConfigEntry *cep; // To store the current variable/value pair etc
  95. char *chanlist, *p, *chname; // Pointurs for checking em chanlist
  96. // Since we'll add a top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
  97. if(type != CONFIG_MAIN)
  98. return 0; // Returning 0 means idgaf bout dis
  99. // Check for valid config entries first
  100. if(!ce || !ce->ce_varname)
  101. return 0;
  102. // If it isn't our block, idc
  103. if(strcmp(ce->ce_varname, MYCONF))
  104. return 0;
  105. // Loop dat shyte fam
  106. for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
  107. // Do we even have a valid name l0l?
  108. if(!cep->ce_varname) {
  109. config_error("%s:%i: blank %s item", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF); // Rep0t error
  110. errors++; // Increment err0r count fam
  111. continue; // Next iteration imo tbh
  112. }
  113. if(!cep->ce_vardata || !strlen(cep->ce_vardata)) {
  114. config_error("%s:%i: blank value for %s::%s", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname); // Rep0t error
  115. errors++; // Increment err0r count fam
  116. continue; // Next iteration imo tbh
  117. }
  118. if(!strcmp(cep->ce_varname, "channels")) {
  119. chanlist = strdup(cep->ce_vardata); // Clone em
  120. // And czech em
  121. for(chname = strtoken(&p, chanlist, MCHAN_DELIMS); chname; chname = strtoken(&p, NULL, MCHAN_DELIMS)) {
  122. if(*chname != '#') {
  123. config_warn("%s:%i: invalid value '%s' for %s::%s (must start with #)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, chname, MYCONF, cep->ce_varname); // Rep0t error
  124. errors++;
  125. continue;
  126. }
  127. if(strlen(chname) > CHANNELLEN) {
  128. config_warn("%s:%i: invalid value '%s' for %s::%s (channel names may be up to %d characters long)", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, chname, MYCONF, cep->ce_varname, CHANNELLEN);
  129. errors++;
  130. continue;
  131. }
  132. }
  133. free(chanlist);
  134. if(!errors)
  135. muhcfg.got_channels = 1;
  136. continue;
  137. }
  138. if(!strcmp(cep->ce_varname, "tag")) {
  139. muhcfg.got_tag = 1;
  140. continue;
  141. }
  142. if(!strcmp(cep->ce_varname, "position")) {
  143. if(strcmp(cep->ce_vardata, "front") && strcmp(cep->ce_vardata, "back")) {
  144. config_warn("%s:%i: value for %s::%s must be either 'front' or 'back'", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname); // Rep0t error
  145. errors++;
  146. continue;
  147. }
  148. muhcfg.got_position = 1;
  149. continue;
  150. }
  151. // Anything else is unknown to us =]
  152. config_warn("%s:%i: unknown item %s::%s", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname); // So display just a warning
  153. }
  154. *errs = errors;
  155. return errors ? -1 : 1; // Returning 1 means "all good", -1 means we shat our panties
  156. }
  157. // Post test, check for missing shit here
  158. int mafiareturns_configposttest(int *errs) {
  159. int errors = 0;
  160. if(!muhcfg.got_channels) {
  161. config_error("%s: %s::channels is empty/invalid, aborting module load", MOD_HEADER(m_mafiareturns).name, MYCONF);
  162. errors++;
  163. }
  164. if(!muhcfg.got_tag) {
  165. config_error("%s: %s::tag is empty/invalid, aborting module load", MOD_HEADER(m_mafiareturns).name, MYCONF);
  166. errors++;
  167. }
  168. if(!muhcfg.got_position) {
  169. config_warn("%s: %s::position is empty/invalid, defaulting to 'back'", MOD_HEADER(m_mafiareturns).name, MYCONF);
  170. muhcfg.position = 'b';
  171. }
  172. *errs = errors;
  173. return errors ? -1 : 1;
  174. }
  175. // "Run" the config (everything should be valid at this point)
  176. int mafiareturns_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
  177. ConfigEntry *cep; // To store the current variable/value pair etc
  178. char *chanlist, *p, *chname; // Pointurs for checking em chanlist
  179. MChan *last = NULL; // Initialise to NULL so the loop requires minimal l0gic
  180. MChan **chan = &muhcfg.channels; // Hecks so the ->next chain stays intact
  181. // Since we'll add a top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
  182. if(type != CONFIG_MAIN)
  183. return 0; // Returning 0 means idgaf bout dis
  184. // Check for valid config entries first
  185. if(!ce || !ce->ce_varname)
  186. return 0;
  187. // If it isn't mafiareturns, idc
  188. if(strcmp(ce->ce_varname, MYCONF))
  189. return 0;
  190. // Loop dat shyte fam
  191. for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
  192. // Do we even have a valid name and val00 l0l?
  193. if(!cep->ce_varname || !cep->ce_vardata || !strlen(cep->ce_vardata))
  194. continue; // Next iteration imo tbh
  195. if(!strcmp(cep->ce_varname, "channels")) {
  196. chanlist = strdup(cep->ce_vardata); // Clone em
  197. for(chname = strtoken(&p, chanlist, MCHAN_DELIMS); chname; chname = strtoken(&p, NULL, MCHAN_DELIMS)) {
  198. size_t chanlen = sizeof(char) * (strlen(chname) + 1);
  199. // Allocate mem0ry for the current entry
  200. *chan = malloc(sizeof(MChan));
  201. // Allocate/initialise shit here
  202. (*chan)->name = malloc(chanlen);
  203. (*chan)->next = NULL;
  204. // Copy that shit fam
  205. strncpy((*chan)->name, chname, chanlen);
  206. // Premium linked list fam
  207. if(last)
  208. last->next = *chan;
  209. last = *chan;
  210. chan = &(*chan)->next;
  211. }
  212. free(chanlist);
  213. continue;
  214. }
  215. if(!strcmp(cep->ce_varname, "tag")) {
  216. muhcfg.tag = strdup(cep->ce_vardata);
  217. continue;
  218. }
  219. if(!strcmp(cep->ce_varname, "position")) {
  220. muhcfg.position = cep->ce_vardata[0];
  221. continue;
  222. }
  223. }
  224. return 1; // We good
  225. }
  226. unsigned short int mafiareturns_matchnick(aClient *sptr) {
  227. size_t taglen; // Length of el taggerino y0
  228. if(!sptr || !MyClient(sptr) || !IsPerson(sptr) || IsULine(sptr) || IsOper(sptr)) // Sanity cheqq and exclusions lol
  229. return 0;
  230. taglen = strlen(muhcfg.tag);
  231. if(muhcfg.position == 'f') {
  232. if(!strncmp(sptr->name, muhcfg.tag, taglen))
  233. return 1; // got em
  234. }
  235. else if(muhcfg.position == 'b') {
  236. if(!strncmp(sptr->name + strlen(sptr->name) - taglen, muhcfg.tag, taglen))
  237. return 1; // got em
  238. }
  239. return 0; // No match phambly
  240. }
  241. // Now for the actual overrides
  242. static int mafiareturns_nick_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
  243. /* Gets args: Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]
  244. **
  245. ** ovr: Pointer to the override we're attached to
  246. ** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
  247. ** sptr: Pointer to user executing command
  248. ** parc: Amount of arguments (also includes the command in the count)
  249. ** parv: Contains the actual args, first one starts at parv[1]
  250. **
  251. ** So "NICK test" would result in parc = 2 and parv[1] = "test"
  252. ** Also, parv[0] seems to always be NULL, so better not rely on it fam
  253. */
  254. if(!BadPtr(parv[1]) && mafiareturns_matchnick(sptr)) {
  255. sendnotice(sptr, "*** [mafiareturns] Official accounts may not change their names.");
  256. return 0; // Stop processing yo
  257. }
  258. return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
  259. }
  260. static int mafiareturns_part_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
  261. MChan *chan; // Iterat0r
  262. char *chanlist, *p, *chname; // Pointurs for checking em chanlist
  263. char partstr[BUFSIZE]; // To rebuild the argument with allowed chans =]
  264. if(BadPtr(parv[1]) || !mafiareturns_matchnick(sptr)) // No need to do anything lol
  265. return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
  266. // Check if tryna part one or more "protected" chans imo
  267. memset(partstr, '\0', sizeof(partstr));
  268. chanlist = strdup(parv[1]); // Clone em arg
  269. for(chname = strtoken(&p, chanlist, MCHAN_DELIMS); chname; chname = strtoken(&p, NULL, MCHAN_DELIMS)) {
  270. for(chan = muhcfg.channels; chan; chan = chan->next) {
  271. if(!stricmp(chan->name, chname)) { // Case insensitive match pls
  272. sendnotice(sptr, "*** [mafiareturns] Official accounts may not part game channels (%s).", chname);
  273. break;
  274. }
  275. }
  276. if(!chan)
  277. ircsnprintf(partstr, sizeof(partstr), "%s%s,", partstr, chname); // Allowed to part, always appending comma for maximum laziness ;];]
  278. }
  279. free(chanlist); // Free pls
  280. // Got nething left?
  281. if(!partstr[0])
  282. return 0; // Stop processing yo
  283. parv[1] = partstr; // Replace w/ new argument
  284. return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
  285. }