123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /* Copyright (C) All Rights Reserved
- ** Written by Gottem <support@gottem.nl>
- ** Website: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods
- ** License: https://gitgud.malvager.net/Wazakindjes/unrealircd_mods/raw/master/LICENSE
- */
- // One include for all cross-platform compatibility thangs
- #include "unrealircd.h"
- // Config block
- #define MYCONF "mafiareturns"
- #define MCHAN_DELIMS ", \t"
- // Commands to override
- #define OVR_NICK "NICK"
- #define OVR_PART "PART"
- // Quality fowod declarations
- unsigned short int mafiareturns_matchnick(aClient *sptr);
- int mafiareturns_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
- int mafiareturns_configposttest(int *errs); // You may not need this
- int mafiareturns_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
- static int mafiareturns_nick_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
- static int mafiareturns_part_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
- // Muh globals
- static ModuleInfo *mafiaMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
- Cmdoverride *mafiaNickOVR, *mafiaPartOVR; // Pointers to the overrides we're gonna add
- // Big hecks go here
- typedef struct t_mafiachan MChan;
- struct t_mafiachan {
- char *name;
- MChan *next;
- };
- struct {
- MChan *channels; // List of channels to "protect"
- char *tag; // If the nick ends/starts with this, we gotta do some shit
- char position; // 'f'ront and 'b'ack lol
- unsigned int num_chans; // How many chans we got
- // These are just for setting to 0 or 1 to see if we got em config directives ;]
- unsigned short int got_channels;
- unsigned short int got_tag;
- unsigned short int got_position;
- } muhcfg;
- // Dat dere module header
- ModuleHeader MOD_HEADER(m_mafiareturns) = {
- "m_mafiareturns", // Module name
- "$Id: v1.0 2018/01/11 Gottem$", // Version
- "Improves MafiaReturns chat functionality", // Description
- "3.2-b8-1", // Modversion, not sure wat do
- NULL
- };
- // Configuration testing-related hewks go in testing phase obv
- MOD_TEST(m_mafiareturns) {
- // We have our own config block so we need to checkem config obv m9
- // Priorities don't really matter here
- HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, mafiareturns_configtest);
- HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, mafiareturns_configposttest);
- return MOD_SUCCESS;
- }
- // Initialisation routine (register hooks, commands and modes or create structs etc)
- MOD_INIT(m_mafiareturns) {
- mafiaMI = modinfo; // Store module info yo
- HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, mafiareturns_configrun);
- return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
- }
- MOD_LOAD(m_mafiareturns) {
- // Attempt to add command overrides
- mafiaNickOVR = CmdoverrideAdd(mafiaMI->handle, OVR_NICK, mafiareturns_nick_override);
- mafiaPartOVR = CmdoverrideAdd(mafiaMI->handle, OVR_PART, mafiareturns_part_override);
- // Check if module handle is available, also check for commands/hooks/overrides that weren't added for some raisin
- if(ModuleGetError(mafiaMI->handle) != MODERR_NOERROR || !mafiaNickOVR || !mafiaPartOVR) {
- // Display error string kek
- config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_mafiareturns).name, ModuleGetErrorStr(mafiaMI->handle));
- return MOD_FAILED; // No good
- }
- return MOD_SUCCESS; // We good
- }
- // Called on unload/rehash obv
- MOD_UNLOAD(m_mafiareturns) {
- MChan *chan; // Iterat0r
- if(muhcfg.num_chans) { // inb4rip
- // This shit is a bit convoluted to prevent memory issues obv famalmalmalmlmalm
- while((chan = muhcfg.channels) != NULL) {
- muhcfg.channels = muhcfg.channels->next;
- if(chan->name) free(chan->name);
- free(chan);
- }
- muhcfg.channels = NULL; // Let's be explicit lol
- }
- muhcfg.num_chans = 0; // Just to maek shur
- if(muhcfg.tag) // inb4rip
- free(muhcfg.tag); // Let's free this lol
- muhcfg.position = 0;
- return MOD_SUCCESS; // We good
- }
- int mafiareturns_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
- int errors = 0; // Error count
- ConfigEntry *cep; // To store the current variable/value pair etc
- char *chanlist, *p, *chname; // Pointurs for checking em chanlist
- // Since we'll add a top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
- if(type != CONFIG_MAIN)
- return 0; // Returning 0 means idgaf bout dis
- // Check for valid config entries first
- if(!ce || !ce->ce_varname)
- return 0;
- // If it isn't our block, idc
- if(strcmp(ce->ce_varname, MYCONF))
- return 0;
- // Loop dat shyte fam
- for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
- // Do we even have a valid name l0l?
- if(!cep->ce_varname) {
- config_error("%s:%i: blank %s item", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF); // Rep0t error
- errors++; // Increment err0r count fam
- continue; // Next iteration imo tbh
- }
- if(!cep->ce_vardata || !strlen(cep->ce_vardata)) {
- config_error("%s:%i: blank value for %s::%s", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname); // Rep0t error
- errors++; // Increment err0r count fam
- continue; // Next iteration imo tbh
- }
- if(!strcmp(cep->ce_varname, "channels")) {
- chanlist = strdup(cep->ce_vardata); // Clone em
- // And czech em
- for(chname = strtoken(&p, chanlist, MCHAN_DELIMS); chname; chname = strtoken(&p, NULL, MCHAN_DELIMS)) {
- if(*chname != '#') {
- 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
- errors++;
- continue;
- }
- if(strlen(chname) > CHANNELLEN) {
- 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);
- errors++;
- continue;
- }
- }
- free(chanlist);
- if(!errors)
- muhcfg.got_channels = 1;
- continue;
- }
- if(!strcmp(cep->ce_varname, "tag")) {
- muhcfg.got_tag = 1;
- continue;
- }
- if(!strcmp(cep->ce_varname, "position")) {
- if(strcmp(cep->ce_vardata, "front") && strcmp(cep->ce_vardata, "back")) {
- 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
- errors++;
- continue;
- }
- muhcfg.got_position = 1;
- continue;
- }
- // Anything else is unknown to us =]
- 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
- }
- *errs = errors;
- return errors ? -1 : 1; // Returning 1 means "all good", -1 means we shat our panties
- }
- // Post test, check for missing shit here
- int mafiareturns_configposttest(int *errs) {
- int errors = 0;
- if(!muhcfg.got_channels) {
- config_error("%s: %s::channels is empty/invalid, aborting module load", MOD_HEADER(m_mafiareturns).name, MYCONF);
- errors++;
- }
- if(!muhcfg.got_tag) {
- config_error("%s: %s::tag is empty/invalid, aborting module load", MOD_HEADER(m_mafiareturns).name, MYCONF);
- errors++;
- }
- if(!muhcfg.got_position) {
- config_warn("%s: %s::position is empty/invalid, defaulting to 'back'", MOD_HEADER(m_mafiareturns).name, MYCONF);
- muhcfg.position = 'b';
- }
- *errs = errors;
- return errors ? -1 : 1;
- }
- // "Run" the config (everything should be valid at this point)
- int mafiareturns_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
- ConfigEntry *cep; // To store the current variable/value pair etc
- char *chanlist, *p, *chname; // Pointurs for checking em chanlist
- MChan *last = NULL; // Initialise to NULL so the loop requires minimal l0gic
- MChan **chan = &muhcfg.channels; // Hecks so the ->next chain stays intact
- // Since we'll add a top-level block to unrealircd.conf, need to filter on CONFIG_MAIN lmao
- if(type != CONFIG_MAIN)
- return 0; // Returning 0 means idgaf bout dis
- // Check for valid config entries first
- if(!ce || !ce->ce_varname)
- return 0;
- // If it isn't mafiareturns, idc
- if(strcmp(ce->ce_varname, MYCONF))
- return 0;
- // Loop dat shyte fam
- for(cep = ce->ce_entries; cep; cep = cep->ce_next) {
- // Do we even have a valid name and val00 l0l?
- if(!cep->ce_varname || !cep->ce_vardata || !strlen(cep->ce_vardata))
- continue; // Next iteration imo tbh
- if(!strcmp(cep->ce_varname, "channels")) {
- chanlist = strdup(cep->ce_vardata); // Clone em
- for(chname = strtoken(&p, chanlist, MCHAN_DELIMS); chname; chname = strtoken(&p, NULL, MCHAN_DELIMS)) {
- size_t chanlen = sizeof(char) * (strlen(chname) + 1);
- // Allocate mem0ry for the current entry
- *chan = malloc(sizeof(MChan));
- // Allocate/initialise shit here
- (*chan)->name = malloc(chanlen);
- (*chan)->next = NULL;
- // Copy that shit fam
- strncpy((*chan)->name, chname, chanlen);
- // Premium linked list fam
- if(last)
- last->next = *chan;
- last = *chan;
- chan = &(*chan)->next;
- }
- free(chanlist);
- continue;
- }
- if(!strcmp(cep->ce_varname, "tag")) {
- muhcfg.tag = strdup(cep->ce_vardata);
- continue;
- }
- if(!strcmp(cep->ce_varname, "position")) {
- muhcfg.position = cep->ce_vardata[0];
- continue;
- }
- }
- return 1; // We good
- }
- unsigned short int mafiareturns_matchnick(aClient *sptr) {
- size_t taglen; // Length of el taggerino y0
- if(!sptr || !MyClient(sptr) || !IsPerson(sptr) || IsULine(sptr) || IsOper(sptr)) // Sanity cheqq and exclusions lol
- return 0;
- taglen = strlen(muhcfg.tag);
- if(muhcfg.position == 'f') {
- if(!strncmp(sptr->name, muhcfg.tag, taglen))
- return 1; // got em
- }
- else if(muhcfg.position == 'b') {
- if(!strncmp(sptr->name + strlen(sptr->name) - taglen, muhcfg.tag, taglen))
- return 1; // got em
- }
- return 0; // No match phambly
- }
- // Now for the actual overrides
- static int mafiareturns_nick_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
- /* Gets args: Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]
- **
- ** ovr: Pointer to the override we're attached to
- ** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
- ** sptr: Pointer to user executing command
- ** parc: Amount of arguments (also includes the command in the count)
- ** parv: Contains the actual args, first one starts at parv[1]
- **
- ** So "NICK test" would result in parc = 2 and parv[1] = "test"
- ** Also, parv[0] seems to always be NULL, so better not rely on it fam
- */
- if(!BadPtr(parv[1]) && mafiareturns_matchnick(sptr)) {
- sendnotice(sptr, "*** [mafiareturns] Official accounts may not change their names.");
- return 0; // Stop processing yo
- }
- return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
- }
- static int mafiareturns_part_override(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]) {
- MChan *chan; // Iterat0r
- char *chanlist, *p, *chname; // Pointurs for checking em chanlist
- char partstr[BUFSIZE]; // To rebuild the argument with allowed chans =]
- if(BadPtr(parv[1]) || !mafiareturns_matchnick(sptr)) // No need to do anything lol
- return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
- // Check if tryna part one or more "protected" chans imo
- memset(partstr, '\0', sizeof(partstr));
- chanlist = strdup(parv[1]); // Clone em arg
- for(chname = strtoken(&p, chanlist, MCHAN_DELIMS); chname; chname = strtoken(&p, NULL, MCHAN_DELIMS)) {
- for(chan = muhcfg.channels; chan; chan = chan->next) {
- if(!stricmp(chan->name, chname)) { // Case insensitive match pls
- sendnotice(sptr, "*** [mafiareturns] Official accounts may not part game channels (%s).", chname);
- break;
- }
- }
- if(!chan)
- ircsnprintf(partstr, sizeof(partstr), "%s%s,", partstr, chname); // Allowed to part, always appending comma for maximum laziness ;];]
- }
- free(chanlist); // Free pls
- // Got nething left?
- if(!partstr[0])
- return 0; // Stop processing yo
- parv[1] = partstr; // Replace w/ new argument
- return CallCmdoverride(ovr, cptr, sptr, parc, parv); // Run original function yo
- }
|