[DONE] m_clearlist to clear +bIe lists

Need a module converted from 3.2.x to UnrealIRCd 4? Or looking for a certain module? Ask here.

Moderator: Supporters

Posts: 63
Joined: Fri Aug 19, 2016 5:26 pm

[DONE] m_clearlist to clear +bIe lists

Postby Gottem » Tue Sep 06, 2016 9:19 pm

This module is quite similar to m_rmtkl in that you can clear "ban" lists based on masks with wildcards. So you could use a mask of *!*@` or even just * to clear everything, it's pretty straightforward tbh. =]

Syntax: CLEARLIST <channel> <flags> <mask>

b => ban
e => ban exception
I => invite exception

CLEARLIST #bighek b *
CLEARLIST #ayylmao Ie *!uid*@*
CLEARLIST #ham * *

Git repos ftw, also the most recent version (may look a bit funky due to non-word characters in the help strings):

Code: Select all

// One include for all cross-platform compatibility thangs
#include "unrealircd.h"

// Command string, change this

// Dem macros yo
#define DelCommand(x) if(x) CommandDel(x); x = NULL // For unregistering our command when unloading/rehashing
CMD_FUNC(m_clearlist); // Register command function

// Quality fowod declarations
static int dumpit(aClient *sptr, char **p);

// Muh globals
static ModuleInfo *clearListMI = NULL; // Store ModuleInfo so we can use it to check for errors in MOD_LOAD
Command *clearListCmd; // Pointer to the command we're gonna add

// Store some info about dem dere list types
typedef struct {
   int   type;
   char flag;
} listType;

// Muh array
listType demListTypes[] = {
   { MODE_BAN, 'b' }, // b& obv
   { MODE_EXCEPT, 'e' }, // Ban exceptions y0
   { MODE_INVEX, 'I' }, // Invite exception (invex) m8
   { 0, 0 }, // Just in case, for unknown m0des

// Help string in case someone does just /CLEARLIST
static char *clearListhelp[] = {
   /* Special characters:
   ** STX = bold -- \x02
   ** US = underlined -- \x1F
   "*** Help on /CLEARLIST ***",
   "Allows you to easily clear out ban and exception lists (+b, +e, +I)",
   "Restricted to chanadmins, owners and IRC ops for obvious raisins",
   "    /CLEARLIST channel flag mask",
   "        Wildcards are accepted for flag and mask",
   "    /CLEARLIST #bighek bI *!*@*",
   "        Clear all bans and invexes in #bighek",
   "    /CLEARLIST #bighek b *!uid*@*",
   "        Clear all bans on free IRCCloud accounts",
   "    /CLEARLIST #bighek * *!uid*@*",
   "        Clear +beI lists entirely",

// Dat dere module header
ModuleHeader MOD_HEADER(m_clearlist) = {
   "$Id: v1.0 2016/09/06 $",
   "Adds /CLEARLIST <channel> <types> <mask> command to clear out banlists etc",
   "3.2-b8-1", // Modversion, not sure wat do

// Initialisation routine (register hooks, commands and modes or create structs etc)
MOD_INIT(m_clearlist) {
   // If command already exists for some reason, bail out
   if(CommandExists(MSG_CLEARLIST)) {
      config_error("Command %s already exists", MSG_CLEARLIST);
      return MOD_FAILED;

   clearListCmd = CommandAdd(modinfo->handle, MSG_CLEARLIST, m_clearlist, 3, M_SERVER | M_USER);
   clearListMI = modinfo; // Store module info yo
   return MOD_SUCCESS; // Let MOD_LOAD handle errors

// Actually load the module here (also command overrides as they may not exist in MOD_INIT yet)
MOD_LOAD(m_clearlist) {
   // Did the module throw an error during initialisation, or is clearListCmd null even?
   if(ModuleGetError(clearListMI->handle) != MODERR_NOERROR || !clearListCmd) {
      // Display error string kek
      config_error("A critical error occurred when loading module %s: %s", MOD_HEADER(m_clearlist).name, ModuleGetErrorStr(clearListMI->handle));
      return MOD_FAILED; // No good

   return MOD_SUCCESS; // We good

// Called on unload/rehash obv
MOD_UNLOAD(m_clearlist) {
   DelCommand(clearListCmd); // Attempt to unregister custom command
   return MOD_SUCCESS; // We good

// Dump a NULL-terminated array of strings to user sptr using the numeric rplnum, and then return 0 (taken from DarkFire IRCd)
static int dumpit(aClient *sptr, char **p) {
   for(; *p != NULL; p++)
      sendto_one(sptr, ":%s %03d %s :%s", me.name, RPL_TEXT, sptr->name, *p);

   // Let user take 8 seconds to read it
   sptr->local->since += 8;
   return 0;

CMD_FUNC(m_clearlist) {
   /* Gets args: aClient *cptr, aClient *sptr, int parc, char[] parv
   ** cptr: Pointer to directly attached client -- if remote user this is the remote server instead
   ** sptr: Pointer to user executing command -- you'll probably wanna use this fam
   ** parc: Amount of arguments (also includes the command in the count)
   ** parv: Contains the actual args, first one starts at parv[1]
   ** So "CLEARLIST 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
   Ban **muhList, *ban, *bnext; // Pointer to pointer of banlist, also pointers to ban entries
   listType *ltype; // Pointer to our listType struct
   char flag; // Store current flag/type for dat dere iteration fam
   char *channel, *types, *rawmask; // Pointers to store arguments
   char remflags[MAXMODEPARAMS], remstr[MODEBUFLEN]; // Some buffers to store flags and masks to remove
   aChannel *chptr; // Pointer to channel m8
   int strcount, del; // Keep track of mask counts to do shit like -bbb, also "boolean" to actually delete the list entry

   if(BadPtr(parv[1])) // If first argument is a bad pointer, don't proceed
      return dumpit(sptr, clearListhelp); // Return help string instead

   if(BadPtr(parv[2]) || BadPtr(parv[3])) { // We need 3 args fam
      sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, "CLEARLIST"); // Show "needs more parameters" error string
      return -1; // "Critical" error

   if(parv[1][0] != '#') { // If first character is not a #, this is not a channel
      sendnotice(sptr, "Invalid channel name %s", parv[1]); // So gtfo
      return -1; // "Critical" error

   channel = parv[1]; // Store channel arg
   types = parv[2]; // Store flags arg
   rawmask = parv[3]; // Store n!i@h mask arg
   if(!(chptr = find_channel(channel, NULL))) { // Can we even find the channel?
      sendnotice(sptr, "Channel %s doesn't exist", parv[1]); // Lolnope
      return -1; // Actual critical error

   // Gotta be IRC oper or have +a or +q to use this shit
   if(!IsOper(sptr) && !is_chanownprotop(sptr, chptr) && !is_chanowner(sptr, chptr)) {
      sendnotice(sptr, "You're not allowed to do that (need +a, +q or IRC op status)"); // Ain't gonna happen fam
      return -1; // Actual critical error

   // If types contains a wildcard char, just iterate over all of the supported flags
   if(strchr(types, '*'))
      types = "beI"; // Which are +b, +e and +I

   // Loop over the global array of supported types
   for(ltype = demListTypes; ltype->type; ltype++) {
      flag = ltype->flag; // Get dat flag
      strcount = 0; // Set count to 0
      memset(remflags, 0, sizeof(remflags)); // Reset flags to remove entirely
      memset(remstr, 0, sizeof(remstr)); // Ditto for the masks

      if(!strchr(types, flag)) // Does the given argument match this type's flag?
         continue; // Next flag imo tbh

      // Check what flag this is m9
      switch(flag) {
         // We have **banList so we can actually modify the "live" list, instead of just a shitty copy

         case 'b': // Banned lol
            muhList = &chptr->banlist; // Quality reference

         case 'e': // Ban exception
            muhList = &chptr->exlist; // Ayyyy

         case 'I': // Yay invex
            muhList = &chptr->invexlist; // Lmao

         default: // Just a safeguard imo th
            continue; // Next type

      // Loop over all entries in the current list
      for(ban = *muhList; ban; ban = bnext) {
         del = 0; // Set "boolean" to 0
         bnext = ban->next; // Already get the next entry here, since we may delete the current one
         if(!match(rawmask, ban->banstr)) { // Does the entry's mask match the given arg? (match() does bighek with wildcards)
            remflags[strcount] = flag; // Add this flag to our remflags array
            strcount++; // Increment strcount later cuz muh first char = index 0
            del = 1; // Set dat boolean so we can delete this entry at the end of this iteration

            if(!remstr[0]) // First match this round (muh memset)?
               strlcpy(remstr, ban->banstr, sizeof(remstr)); // Then initialise that shit with the current mask

            // Es not?
            else {
               strlcat(remstr, " ", sizeof(remstr)); // Mite b useful to put a space between masks
               strlcat(remstr, ban->banstr, sizeof(remstr)); // Append actual mask here

         // We'll use at least 5 masks together, until the string length exceeds 150 chars or if we run out of entries
         if((strcount >= 5 && strlen(remstr) >= 150) || !ban->next || strcount >= MAXMODEPARAMS) {
            // Apparently using "* " for mask with active entries results in a weird MODE message
            if(!strchr(remflags, flag)) // So let's skip that shit

            // Apparently this following line is nothing but cosmetic
            sendto_channel_butserv(chptr, &me, ":%s MODE %s -%s %s", sptr->name, channel, remflags, remstr); // Send a MODE message to the channel to notify users
            sendto_server(NULL, 0, 0, ":%s MODE %s -%s %s", sptr->name, channel, remflags, remstr); // Send a MODE message to the server to propagate it through the netwerk

            strcount = 0; // Reset counter
            memset(remflags, 0, sizeof(remflags)); // Reset flags
            memset(remstr, 0, sizeof(remstr)); // Reset masks

         // Actually delete the entry from the IRCd here
            del_listmode(muhList, chptr, ban->banstr); // Good shit fam

   return 0; // All good

Posts: 63
Joined: Fri Aug 19, 2016 5:26 pm

Re: [DONE] m_clearlist to clear +bIe lists

Postby Gottem » Wed Jan 11, 2017 5:57 pm

It also works for removing malformed masks, such as: asf@*, qwerty etc. A lot of people seem to be getting these after upgrading to 4.0.1x. The module already supported it but apparently it didn't quite properly propagate to other servers. It does now. =]

Simply doing /clearlist #chan b kjsdhgjdhfgjhdfg will take care of it, as it will iterate through the ban entries anyways. Any malformed mask will get a special treatment regardless of whether it matches kjsdhgjdhfgjhdfg. ;]

Grab the updated version from the git repo in the OP.

UnrealIRCd head coder
Posts: 1711
Joined: Sat Mar 06, 2004 8:57 pm
Location: .nl

Re: [DONE] m_clearlist to clear +bIe lists

Postby Syzop » Thu Jan 12, 2017 8:55 am

You mean before they upgraded to 4.0.10 ;). With 4.0.10 (starting -rc2) and later these incorrect bans cannot be added. With older versions such as 4.0.9 (and before) there was a bug causing these bans to be added sometimes. In fact, you reported one of the symptoms yourself on the bug tracker with UnrealIRCd 4.0.5 but it was so sporadic that we could not reproduce.

I'm only aware of two reports in our support channel and that one bug report. Useful module, though, I referred those two people to your mod :)
If you know of.. say, more than 10 reports, then let me know, so I know that I should write a bit more elaborate on the subject in the release notes. Would add another reason why people should upgrade to 4.0.10.

Posts: 63
Joined: Fri Aug 19, 2016 5:26 pm

Re: [DONE] m_clearlist to clear +bIe lists

Postby Gottem » Thu Jan 12, 2017 1:39 pm

Well I may have misunderstood the exact issue then. :D It seemed like (partially) upgrading your IRCds to 4.0.1x resulted in these bans. Doesn't really matter though, it's just semantics in the end.

And yeah, I remember that report. :> It still hasn't come back since, we're still on 4.0.5 even (with some of your security patches). I'll keep an eye out for additional reports on IRC. =]

Return to “Modules (3rd party)”

Who is online

Users browsing this forum: No registered users and 1 guest