Fix bug #916138 so -l doesn't gobble an argument.
[ircu2.10.12-pk.git] / ircd / channel.c
index 00e4fd9eefd7d22b06ef71de561deaa21793b985..29b773488fcd0e07e72461b8242a490c67353b2f 100644 (file)
@@ -174,12 +174,11 @@ static char *make_nick_user_host(char *namebuf, const char *nick,
  * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
  * IP-number as the parameters.  If NULL, they become "*".
  */
-#define NUI_BUFSIZE    (NICKLEN + USERLEN + 16 + 3)
+#define NUI_BUFSIZE    (NICKLEN + USERLEN + SOCKIPLEN + 4)
 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
-                              struct in_addr ip)
+                              const struct irc_in_addr *ip)
 {
-  ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name,
-               ircd_ntoa((const char*) &ip));
+  ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
   return ipbuf;
 }
 
@@ -480,11 +479,11 @@ static int is_banned(struct Client *cptr, struct Channel *chptr,
     if ((tmp->flags & CHFL_BAN_IPMASK)) {
       if (!ip_s)
         ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
-                                (cli_user(cptr))->username, cli_ip(cptr));
+                                (cli_user(cptr))->username, &cli_ip(cptr));
       if (match(tmp->value.ban.banstr, ip_s) == 0)
         break;
     }
-    else if (match(tmp->value.ban.banstr, s) == 0)
+    if (match(tmp->value.ban.banstr, s) == 0)
       break;
     else if (sr && match(tmp->value.ban.banstr, sr) == 0)
       break;
@@ -841,6 +840,7 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr)
   int                 opped_members_index = 0;
   struct Membership** opped_members = NULL;
   int                 last_oplevel = 0;
+  int                 feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
 
   assert(0 != cptr);
   assert(0 != chptr); 
@@ -919,7 +919,7 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr)
           * Do we have a nick with a new mode ?
           * Or are we starting a new BURST line?
           */
-         if (new_mode)
+         if (new_mode || !feat_oplevels)
          {
            /*
             * This means we are at the _first_ member that has only
@@ -937,9 +937,11 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr)
              tbuf[loc++] = 'v';
            if (IsChanOp(member))       /* flag_cnt == 2 or 3 */
            {
-             /* append the absolute value of the oplevel */
-             loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
-             last_oplevel = member->oplevel;
+              /* append the absolute value of the oplevel */
+              if (feat_oplevels)
+                loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
+              else
+                tbuf[loc++] = 'o';
            }
            tbuf[loc] = '\0';
            msgq_append(&me, mb, tbuf);
@@ -1017,6 +1019,9 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr)
                                  that didn't fit (full==1) */
   if (opped_members)
     MyFree(opped_members);
+  if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
+      sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
+                    chptr->creationtime, chptr->topic_time, chptr->topic);
 }
 
 /*
@@ -1168,7 +1173,6 @@ top:
 
 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
 {
-  struct SLink *lp;
   int overrideJoin = 0;  
   
   /*
@@ -1177,9 +1181,8 @@ int can_join(struct Client *sptr, struct Channel *chptr, char *key)
    * Now a user CAN escape anything if invited -- Isomer
    */
 
-  for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
-    if (lp->value.chptr == chptr)
-      return 0;
+  if (IsInvited(sptr, chptr))
+    return 0;
   
   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
      a HACK(4) notice will be sent if he would not have been supposed
@@ -1343,17 +1346,19 @@ void list_next_channels(struct Client *cptr, int nr)
   {
     for (; chptr; chptr = chptr->next)
     {
-      if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) && 
-          SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
+      if (!cli_user(cptr))
+        continue;
+      if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) && 
+          SecretChannel(chptr) && !find_channel_member(cptr, chptr))
         continue;
       if (chptr->users > args->min_users && chptr->users < args->max_users &&
           chptr->creationtime > args->min_time &&
           chptr->creationtime < args->max_time &&
-          (!args->topic_limits || (*chptr->topic &&
+          (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
           chptr->topic_time > args->min_topic_time &&
           chptr->topic_time < args->max_topic_time)))
       {
-        if (ShowChannel(cptr,chptr))
+        if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
          send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
                     chptr->topic);
         chptr = chptr->next;
@@ -1519,7 +1524,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
     MODE_WASDELJOINS,   'd',
 /*  MODE_KEY,          'k', */
 /*  MODE_BAN,          'b', */
-/*  MODE_LIMIT,                'l', */
+    MODE_LIMIT,                'l',
 /*  MODE_APASS,                'A', */
 /*  MODE_UPASS,                'u', */
     0x0, 0x0
@@ -1719,11 +1724,8 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
                           "[%Tu]",
-#ifdef HEAD_IN_SAND_SNOTICES
-                          cli_name(mbuf->mb_source),
-#else
-                          cli_name(app_source),
-#endif
+                          cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
+                                    mbuf->mb_source : app_source),
                           mbuf->mb_channel->chname,
                           rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
                           addbuf, remstr, addstr,
@@ -1736,7 +1738,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
                addbuf_i ? "+" : "", addbuf, remstr, addstr);
 
     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
-      sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
+      sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
                                "%H %s%s%s%s%s%s", mbuf->mb_channel,
                                rembuf_i ? "-" : "", rembuf,
                                addbuf_i ? "+" : "", addbuf, remstr, addstr);
@@ -1928,6 +1930,10 @@ modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
   assert(0 != mbuf);
   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
 
+  if (mode == (MODE_LIMIT | MODE_DEL)) {
+      mbuf->mb_rem |= mode;
+      return;
+  }
   MB_TYPE(mbuf, mbuf->mb_count) = mode;
   MB_UINT(mbuf, mbuf->mb_count) = uint;
 
@@ -2172,6 +2178,9 @@ mode_parse_limit(struct ParseState *state, int *flag_p)
     state->parc--;
     state->max_args--;
 
+    if ((int)t_limit<0) /* don't permit a negative limit */
+      return;
+
     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
        (!t_limit || t_limit == state->chptr->mode.limit))
       return;
@@ -2184,6 +2193,16 @@ mode_parse_limit(struct ParseState *state, int *flag_p)
     return;
   }
 
+  /* Can't remove a limit that's not there */
+  if (state->dir == MODE_DEL && !state->chptr->mode.limit)
+    return;
+    
+  /* Skip if this is a burst and a lower limit than this is set already */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      (state->chptr->mode.mode & flag_p[0]) &&
+      (state->chptr->mode.limit < t_limit))
+    return;
+
   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
     return;
   state->done |= DONE_LIMIT;
@@ -2241,8 +2260,8 @@ mode_parse_key(struct ParseState *state, int *flag_p)
 
   /* clean up the key string */
   s = t_str;
-  while (*++s > ' ' && *s != ':' && --t_len)
-    ;
+  while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
+    s++;
   *s = '\0';
 
   if (!*t_str) { /* warn if empty */
@@ -2255,6 +2274,13 @@ mode_parse_key(struct ParseState *state, int *flag_p)
   if (!state->mbuf)
     return;
 
+  /* Skip if this is a burst, we have a key already and the new key is 
+   * after the old one alphabetically */
+  if ((state->flags & MODE_PARSE_BURST) &&
+      *(state->chptr->mode.key) &&
+      ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
+    return;
+
   /* can't add a key if one is set, nor can one remove the wrong key */
   if (!(state->flags & MODE_PARSE_FORCE))
     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
@@ -2826,8 +2852,7 @@ mode_process_clients(struct ParseState *state)
       if (MyUser(state->sptr)) {
 
        /* don't allow local opers to be deopped on local channels */
-       if (MyUser(state->sptr) &&
-            state->cli_change[i].client != state->sptr &&
+       if (state->cli_change[i].client != state->sptr &&
            IsLocalChannel(state->chptr->chname) &&
            HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
          send_reply(state->sptr, ERR_ISOPERLCHAN,
@@ -3188,7 +3213,7 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
 
     /* Send notification to channel */
     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
-      sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
+      sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
                                (flags & CHFL_BANNED || !jbuf->jb_comment) ?
                                ":%H" : "%H :%s", chan, jbuf->jb_comment);
     else if (MyUser(jbuf->jb_source))
@@ -3219,11 +3244,11 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
 
     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
       /* Send the notification to the channel */
-      sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, "%H", chan);
+      sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
 
       /* send an op, too, if needed */
       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
-       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
+       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
                                         chan, jbuf->jb_source);
     } else if (MyUser(jbuf->jb_source))
       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
@@ -3309,7 +3334,7 @@ int IsInvited(struct Client* cptr, const void* chptr)
 
 void RevealDelayedJoin(struct Membership *member) {
   ClearDelayedJoin(member);
-  sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, ":%H",
+  sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
                                    member->channel);
   CheckDelayedJoins(member->channel);
 }
@@ -3327,7 +3352,7 @@ void CheckDelayedJoins(struct Channel *chan) {
     if (!memb2) {
       /* clear +d */
       chan->mode.mode &= ~MODE_WASDELJOINS;
-      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 
+      sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
                                        "%H -d", chan);
     }
   }