]> jfr.im git - irc/quakenet/newserv.git/blobdiff - glines/glines_commands.c
CHANSERV: fix issue where chanserv_relay doesn't wait for db to be loaded before...
[irc/quakenet/newserv.git] / glines / glines_commands.c
index 8f0ac16faf3d3d5dc9d5bf2f5f8859d0a50c014b..8aae8cb253fa044c52e061073d316d5dc3a52053 100644 (file)
@@ -18,7 +18,7 @@ MODULE_VERSION("");
 static void registercommands(int, void *);
 static void deregistercommands(int, void *);
 
-static int parse_gline_flags(nick *sender, const char *flagparam, int *overridesanity, int *overridelimit, int *simulate, int *coff) {
+static int parse_gline_flags(nick *sender, const char *flagparam, int *overridesanity, int *overridelimit, int *simulate, int *chase, int *coff) {
   const char *pos;
 
   *coff = 0;
@@ -26,6 +26,9 @@ static int parse_gline_flags(nick *sender, const char *flagparam, int *overrides
   *overridelimit = 0;
   *simulate = 0;
 
+  if (chase)
+    *chase = 0;
+
   if (flagparam[0] == '-') {
     *coff = 1;
 
@@ -40,85 +43,123 @@ static int parse_gline_flags(nick *sender, const char *flagparam, int *overrides
        case 'S':
          *simulate = 1;
          break;
+        case 'c':
+          if (!chase)
+            goto invalid;
+
+          *chase = 1;
+          break;
        default:
-         controlreply(sender, "Invalid flag specified: %c", *pos);
-         return 0;
+          goto invalid;
       }
     }
   }
 
   return 1;
+
+invalid:
+  controlreply(sender, "Invalid flag specified: %c", *pos);
+  return 0;
 }
 
 static int glines_cmdblock(void *source, int cargc, char **cargv) {
   nick *sender = source;
-  nick *target;
-  int hits, duration;
-  int coff, overridesanity, overridelimit, simulate;
+  nick *target, *wnp;
+  whowas *ww;
+  int hits, duration, id;
+  int coff, overridesanity, overridelimit, simulate, chase;
   char *reason;
   char creator[128];
   glinebuf gbuf;
+  int ownww;
 
   if (cargc < 1)
     return CMD_USAGE;
 
-  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &coff))
+  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &chase, &coff))
     return CMD_ERROR;
 
   if (cargc < 3 + coff)
     return CMD_USAGE;
 
+  duration = durationtolong(cargv[coff + 1]);
+
+  if (duration <= 0) {
+    controlreply(sender, "Invalid duration specified.");
+    return CMD_ERROR;
+  }
+
   target = getnickbynick(cargv[coff]);
 
   if (!target) {
-    controlreply(sender, "Sorry, couldn't find that user.");
-    return CMD_ERROR;
+    ww = whowas_chase(cargv[coff], 1800);
+   
+    if (!ww) {
+      controlreply(sender, "Sorry, couldn't find that user.");
+      return CMD_ERROR;
+    }
+   
+    ownww = 0;
+
+    controlreply(sender, "Found matching whowas record:");
+    controlreply(sender, "%s", whowas_format(ww));
+  } else {
+    ww = whowas_fromnick(target, 1);
+    ownww = 1;
   }
 
-  duration = durationtolong(cargv[coff + 1]);
+  wnp = &ww->nick;
 
-  if (duration <= 0) {
-    controlreply(sender, "Invalid duration specified.");
+  if (sender != target && (IsService(wnp) || IsOper(wnp) || NickOnServiceServer(wnp))) {
+    controlreply(sender, "Target user '%s' is an oper or a service. Not setting G-Lines.", wnp->nick);
     return CMD_ERROR;
   }
 
   rejoinline(cargv[coff + 2], cargc - coff - 2);
   reason = cargv[coff + 2];
 
-  if (sender->auth)
-    snprintf(creator, sizeof(creator), "#%s", sender->authname);
-  else
-    strncpy(creator, controlid(sender), sizeof(creator));
+  snprintf(creator, sizeof(creator), "#%s", sender->authname);
 
-  glinebufinit(&gbuf, 1);
+  glinebufinit(&gbuf, 0);
   glinebufcommentv(&gbuf, "BLOCK", cargc + coff - 1, cargv);
-  glinebufaddbynick(&gbuf, target, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
+  glinebufaddbywhowas(&gbuf, ww, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
+
+  glinebufspew(&gbuf, sender);
 
-  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit, simulate)) {
+  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
     glinebufabort(&gbuf);
+    if (ownww)
+      whowas_free(ww);
     controlreply(sender, "G-Lines failed sanity checks. Not setting G-Lines.");
     return CMD_ERROR;
   }
 
   if (simulate) {
     glinebufabort(&gbuf);
+    if (ownww)
+      whowas_free(ww);
     controlreply(sender, "Simulation complete. Not setting G-Lines.");
     return CMD_ERROR;
   }
 
-  glinebufcounthits(&gbuf, &hits, NULL, NULL);
-  glinebufcommit(&gbuf, 1);
+  glinebufcounthits(&gbuf, &hits, NULL);
+  id = glinebufcommit(&gbuf, 1);
 
-  controlwall(NO_OPER, NL_GLINES, "%s BLOCK'ed user '%s!%s@%s' for %s with reason '%s' (%d hits)", controlid(sender), target->nick, target->ident, target->host->name->content, longtoduration(duration, 0), reason, hits);
+  controlwall(NO_OPER, NL_GLINES, "%s BLOCK'ed user '%s!%s@%s' for %s with reason '%s' (%d hits)", controlid(sender),
+              wnp->nick, wnp->ident, wnp->host->name->content,
+              longtoduration(duration, 0), reason, hits);
 
-  controlreply(sender, "Done.");
+  if (ownww)
+    whowas_free(ww);
+
+  controlreply(sender, "Done. G-Line transaction ID: %d", id);
 
   return CMD_OK;
 }
 
 static int glines_cmdgline(void *source, int cargc, char **cargv) {
   nick *sender = source;
-  int duration, users, channels;
+  int duration, users, channels, id;
   char *mask, *reason;
   char creator[128];
   int coff, overridesanity, overridelimit, simulate;
@@ -130,7 +171,7 @@ static int glines_cmdgline(void *source, int cargc, char **cargv) {
   if (cargc < 1)
     return CMD_USAGE;
 
-  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &coff))
+  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
     return CMD_ERROR;
 
   if (cargc < 3 + coff)
@@ -162,12 +203,9 @@ static int glines_cmdgline(void *source, int cargc, char **cargv) {
   }
 #endif /* SNIRCD_VERSION */
 
-  if (sender->auth)
-    snprintf(creator, sizeof(creator), "#%s", sender->authname);
-  else
-    strncpy(creator, controlid(sender), sizeof(creator));
+  snprintf(creator, sizeof(creator), "#%s", sender->authname);
 
-  glinebufinit(&gbuf, 1);
+  glinebufinit(&gbuf, 0);
   glinebufcommentv(&gbuf, "GLINE", cargc + coff - 1, cargv);
 
   if (!glinebufadd(&gbuf, mask, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration)) {
@@ -175,7 +213,9 @@ static int glines_cmdgline(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit, simulate)) {
+  glinebufspew(&gbuf, sender);
+
+  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
     glinebufabort(&gbuf);
     controlreply(sender, "G-Lines failed sanity checks. Not setting G-Lines.");
     return CMD_ERROR;
@@ -187,13 +227,13 @@ static int glines_cmdgline(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  glinebufcounthits(&gbuf, &users, &channels, NULL);
-  glinebufcommit(&gbuf, 1);
+  glinebufcounthits(&gbuf, &users, &channels);
+  id = glinebufcommit(&gbuf, 1);
 
   controlwall(NO_OPER, NL_GLINES, "%s GLINE'd mask '%s' for %s with reason '%s' (hits %d users/%d channels)",
     controlid(sender), mask, longtoduration(duration, 0), reason, users, channels);
 
-  controlreply(sender, "Done.");
+  controlreply(sender, "Done. G-Line transaction ID: %d", id);
 
   return CMD_OK;
 }
@@ -206,7 +246,7 @@ static int glines_cmdsmartgline(void *source, int cargc, char **cargv) {
   struct irc_in_addr ip;
   unsigned char bits;
   int hits, duration;
-  int coff, overridesanity, overridelimit, simulate;
+  int coff, overridesanity, overridelimit, simulate, id;
   char *reason;
   char creator[128];
   glinebuf gbuf;
@@ -214,7 +254,7 @@ static int glines_cmdsmartgline(void *source, int cargc, char **cargv) {
   if (cargc < 1)
     return CMD_USAGE;
 
-  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &coff))
+  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
     return CMD_ERROR;
 
   if (cargc < 3 + coff)
@@ -265,16 +305,15 @@ static int glines_cmdsmartgline(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  if (sender->auth)
-    snprintf(creator, sizeof(creator), "#%s", sender->authname);
-  else
-    strncpy(creator, controlid(sender), sizeof(creator));
+  snprintf(creator, sizeof(creator), "#%s", sender->authname);
 
-  glinebufinit(&gbuf, 1);
+  glinebufinit(&gbuf, 0);
   glinebufcommentv(&gbuf, "SMARTGLINE", cargc + coff - 1, cargv);
   glinebufaddbyip(&gbuf, user, &ip, 128, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
 
-  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit, simulate)) {
+  glinebufspew(&gbuf, sender);
+
+  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
     glinebufabort(&gbuf);
     controlreply(sender, "G-Lines failed sanity checks. Not setting G-Lines.");
     return CMD_ERROR;
@@ -286,13 +325,13 @@ static int glines_cmdsmartgline(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  glinebufcounthits(&gbuf, &hits, NULL, NULL);
-  glinebufcommit(&gbuf, 1);
+  glinebufcounthits(&gbuf, &hits, NULL);
+  id = glinebufcommit(&gbuf, 1);
 
   controlwall(NO_OPER, NL_GLINES, "%s SMARTGLINE'd mask '%s' for %s with reason '%s' (%d hits)",
     controlid(sender), cargv[0], longtoduration(duration, 0), reason, hits);
 
-  controlreply(sender, "Done.");
+  controlreply(sender, "Done. G-Line transaction ID: %d", id);
 
   return CMD_OK;
 }
@@ -353,7 +392,7 @@ static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
   channel *cp;
   nick *np;
   char *reason = "Clearing channel.";
-  int mode, duration, i, slot, hits;
+  int mode, duration, i, slot, hits, id;
   int coff, overridesanity, overridelimit, simulate;
   array victims;
   char creator[128];
@@ -362,7 +401,7 @@ static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
   if (cargc < 1)
     return CMD_USAGE;
 
-  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &coff))
+  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
     return CMD_ERROR;
 
   if (cargc < 2 + coff)
@@ -429,12 +468,9 @@ static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
     (((nick **)victims.content)[slot]) = np;
   }
 
-  if (sender->auth)
-    snprintf(creator, sizeof(creator), "#%s", sender->authname);
-  else
-    strncpy(creator, controlid(sender), sizeof(creator));
+  snprintf(creator, sizeof(creator), "#%s", sender->authname);
 
-  glinebufinit(&gbuf, 1);
+  glinebufinit(&gbuf, 0);
   glinebufcommentv(&gbuf, "CLEARCHAN", cargc + coff - 1, cargv);
 
   for (i = 0; i < victims.cursi; i++) {
@@ -467,10 +503,14 @@ static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
     }
   }
 
-  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit, simulate)) {
-    glinebufabort(&gbuf);
-    controlreply(sender, "G-Line failed sanity checks. Not setting G-Line.");
-    return CMD_ERROR;
+  if (mode != 0 && mode != 1) {
+    glinebufspew(&gbuf, sender);
+
+    if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
+      glinebufabort(&gbuf);
+      controlreply(sender, "G-Line failed sanity checks. Not setting G-Line.");
+      return CMD_ERROR;
+    }
   }
 
   if (simulate) {
@@ -479,19 +519,21 @@ static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  glinebufcounthits(&gbuf, &hits, NULL, NULL);
-  glinebufcommit(&gbuf, 1);
+  glinebufmerge(&gbuf);
+  glinebufcounthits(&gbuf, &hits, NULL);
+  id = glinebufcommit(&gbuf, 1);
 
   array_free(&victims);
 
-  if (mode == 0 || mode == 1)
+  if (mode == 0 || mode == 1) {
     controlwall(NO_OPER, NL_GLINES, "%s CLEARCHAN'd channel '%s' with mode '%s' and reason '%s'",
       controlid(sender), cp->index->name->content, cargv[1], reason);
-  else
+    controlreply(sender, "Done.");
+  } else {
     controlwall(NO_OPER, NL_GLINES, "%s CLEARCHAN'd channel '%s' with mode '%s', duration %s and reason '%s' (%d hits)",
       controlid(sender), cp->index->name->content, cargv[1], longtoduration(duration, 0), reason, hits);
-
-  controlreply(sender, "Done.");
+    controlreply(sender, "Done. G-Line transaction ID: %d", id);
+  }
 
   return CMD_OK;
 }
@@ -501,7 +543,7 @@ static int glines_cmdtrustgline(void *source, int cargc, char **cargv) {
   trustgroup *tg;
   trusthost *th;
   int duration, hits;
-  int coff, overridesanity, overridelimit, simulate;
+  int coff, overridesanity, overridelimit, simulate, id;
   char *reason;
   char mask[512];
   char creator[128];
@@ -510,7 +552,7 @@ static int glines_cmdtrustgline(void *source, int cargc, char **cargv) {
   if (cargc < 1)
     return CMD_USAGE;
 
-  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &coff))
+  if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
     return CMD_ERROR;
 
   if (cargc < 4 + coff)
@@ -533,20 +575,19 @@ static int glines_cmdtrustgline(void *source, int cargc, char **cargv) {
   rejoinline(cargv[coff + 3], cargc - coff - 3);
   reason = cargv[coff + 3];
 
-  if (sender->auth)
-    snprintf(creator, sizeof(creator), "#%s", sender->authname);
-  else
-    strncpy(creator, controlid(sender), sizeof(creator));
+  snprintf(creator, sizeof(creator), "#%s", sender->authname);
 
   glinebufinit(&gbuf, 0);
   glinebufcommentv(&gbuf, "TRUSTGLINE", cargc + coff - 1, cargv);
 
   for(th = tg->hosts; th; th = th->next) {
-    snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], trusts_cidr2str(&th->ip, th->bits));
+    snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], CIDRtostr(th->ip, th->bits));
     glinebufadd(&gbuf, mask, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
   }
 
-  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit, simulate)) {
+  glinebufspew(&gbuf, sender);
+
+  if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
     glinebufabort(&gbuf);
     controlreply(sender, "G-Line failed sanity checks. Not setting G-Line.");
     return CMD_ERROR;
@@ -558,13 +599,13 @@ static int glines_cmdtrustgline(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  glinebufcounthits(&gbuf, &hits, NULL, NULL);
-  glinebufcommit(&gbuf, 1);
+  glinebufcounthits(&gbuf, &hits, NULL);
+  id = glinebufcommit(&gbuf, 1);
 
   controlwall(NO_OPER, NL_GLINES, "%s TRUSTGLINE'd user '%s' on trust group '%s' for %s with reason '%s' (%d hits)",
     controlid(sender), cargv[1], tg->name->content, longtoduration(duration, 0), reason, hits);
 
-  controlreply(sender, "Done.");
+  controlreply(sender, "Done. G-Line transaction ID: %d", id);
 
   return CMD_OK;
 }
@@ -590,7 +631,7 @@ static int glines_cmdtrustungline(void *source, int cargc, char **cargv) {
   count = 0;
 
   for (th = tg->hosts; th; th = th->next) {
-    snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], trusts_cidr2str(&th->ip, th->bits));
+    snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], CIDRtostr(th->ip, th->bits));
 
     gl = findgline(mask);
 
@@ -665,7 +706,7 @@ static int glines_cmdglist(void *source, int cargc, char **cargv) {
   char *mask;
   int count = 0;
   int limit = 500;
-  char tmp[250];
+  char expirestr[250], idstr[250];
 
   if (cargc < 1 || (cargc == 1 && cargv[0][0] == '-')) {
     controlreply(sender, "Syntax: glist [-flags] <mask>");
@@ -680,8 +721,6 @@ static int glines_cmdglist(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
 
-  mask = cargv[0];
-
   if (cargc > 1) {
     char* ch = cargv[0];
 
@@ -733,10 +772,15 @@ static int glines_cmdglist(void *source, int cargc, char **cargv) {
   }
 
   if (!(flags & GLIST_COUNT))
-    controlreply(sender, "%-50s %-19s %-25s %s", "Mask:", "Expires in:", "Creator:", "Reason:");
+    controlreply(sender, "%-50s %-19s %-15s %-25s %s", "Mask:", "Expires in:", "Transaction ID:", "Creator:", "Reason:");
 
   gline *searchgl = makegline(mask);
 
+  if (!searchgl) {
+    controlreply(sender, "Invalid G-line mask specified.");
+    return CMD_ERROR;
+  }
+
   for (gl = glinelist; gl; gl = next) {
     next = gl->next;
 
@@ -757,13 +801,14 @@ static int glines_cmdglist(void *source, int cargc, char **cargv) {
       if (!(gl->flags & GLINE_REALNAME))
         continue;
       if (flags & GLIST_EXACT) {
-        if (!glineequal(searchgl, gl)) {
+        if (!glineequal(searchgl, gl))
           continue;
-        }
       } else if (flags & GLIST_FIND) {
-        if (!gline_match_mask(searchgl, gl)) {
+        if (!gline_match_mask(gl, searchgl))
+          continue;
+      } else {
+        if (!match2strings(mask, glinetostring(gl)))
           continue;
-        }
       }
     } else {
       if (gl->flags & GLINE_REALNAME)
@@ -774,28 +819,29 @@ static int glines_cmdglist(void *source, int cargc, char **cargv) {
           if (!gl->reason || ircd_strcmp(mask, gl->reason->content) != 0)
             continue;
         } else if (flags & GLIST_FIND) {
-          if (!gl->reason || match(gl->reason->content, mask))
+          if (!gl->reason || !match2strings(gl->reason->content, mask))
             continue;
-        } else if (!gl->reason || match(mask, gl->reason->content))
+        } else if (!gl->reason || !match2strings(mask, gl->reason->content))
             continue;
       } else if (flags & GLIST_OWNER) {
         if (flags & GLIST_EXACT) {
           if (!gl->creator || ircd_strcmp(mask, gl->creator->content) != 0)
             continue;
         } else if (flags & GLIST_FIND) {
-          if (!gl->creator || match(gl->creator->content, mask))
+          if (!gl->creator || !match2strings(gl->creator->content, mask))
             continue;
-        } else if (!gl->creator || match(mask, gl->creator->content))
+        } else if (!gl->creator || !match2strings(mask, gl->creator->content))
           continue;
       } else {
         if (flags & GLIST_EXACT) {
-          if (!glineequal(searchgl, gl)) {
+          if (!glineequal(searchgl, gl))
             continue;
-          }
         } else if (flags & GLIST_FIND) {
-          if (!gline_match_mask(searchgl, gl)) {
+          if (!gline_match_mask(gl, searchgl))
+            continue;
+        } else {
+          if (!match2strings(mask, glinetostring(gl)))
             continue;
-          }
         }
       }
     }
@@ -806,11 +852,13 @@ static int glines_cmdglist(void *source, int cargc, char **cargv) {
     count++;
 
     if (!(flags & GLIST_COUNT) && count < limit) {
-      snprintf(tmp, 249, "%s", glinetostring(gl));
-      controlreply(sender, "%s%-49s %-19s %-25s %s",
+      snprintf(expirestr, sizeof(expirestr), "%s", glinetostring(gl));
+      snprintf(idstr, sizeof(idstr), "%d", gl->glinebufid);
+      controlreply(sender, "%s%-49s %-19s %-15s %-25s %s",
         (gl->flags & GLINE_ACTIVE) ? "+" : "-",
-        tmp,
+        expirestr,
         (gl->flags & GLINE_ACTIVE) ? (char*)longtoduration(gl->expire - curtime, 0) : "<inactive>",
+        gl->glinebufid ? idstr : "",
         gl->creator ? gl->creator->content : "",
         gl->reason ? gl->reason->content : "");
     }
@@ -853,8 +901,9 @@ static int glines_cmdglinelog(void *source, int cargc, char **cargv) {
       for (gl = gbl->glines; gl; gl = gl->next)
        count++;
 
-      strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&gbl->flush));
-      controlreply(sender, "%-20s %-10d %-10d %-15d %-15d %s", timebuf, gbl->id, count, gbl->userhits, gbl->channelhits, gbl->comment ? gbl->comment->content : "no comment");
+      strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime((gbl->amend) ? &gbl->amend : &gbl->commit));
+      strncat(timebuf, (gbl->amend) ? "*" : " ", sizeof(timebuf));
+      controlreply(sender, "%-20s %-10d %-10d %-15d %-15d %s", timebuf, gbl->id, count, gbl->userhits, gbl->channelhits, gbl->comment ? gbl->comment->content : "(no comment)");
     }
 
     if (id != 0 && gbl->id == id) {
@@ -951,7 +1000,7 @@ static void registercommands(int hooknum, void *arg) {
     return;
   commandsregistered = 1;
 
-  registercontrolhelpcmd("block", NO_OPER, 4, glines_cmdblock, "Usage: block ?flags? <nick> <duration> <reason>\nSets a gline using an appropriate mask given the user's nickname.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
+  registercontrolhelpcmd("block", NO_OPER, 4, glines_cmdblock, "Usage: block ?flags? <nick> <duration> <reason>\nSets a gline using an appropriate mask given the user's nickname.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit\n-c - chase nick across quits/kills/nick changes");
   registercontrolhelpcmd("gline", NO_OPER, 4, glines_cmdgline, "Usage: gline ?flags? <mask> <duration> <reason>\nSets a gline.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
   registercontrolhelpcmd("smartgline", NO_OPER, 4, glines_cmdsmartgline, "Usage: smartgline ?flags? <user@host> <duration> <reason>\nSets a gline. Automatically adjusts the mask depending on whether the specified mask is trusted.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
   registercontrolhelpcmd("ungline", NO_OPER, 1, glines_cmdungline, "Usage: ungline <mask>\nDeactivates a gline.");