123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- /* 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 "noghosts"
- // Hewkerino
- #define MYHEWK HOOKTYPE_UMODE_CHANGE
- // Big hecks go here
- typedef struct t_chanstrukk muhchan;
- struct t_chanstrukk {
- char *name;
- muhchan *next;
- };
- // Quality fowod declarations;
- int noghosts_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
- int noghosts_configposttest(int *errs);
- int noghosts_configrun(ConfigFile *cf, ConfigEntry *ce, int type);
- unsigned short int is_chan_monitored(char *chname);
- int noghosts_hook_chumode(aClient *sptr, long oldflags, long newflags);
- // Muh globals
- static ModuleInfo *noghostsMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
- Hook *noghostsHook = NULL;
- // Muh config shit y0
- struct {
- char *message;
- char *flags;
- muhchan *channels;
- int chancount;
- unsigned short int got_message;
- unsigned short int got_flags;
- } muhcfg;
- // Dat dere module header
- ModuleHeader MOD_HEADER(m_noghosts) = {
- "m_noghosts", // Module name
- "$Id: v1.01 2018/03/02 Gottem$", // Version
- "Keep channels clear of \"ghosts\" of opers", // Description
- "3.2-b8-1", // Modversion, not sure wat do
- NULL
- };
- // Configuration testing-related hewks go in testing phase obv
- MOD_TEST(m_noghosts) {
- // 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, noghosts_configtest);
- HookAdd(modinfo->handle, HOOKTYPE_CONFIGPOSTTEST, 0, noghosts_configposttest);
- return MOD_SUCCESS;
- }
- // Initialisation routine (register hooks, commands and modes or create structs etc)
- MOD_INIT(m_noghosts) {
- noghostsMI = modinfo; // Store module info yo
- HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, noghosts_configrun);
- // Add a hook with priority 0 (i.e. normal) that returns an int
- noghostsHook = HookAdd(modinfo->handle, MYHEWK, 0, noghosts_hook_chumode);
- return MOD_SUCCESS; // Let MOD_LOAD handle errors and registering of overrides
- }
- MOD_LOAD(m_noghosts) {
- // Check if module handle is available, also check for commands/hooks/overrides that weren't added for some raisin
- if(ModuleGetError(noghostsMI->handle) != MODERR_NOERROR || !noghostsHook) {
- // Display error string kek
- config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_noghosts).name, ModuleGetErrorStr(noghostsMI->handle));
- return MOD_FAILED; // No good
- }
- return MOD_SUCCESS; // We good
- }
- // Called on unload/rehash obv
- MOD_UNLOAD(m_noghosts) {
- // Clean up any structs and other shit here
- if(muhcfg.message) {
- free(muhcfg.message);
- muhcfg.message = NULL;
- }
- if(muhcfg.flags) {
- free(muhcfg.flags);
- muhcfg.flags = NULL;
- }
- if(muhcfg.channels) {
- // This shit is a bit convoluted to prevent memory issues obv famalmalmalmlmalm
- muhchan *ch;
- while((ch = muhcfg.channels) != NULL) {
- muhcfg.channels = muhcfg.channels->next;
- if(ch->name) free(ch->name);
- free(ch);
- }
- muhcfg.channels = NULL;
- }
- muhcfg.chancount = 0;
- return MOD_SUCCESS; // We good
- }
- int noghosts_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) {
- int errors = 0; // Error count
- ConfigEntry *cep, *cep2; // To store the current variable/value pair etc, nested
- // 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(!strcmp(cep->ce_varname, "flags")) {
- if(!cep->ce_vardata || !strlen(cep->ce_vardata)) {
- config_error("%s:%i: %s::%s must be non-empty fam", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
- errors++; // Increment err0r count fam
- continue;
- }
- if(strcmp(cep->ce_vardata, "O")) {
- config_error("%s:%i: %s::%s must be one of: O", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
- errors++; // Increment err0r count fam
- continue;
- }
- muhcfg.got_flags = 1;
- continue;
- }
- if(!strcmp(cep->ce_varname, "message")) {
- if(!cep->ce_vardata || !strlen(cep->ce_vardata)) {
- config_error("%s:%i: %s::%s must be non-empty fam", cep->ce_fileptr->cf_filename, cep->ce_varlinenum, MYCONF, cep->ce_varname);
- errors++; // Increment err0r count fam
- continue;
- }
- muhcfg.got_message = 1;
- continue;
- }
- // Here comes a nested block =]
- if(!strcmp(cep->ce_varname, "channels")) {
- // Loop 'em again
- for(cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next) {
- if(!cep2->ce_varname || !strlen(cep2->ce_varname)) {
- config_error("%s:%i: blank %s::%s item", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, MYCONF, cep->ce_varname); // Rep0t error
- errors++; // Increment err0r count fam
- continue; // Next iteration imo tbh
- }
- if(cep2->ce_varname[0] != '#') {
- config_error("%s:%i: invalid channel name '%s': must start with #", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep2->ce_varname); // Rep0t error
- errors++; // Increment err0r count fam
- continue; // Next iteration imo tbh
- }
- if(strlen(cep2->ce_varname) > CHANNELLEN) {
- config_error("%s:%i: invalid channel name '%s': must not exceed %d characters in length", cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep2->ce_varname, CHANNELLEN);
- errors++; // Increment err0r count fam
- continue; // Next iteration imo tbh
- }
- muhcfg.chancount++;
- }
- 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 noghosts_configposttest(int *errs) {
- int errors = 0;
- if(!muhcfg.got_flags)
- muhcfg.flags = strdup("O");
- if(!muhcfg.got_message) // I may remove/change this when more flags are used ;]
- muhcfg.message = strdup("Opered down");
- *errs = errors;
- return errors ? -1 : 1;
- }
- // "Run" the config (everything should be valid at this point)
- int noghosts_configrun(ConfigFile *cf, ConfigEntry *ce, int type) {
- ConfigEntry *cep, *cep2; // To store the current variable/value pair etc, nested
- muhchan *last = NULL; // Initialise to NULL so the loop requires minimal l0gic
- muhchan **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 noghosts, 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)
- continue; // Next iteration imo tbh
- if(!strcmp(cep->ce_varname, "flags")) {
- if(muhcfg.flags)
- free(muhcfg.flags);
- muhcfg.flags = strdup(cep->ce_vardata);
- continue;
- }
- if(!strcmp(cep->ce_varname, "message")) {
- if(muhcfg.message)
- free(muhcfg.message);
- muhcfg.message = strdup(cep->ce_vardata);
- continue;
- }
- // Nesting
- if(!strcmp(cep->ce_varname, "channels")) {
- // Loop 'em
- for(cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next) {
- if(!cep2->ce_varname)
- continue; // Next iteration imo tbh
- // Gotta get em length yo
- size_t namelen = sizeof(char) * (strlen(cep2->ce_varname) + 1);
- // Allocate mem0ry for the current entry
- *chan = malloc(sizeof(muhchan));
- // Allocate/initialise shit here
- (*chan)->name = malloc(namelen);
- (*chan)->next = NULL;
- // Copy that shit fam
- strncpy((*chan)->name, cep2->ce_varname, namelen);
- // Premium linked list fam
- if(last)
- last->next = *chan;
- last = *chan;
- chan = &(*chan)->next;
- }
- continue;
- }
- }
- return 1; // We good
- }
- unsigned short int is_chan_monitored(char *chname) {
- muhchan *chan;
- if(!muhcfg.chancount) // No channels specified = default to all ;]
- return 1;
- // Checkem configured channels nao
- for(chan = muhcfg.channels; chan; chan = chan->next) {
- if(!stricmp(chan->name, chname))
- return 1;
- }
- return 0;
- }
- // Actual hewk functions m8
- int noghosts_hook_chumode(aClient *sptr, long oldflags, long newflags) {
- Membership *lp, *next;
- char *parv[4];
- // Don't bother with remote clients or if flags r set but don't contain O ;];]
- if(!MyConnect(sptr) || (muhcfg.flags && !strchr(muhcfg.flags, 'O')))
- return HOOK_CONTINUE;
- // CHECK OPER DOWN LOL
- if((oldflags & UMODE_OPER) && !(newflags & UMODE_OPER)) {
- for(lp = sptr->user->channel; lp; lp = next) {
- next = lp->next; // Cuz inb4rip linked list after a PART
- // Check for chancount here to save one function call/iteration =]]]
- if(has_channel_mode(lp->chptr, 'O') && (!muhcfg.chancount || is_chan_monitored(lp->chptr->chname))) {
- // Rebuild all parv cuz we prolly should =]
- parv[0] = NULL; // PART
- parv[1] = lp->chptr->chname;
- parv[2] = muhcfg.message;
- parv[3] = NULL; // EOL
- int suppresshack = do_cmd(sptr, sptr, "PART", 3, parv);
- }
- }
- }
- return HOOK_CONTINUE;
- }
|