]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Update USERS command to have silly restriction on "helpers" as per helpmod2.
authorsplidge <redacted>
Fri, 14 Mar 2008 15:39:26 +0000 (15:39 +0000)
committersplidge <redacted>
Fri, 14 Mar 2008 15:39:26 +0000 (15:39 +0000)
Also tidied up and documented the subtle bits.

chanserv/chancmds/users.c
chanserv/chanserv_messages.h

index 9a75c93e11bf1d7ee67990b3f56d6645a1f5f40a..ca03d24f47d3f40798e73d6730087729859fc368 100644 (file)
 #include <string.h>
 #include <stdio.h>
 
+/* Random flags and structs and sort functions which will come in handly later */
+
 #define ISQ   0x40000000
 #define ISOP  0x20000000
 #define ISV   0x10000000
 
 struct chanuserrec {
-  unsigned int flags; /* Something that sorts nicely */
+  unsigned int flags;
   regchanuser *rcup;
   reguser *rup;
   nick *np;
@@ -42,6 +44,7 @@ static int comparetheflags(const void *a, const void *b) {
 
 int csc_dousers(void *source, int cargc, char **cargv) {
   nick *sender=source, *np;
+  reguser *rup=getreguserfromnick(sender);
   chanindex *cip;
   regchan *rcp;
   struct chanuserrec *theusers;
@@ -52,6 +55,7 @@ int csc_dousers(void *source, int cargc, char **cargv) {
   char uhbuf[USERLEN+HOSTLEN+2];
   flag_t flagmask;
   unsigned int ops,voices,users,flags,qops,masters;
+  unsigned int notonchan=0;
   
   if (cargc<1) {
     chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "users");
@@ -69,25 +73,53 @@ int csc_dousers(void *source, int cargc, char **cargv) {
     return CMD_ERROR;
   }
   
-  if (!cs_privcheck(QPRIV_VIEWFULLCHANLEV, sender) && !getnumerichandlefromchanhash(cip->channel->users,sender->numeric)) {
+  /* Two part logic here.  Firstly, only staff are allowed to look at
+   * channels they are not on.  But later we will prevent them looking at
+   * channels with opers on them, but clearly it's ok to do this on any
+   * channel you are actually on regardless of whether there is an oper or
+   * not.  So extract this "notonchan" status here and use it in the later
+   * checks.  We set "notonchan" if you are not an oper and not on the
+   * channel.  Non-staff with "notonchan" set are then immediately rebuffed. 
+   */
+  if (!getnumerichandlefromchanhash(cip->channel->users,sender->numeric) && 
+      !UHasOperPriv(rup))
+    notonchan=1;
+  
+  if (!cs_privcheck(QPRIV_VIEWFULLCHANLEV, sender) && notonchan) {
     chanservstdmessage(sender,QM_NOTONCHAN,cip->name->content);
     return CMD_ERROR;
   }
-  
+
+  /* malloc() time: if we abort after here we should goto out; rather than
+   * return; */
   theusers=malloc(cp->users->totalusers * sizeof(struct chanuserrec));
   memset(theusers,0,cp->users->totalusers * sizeof(struct chanuserrec));
-  
+  /* OK, fill in our custom struct with useful info about each actual user */ 
   for (i=0,j=0;i<cp->users->hashsize;i++) {
     if (cp->users->content[i]==nouser)
       continue;
     
+    /* shouldn't happen */
     if (!(np=getnickbynumeric(cp->users->content[i])))
       goto out;
 
+    /* Don't let non-opers look at channels with opers in.  How paranoid are we?
+     * Obviously if you are on the channel yourself, no such silliness is necessary. 
+     * Making the arbitrary assumption that one letter nicks are OK as per helpmod2.
+     */
+    if (notonchan && IsOper(np) && np->nick[1] && 
+        (IsSecret(cp) || IsPrivate(cp) || IsKey(cp) || IsInviteOnly(cp))) {
+      chanservstdmessage(sender,QM_OPERONCHAN,"users",cip->name->content);
+      goto out;
+    }
+
     theusers[j].np=np;
 
+    /* Copy op and voice bits from the chanuser */
     theusers[j].flags=(cp->users->content[i]>>2) & 0x30000000;
 
+    /* Make sure we come out at the top of the list */
     if (np==chanservnick) {
       theusers[j].flags|=0x40000000;
     }
@@ -95,6 +127,7 @@ int csc_dousers(void *source, int cargc, char **cargv) {
     theusers[j].rup=getreguserfromnick(np);
     if (theusers[j].rup) {
       theusers[j].rcup=findreguseronchannel(rcp, theusers[j].rup);
+      /* OR in the chanlev flags at the bottom if they are known */
       if (theusers[j].rcup)
         theusers[j].flags |= theusers[j].rcup->flags;
     }
@@ -104,7 +137,11 @@ int csc_dousers(void *source, int cargc, char **cargv) {
   qsort(theusers, j, sizeof(struct chanuserrec), comparetheflags);
   
   chanservstdmessage(sender, QM_USERSHEADER, cip->name->content);
-  
+
+  /* Determine what flags to show.  Public flags always OK, punishment flags
+   * for masters only, personal flags for yourself only except staff who can
+   * see all.  Obviously we have to do the bit about personal flags later on... 
+   */
   flagmask=QCUFLAGS_PUBLIC;
   ops=voices=users=flags=qops=masters=0;
   if (cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, "users", 0, 1))
@@ -126,7 +163,8 @@ int csc_dousers(void *source, int cargc, char **cargv) {
     } 
 
     if (theusers[i].flags & ISQ) {
-      modechar='@';
+      /* OK so in reality we may actually have a username and even some
+       * flags.  But those don't really matter so let's sub in a cute message. */
       unbuf="It's me!";
       flagbuf="";
     } else {
@@ -147,8 +185,13 @@ int csc_dousers(void *source, int cargc, char **cargv) {
           masters++;
       }        
       
+      /* Subtlety here: we conditionally OR in the personal flags for
+       * display but not for the check.  This is because if you have
+       * personal flags you must have some public flag too by definition. 
+       * Compare based on reguser so you can see personal flags for all
+       * clones on your account. */
       if (theusers[i].rcup && (theusers[i].rcup->flags & flagmask)) {
-        flagbuf=printflags((flagmask | (theusers[i].np==sender?QCUFLAGS_PERSONAL:0)) & theusers[i].rcup->flags, rcuflags);
+        flagbuf=printflags((flagmask | (theusers[i].rup==rup?QCUFLAGS_PERSONAL:0)) & theusers[i].rcup->flags, rcuflags);
       } else {
         flagbuf="";
       }
@@ -162,7 +205,7 @@ int csc_dousers(void *source, int cargc, char **cargv) {
   chanservstdmessage(sender, QM_USERSSUMMARY, j, ops, voices, users, flags, qops, masters);
   return CMD_OK;
   
-  out:
+out:
   free(theusers);
   return CMD_ERROR;
 }
index d25fa37ef885a63d5418cb0df163cd81299a189b..1a0ea6a0ac739a12d31c5f28bec9b4748ec4f1bf 100644 (file)
@@ -201,6 +201,7 @@ BeginMessages() {
   msg(QM_USERSHEADER, "Users currently on $0:\nNick            Username        Flags        Host", "s"),
   msg(QM_EMPTYCHAN, "Channel $0 is currently empty.", "s"),
   msg(QM_USERSSUMMARY, "Total $0 users: $1 opped, $2 voiced, $3 others, $4 with flags ($5 ops, $6 masters)", "ddddddd"),
+  msg(QM_OPERONCHAN, "You cannot use $0 on $1 since an oper is on the channel.","ss"),
 } 
 EndMessages()
 #endif