]> jfr.im git - irc/quakenet/newserv.git/blobdiff - channel/channelhandlers.c
channel: Don't trigger the CHANNEL_PART hook for ghost parts after a kick, the user...
[irc/quakenet/newserv.git] / channel / channelhandlers.c
index b1b407ea10175133c897d6332ea8e1e165b81199..a42847bbcb8722e83a6d66493385a0a5520693da 100644 (file)
@@ -27,7 +27,7 @@ int handleburstmsg(void *source, int cargc, char **cargv) {
   int isnewchan;
   
   /* (we don't see the first 2 params in cargc) */
-  /* AK B #+lod+ 1017561154 +tnk eits ATJWu:o,AiW1a,Ag3lV,AiWnl,AE6oI :%*!@D577A90D.kabel.telenet.be */
+  /* AK B #+lod+ 1017561154 +tnk eits ATJWu:o,AiW1a,Ag3lV,AiWnl,AE6oI :%*!@123.example.net */
   
   if (cargc<2) {
     Error("channel",ERR_WARNING,"Burst message with only %d parameters",cargc);
@@ -212,7 +212,7 @@ int handleburstmsg(void *source, int cargc, char **cargv) {
 int handlejoinmsg(void *source, int cargc, char **cargv) {
   char *pos,*nextchan;
   nick *np;
-  void *harg[2];
+  void *harg[3];
   channel *cp,**ch;
   long timestamp=0;
   int i;
@@ -230,7 +230,7 @@ int handlejoinmsg(void *source, int cargc, char **cargv) {
   /* Find out who we are talking about here */
   np=getnickbynumericstr(source);
   if (np==NULL) {
-    Error("channel",ERR_WARNING,"Channel join from non existent user %s",source);
+    Error("channel",ERR_WARNING,"Channel join from non existent user %s",(char *)source);
     return CMD_OK;  
   }
   
@@ -257,6 +257,7 @@ int handlejoinmsg(void *source, int cargc, char **cargv) {
         /* Send hook */
         harg[0]=ch[i];
         harg[1]=np;
+        harg[2]=NULL;
         triggerhook(HOOK_CHANNEL_PART,harg);
         delnickfromchannel(ch[i],np->numeric,0);
       }
@@ -283,16 +284,23 @@ int handlejoinmsg(void *source, int cargc, char **cargv) {
         if (newchan) {
           delchannel(cp);
         } 
-      } else { 
+      } else {
+        chanindex *cip=cp->index;
+         
         /* If we just created a channel, flag it */
         if (newchan) {
           triggerhook(HOOK_CHANNEL_NEWCHANNEL,cp);
         }
-
-        /* send hook */
-        harg[0]=cp;
-        harg[1]=np;
-        triggerhook(HOOK_CHANNEL_JOIN,harg);
+        
+        /* Don't send HOOK_CHANNEL_JOIN if the channel doesn't exist any
+         * more (can happen if something destroys it in response to
+         * HOOK_CHANNEL_NEWCHANNEL) */
+        if (cp == cip->channel) {
+          /* send hook */
+          harg[0]=cp;
+          harg[1]=np;
+          triggerhook(HOOK_CHANNEL_JOIN,harg);
+        }
       }
     }
     nextchan=pos;
@@ -317,7 +325,7 @@ int handlecreatemsg(void *source, int cargc, char **cargv) {
   /* Find out who we are talking about here */
   np=getnickbynumericstr(source);
   if (np==NULL) {
-    Error("channel",ERR_WARNING,"Channel create from non existent user %s",source);
+    Error("channel",ERR_WARNING,"Channel create from non existent user %s",(char *)source);
     return CMD_OK;  
   }
   
@@ -354,16 +362,22 @@ int handlecreatemsg(void *source, int cargc, char **cargv) {
       if (newchan) {
         delchannel(cp);
       }
-    } else {  
+    } else {
+      chanindex *cip = cp->index;
+        
       /* Flag the channel as new if necessary */
       if (newchan) {
         triggerhook(HOOK_CHANNEL_NEWCHANNEL,cp);
       }
     
-      /* Trigger hook */
-      harg[0]=cp;
-      harg[1]=np;
-      triggerhook(HOOK_CHANNEL_CREATE,harg);
+      /* If HOOK_CHANNEL_NEWCHANNEL has caused the channel to be deleted,
+       * don't trigger the CREATE hook. */
+      if (cip->channel == cp) {
+        /* Trigger hook */
+        harg[0]=cp;
+        harg[1]=np;
+        triggerhook(HOOK_CHANNEL_CREATE,harg);
+      }
     }
     nextchan=pos;
   }
@@ -394,7 +408,7 @@ int handlepartmsg(void *source, int cargc, char **cargv) {
   /* Find out who we are talking about here */
   np=getnickbynumericstr(source);
   if (np==NULL) {
-    Error("channel",ERR_WARNING,"PART from non existent numeric %s",source);
+    Error("channel",ERR_WARNING,"PART from non existent numeric %s",(char *)source);
     return CMD_OK;  
   }
   
@@ -418,11 +432,13 @@ int handlepartmsg(void *source, int cargc, char **cargv) {
       /* Erm, parting a channel that's not there?? */
       Error("channel",ERR_WARNING,"Nick %s left non-existent channel %s",np->nick,nextchan);
     } else {
-      /* Trigger hook *FIRST* */
-      harg[0]=cp;
-      triggerhook(HOOK_CHANNEL_PART,harg);
-      
-      delnickfromchannel(cp,np->numeric,1);
+      /* Skip ghost parts (confirmation for kick from target server). */
+      if (getnumerichandlefromchanhash(cp->users, np->numeric)) {
+        /* Trigger hook *FIRST* */
+        harg[0]=cp;
+        triggerhook(HOOK_CHANNEL_PART,harg);
+        delnickfromchannel(cp,np->numeric,1);
+      }
     }
     nextchan=pos;
   }
@@ -441,7 +457,7 @@ int handlekickmsg(void *source, int cargc, char **cargv) {
   
   /* Find out who we are talking about here */
   if ((np=getnickbynumericstr(cargv[1]))==NULL) {
-    Error("channel",ERR_DEBUG,"Non-existant numeric %s kicked from channel %s",source,cargv[0]);
+    Error("channel",ERR_DEBUG,"Non-existant numeric %s kicked from channel %s",(char *)source,cargv[0]);
     return CMD_OK;  
   }
 
@@ -494,10 +510,15 @@ int handletopicmsg(void *source, int cargc, char **cargv) {
   if (cargc>3)
     timestamp=strtol(cargv[cargc-3], NULL, 10);
   
-  if ((np=getnickbynumericstr((char *)source))==NULL) {
+  np=getnickbynumericstr((char *)source);
+
+  /* The following check removed because servers can set topics.. */
+#if 0
+  if (np==NULL) {
     /* We should check the sender exists, but we still change the topic even if it doesn't */
     Error("channel",ERR_WARNING,"Topic change by non-existent user %s",(char *)source);
   }
+#endif
   
   /* Grab channel pointer */
   if ((cp=findchannel(cargv[0]))==NULL) {
@@ -544,11 +565,11 @@ int handlemodemsg(void *source, int cargc, char **cargv) {
   int arg=2;
   char *modestr;
   unsigned long *lp;
-  void *harg[3];
+  void *harg[4];
   nick *np, *target;
   int hooknum;
   int changes=0;
-  
+
   if (cargc<2) {
     return CMD_OK;
   }
@@ -575,6 +596,7 @@ int handlemodemsg(void *source, int cargc, char **cargv) {
   /* Set up the hook data */
   harg[0]=cp;
   harg[1]=np;
+  harg[3]=(void *)(long)(cp->flags);
   
   /* Process the mode string one character at a time */
   /* Maybe I'll write this more intelligently one day if I can comprehend the ircu code that does this */
@@ -652,6 +674,16 @@ int handlemodemsg(void *source, int cargc, char **cargv) {
         changes |= MODECHANGE_MODES;
         break;
         
+      case 'M':
+        if (dir) { SetModNoAuth(cp); } else { ClearModNoAuth(cp); }
+        changes |= MODECHANGE_MODES;
+        break;
+      
+      case 'T':
+        if (dir) { SetSingleTarg(cp); } else { ClearSingleTarg(cp); }
+        changes |= MODECHANGE_MODES;
+        break;
+        
       /* Parameter modes: advance parameter and possibly read it in */    
     
       case 'l':
@@ -733,7 +765,7 @@ int handlemodemsg(void *source, int cargc, char **cargv) {
     }
   }
 
-  harg[2]=(void *)changes;
+  harg[2]=(void *)((long)changes);
   triggerhook(HOOK_CHANNEL_MODECHANGE,(void *)harg);  
   return CMD_OK;
 }
@@ -746,7 +778,7 @@ int handlemodemsg(void *source, int cargc, char **cargv) {
 
 int handleclearmodemsg(void *source, int cargc, char **cargv) {
   channel *cp;
-  void *harg[3];
+  void *harg[4];
   nick *np, *target;
   char *mcp;
   unsigned long usermask=0;
@@ -773,7 +805,8 @@ int handleclearmodemsg(void *source, int cargc, char **cargv) {
              
   harg[0]=cp;
   harg[1]=np;
-  
+  harg[3]=(void *)(long)(cp->flags);
+
   for (mcp=cargv[1];*mcp;mcp++) {
     switch (*mcp) {
       case 'o':
@@ -845,6 +878,16 @@ int handleclearmodemsg(void *source, int cargc, char **cargv) {
         ClearNoNotice(cp);
         changes |= MODECHANGE_MODES;
         break;
+        
+      case 'M':
+        ClearModNoAuth(cp);
+        changes |= MODECHANGE_MODES;
+        break;
+      
+      case 'T':
+        ClearSingleTarg(cp);
+        changes |= MODECHANGE_MODES;
+        break;
 
       case 'b':
         clearallbans(cp);
@@ -889,55 +932,70 @@ int handleclearmodemsg(void *source, int cargc, char **cargv) {
     }
   }
 
-  harg[2]=(void *)changes;
+  harg[2]=(void *)((long)changes);
   triggerhook(HOOK_CHANNEL_MODECHANGE, harg);
   return CMD_OK;
 }
 
 void handlewhoischannels(int hooknum, void *arg) {
-  channel** chans;
+  channel **chans;
   char buffer[1024];
-  sstring* name;
-  unsigned long* num;
+  unsigned int bufpos;
+  sstring *name;
+  unsigned long *num;
   int i;
-  void **args = (void **)arg;
-  nick *sender = (nick *)args[0], *target = (nick *)args[1];
-
-  if(IsService(target) || IsHideChan(target))
+  char **args = (char **)arg;
+  nick *sender = (nick *)args[0]; /* sender nick */
+  nick *target = (nick *)args[1]; /* target nick */
+  char *sourcenum = args[2];      /* source numeric */
+
+  /* do not show channels for +k service clients or IRC Operators
+   * do not show channels for +n users
+   * unless they whois themselves
+   */
+  if ((IsService(target) || IsHideChan(target)) && sender != target)
     return;
 
   chans = (channel **)(target->channels->content);
 
   buffer[0] = '\0';
-
+  bufpos=0;
+  
   /* Not handling delayed joins. */
   for(i=target->channels->cursi-1;i>=0;i--) {
-    if(IsSecret(chans[i]) || IsPrivate(chans[i])) { /* check common channels */
-      int j;
-      channel **senderchans = (channel **)(sender->channels->content);
-      for(j=0;j<sender->channels->cursi;j++)
-        if(senderchans[j] == chans[i])
-          break;
-      if(j == sender->channels->cursi)
+    /* Secret / Private channels: only show if the sender is on the channel as well */
+    if(IsSecret(chans[i]) || IsPrivate(chans[i])) {
+      if (!getnumerichandlefromchanhash(chans[i]->users, sender->numeric))
         continue;
     }
+
     name = chans[i]->index->name;
-    if (strlen(buffer) + name->length > 508) { /* why 508? */
+    if (bufpos + name->length > 508) { /* why 508? - need room for -@#channame\0 + 1 slack */
       irc_send("%s", buffer);
       buffer[0] = '\0';
+      bufpos=0;
     }
 
+    /*
+     * 319 RPL_WHOISCHANNELS "source 319 target nick :channels"
+     *                       "irc.netsplit.net 319 foobar barfoo :@#chan1 +#chan2 #chan3"
+     *                       "irc.netsplit.net 319 foobar barfoo :-@#chan1 -+#chan2 -#chan3"
+     */
     if(buffer[0] == '\0')
-      snprintf(buffer, sizeof(buffer), ":%s 319 %s %s :", myserver->content, sender->nick, target->nick);
+      bufpos=snprintf(buffer, sizeof(buffer), "%s 319 %s %s :", getmynumeric(), sourcenum, target->nick);
 
     num = getnumerichandlefromchanhash(chans[i]->users, target->numeric);
+
+    /* Adding these flags might make the string "unsafe" (without terminating \0). */
+    /* sprintf'ing the channel name afterwards is guaranteed to fix it though */
+    if (IsDeaf(target))
+      buffer[bufpos++]='-';
     if (*num & CUMODE_OP)
-      strlcat(buffer, "@", sizeof(buffer));
+      buffer[bufpos++]='@';
     else if (*num & CUMODE_VOICE)
-      strlcat(buffer, "+", sizeof(buffer));
+      buffer[bufpos++]='+';
 
-    strlcat(buffer, name->content, sizeof(buffer));
-    strlcat(buffer, " ", sizeof(buffer));
+    bufpos += sprintf(buffer+bufpos, "%s ",name->content);
   }
 
   if (buffer[0] != '\0')