Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / channel.c
index bbedf15202793ed4787dfda1cf54132d62f9544f..ea46920a1910d3bb3e41f4c616e39970fb846537 100644 (file)
@@ -19,6 +19,8 @@
  *
  * $Id$
  */
+#include "config.h"
+
 #include "channel.h"
 #include "client.h"
 #include "hash.h"
@@ -26,7 +28,9 @@
 #include "ircd_alloc.h"
 #include "ircd_chattr.h"
 #include "ircd_defs.h"
+#include "ircd_features.h"
 #include "ircd_log.h"
+#include "ircd_policy.h"
 #include "ircd_reply.h"
 #include "ircd_snprintf.h"
 #include "ircd_string.h"
@@ -43,7 +47,6 @@
 #include "s_misc.h"
 #include "s_user.h"
 #include "send.h"
-#include "sprintf_irc.h"
 #include "struct.h"
 #include "support.h"
 #include "sys.h"
@@ -148,7 +151,7 @@ struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
   if (who)
     return who;
 
-  if (!(who = get_history(user, KILLCHASETIMELIMIT))) {
+  if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
     send_reply(sptr, ERR_NOSUCHNICK, user);
     return 0;
   }
@@ -165,7 +168,7 @@ static char *make_nick_user_host(const char *nick, const char *name,
                                  const char *host)
 {
   static char namebuf[NICKLEN + USERLEN + HOSTLEN + 3];
-  sprintf_irc(namebuf, "%s!%s@%s", nick, name, host);
+  ircd_snprintf(0, namebuf, sizeof(namebuf), "%s!%s@%s", nick, name, host);
   return namebuf;
 }
 
@@ -176,7 +179,8 @@ static char *make_nick_user_host(const char *nick, const char *name,
 static char *make_nick_user_ip(char *nick, char *name, struct in_addr ip)
 {
   static char ipbuf[NICKLEN + USERLEN + 16 + 3];
-  sprintf_irc(ipbuf, "%s!%s@%s", nick, name, ircd_ntoa((const char*) &ip));
+  ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%s!%s@%s", nick, name,
+               ircd_ntoa((const char*) &ip));
   return ipbuf;
 }
 
@@ -309,18 +313,10 @@ int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
           len -= strlen(tmp->value.ban.banstr);
         }
         *banp = tmp->next;
-#if 0
-        /* Silently remove overlapping bans */
-        MyFree(tmp->value.ban.banstr);
-        MyFree(tmp->value.ban.who);
-        free_link(tmp);
-        tmp = 0;
-#else
         /* These will be sent to the user later as -b */
         tmp->next = removed_bans_list;
         removed_bans_list = tmp;
         removed_bans = 1;
-#endif
       }
       else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
       {
@@ -339,7 +335,9 @@ int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
       banp = &(*banp)->next;
     }
   }
-  if (MyUser(cptr) && !removed_bans && (len > MAXBANLENGTH || (cnt >= MAXBANS)))
+  if (MyUser(cptr) && !removed_bans &&
+      (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
+       (cnt >= feature_int(FEAT_MAXBANS))))
   {
     send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
     return -1;
@@ -355,9 +353,13 @@ int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
     assert(0 != ban->value.ban.banstr);
     strcpy(ban->value.ban.banstr, banid);
 
-    ban->value.ban.who = (char*) MyMalloc(strlen(cli_name(cptr)) + 1);
+#ifdef HEAD_IN_SAND_BANWHO
+    if (IsServer(cptr))
+      DupString(ban->value.ban.who, cli_name(&me));
+    else
+#endif
+      DupString(ban->value.ban.who, cli_name(cptr));
     assert(0 != ban->value.ban.who);
-    strcpy(ban->value.ban.who, cli_name(cptr));
 
     ban->value.ban.when = TStime();
     ban->flags = CHFL_BAN;      /* This bit is never used I think... */
@@ -611,7 +613,7 @@ void remove_user_from_all_channels(struct Client* cptr)
 {
   struct Membership* chan;
   assert(0 != cptr);
-  assert(0 != cptr->user);
+  assert(0 != cli_user(cptr));
 
   while ((chan = (cli_user(cptr))->channel))
     remove_user_from_channel(cptr, chan->channel);
@@ -696,10 +698,11 @@ int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr)
 
   /*
    * You can't speak if your off channel, if the channel is modeless, or
-   * +n.(no external messages)
+   * +n (no external messages) or +m (moderated).
    */
   if (!member) {
-    if ((chptr->mode.mode & MODE_NOPRIVMSGS) || IsModelessChannel(chptr->chname)) 
+    if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) 
+       || IsModelessChannel(chptr->chname)) 
       return 0;
     else
       return 1;
@@ -752,16 +755,17 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf,
     *mbuf++ = 'n';
   if (chptr->mode.limit) {
     *mbuf++ = 'l';
-    sprintf_irc(pbuf, "%d", chptr->mode.limit);
+    ircd_snprintf(0, pbuf, sizeof(pbuf), "%d", chptr->mode.limit);
   }
 
   if (*chptr->mode.key) {
     *mbuf++ = 'k';
+    if (chptr->mode.limit)
+      strcat(pbuf, " ");
     if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
-      if (chptr->mode.limit)
-        strcat(pbuf, " ");
       strcat(pbuf, chptr->mode.key);
-    }
+    } else
+      strcat(pbuf, "*");
   }
   *mbuf = '\0';
 }
@@ -1053,15 +1057,12 @@ int can_join(struct Client *sptr, struct Channel *chptr, char *key)
     if (lp->value.chptr == chptr)
       return 0;
   
-#ifdef OPER_WALK_THROUGH_LMODES
   /* 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
      to join normally. */ 
-  if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && compall("OVERRIDE",key) == 0)
-  {
+  if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
+      !BadPtr(key) && compall("OVERRIDE",key) == 0)
     overrideJoin = MAGIC_OPER_OVERRIDE;
-  }
-#endif
 
   if (chptr->mode.mode & MODE_INVITEONLY)
        return overrideJoin + ERR_INVITEONLYCHAN;
@@ -1157,7 +1158,7 @@ void add_invite(struct Client *cptr, struct Channel *chptr)
    * Delete last link in chain if the list is max length
    */
   assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
-  if ((cli_user(cptr))->invites>=MAXCHANNELSPERUSER)
+  if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
     del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
   /*
    * Add client to channel invite list
@@ -1243,6 +1244,8 @@ void list_next_channels(struct Client *cptr, int nr)
     (cli_listing(cptr))->chptr = chptr;
     chptr->mode.mode |= MODE_LISTED;
   }
+
+  update_write(cptr);
 }
 
 /*
@@ -1420,7 +1423,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
 
   /* Ok, if we were given the OPMODE flag, hide the source if its a user */
   if (mbuf->mb_dest & MODEBUF_DEST_OPMODE && !IsServer(mbuf->mb_source))
-    app_source = (cli_user(mbuf->mb_source))->server;
+    app_source = &me;
   else
     app_source = mbuf->mb_source;
 
@@ -1469,7 +1472,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
       }
     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
       /* if it's a limit, we also format the number */
-      sprintf_irc(limitbuf, "%d", MB_UINT(mbuf, i));
+      ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%d", MB_UINT(mbuf, i));
 
       tmp = strlen(limitbuf);
 
@@ -1528,14 +1531,24 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
     /* send the messages off to their destination */
     if (mbuf->mb_dest & MODEBUF_DEST_HACK2) {
       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
-                          "[%Tu]", cli_name(app_source),
+                          "[%Tu]",
+#ifdef HEAD_IN_SAND_SNOTICES
+                          cli_name(mbuf->mb_source),
+#else
+                          cli_name(app_source),
+#endif
                           mbuf->mb_channel->chname,
                           rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
                           addbuf, remstr, addstr,
                           mbuf->mb_channel->creationtime);
       sendcmdto_serv_butone(&me, CMD_DESYNCH, mbuf->mb_connect,
                            ":HACK: %s MODE %s %s%s%s%s%s%s [%Tu]",
-                           cli_name(app_source), mbuf->mb_channel->chname,
+#ifdef HEAD_IN_SAND_SNOTICES
+                           cli_name(mbuf->mb_source),
+#else
+                           cli_name(app_source),
+#endif
+                           mbuf->mb_channel->chname,
                            rembuf_i ? "-" : "", rembuf,
                            addbuf_i ? "+" : "", addbuf, remstr, addstr,
                            mbuf->mb_channel->creationtime);
@@ -1543,14 +1556,24 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
 
     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
-                          "%s%s%s%s%s%s [%Tu]", cli_name(app_source),
+                          "%s%s%s%s%s%s [%Tu]",
+#ifdef HEAD_IN_SAND_SNOTICES
+                          cli_name(mbuf->mb_source),
+#else
+                          cli_name(app_source),
+#endif
                           mbuf->mb_channel->chname, rembuf_i ? "-" : "",
                           rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
                           mbuf->mb_channel->creationtime);
 
     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]", cli_name(app_source),
+                          "[%Tu]",
+#ifdef HEAD_IN_SAND_SNOTICES
+                          cli_name(mbuf->mb_source),
+#else
+                          cli_name(app_source),
+#endif
                           mbuf->mb_channel->chname,
                           rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
                           addbuf, remstr, addstr,
@@ -2127,7 +2150,7 @@ mode_parse_ban(struct ParseState *state, int *flag_p)
     newban->next = 0;
 
     DupString(newban->value.ban.banstr, t_str);
-    newban->value.ban.who = state->sptr->name;
+    newban->value.ban.who = cli_name(state->sptr);
     newban->value.ban.when = TStime();
 
     newban->flags = CHFL_BAN | MODE_ADD;
@@ -2174,16 +2197,18 @@ mode_parse_ban(struct ParseState *state, int *flag_p)
     } else if (state->dir == MODE_ADD) {
       /* if the ban already exists, don't worry about it */
       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
+       newban->flags &= ~MODE_ADD; /* don't add ban at all */
+       MyFree(newban->value.ban.banstr); /* stopper a leak */
+       state->numbans--; /* deallocate last ban */
        if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
          break;
-       continue;
       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
        if (!(ban->flags & MODE_DEL))
          newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
       } else if (!mmatch(t_str, ban->value.ban.banstr))
        ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
 
-      if (!ban->next) {
+      if (!ban->next && (newban->flags & MODE_ADD)) {
        ban->next = newban; /* add our ban with its flags */
        break; /* get out of loop */
       }
@@ -2258,7 +2283,8 @@ mode_process_bans(struct ParseState *state)
        MyFree(ban->value.ban.banstr);
       } else {
        if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
-           (len > MAXBANLENGTH || count >= MAXBANS)) {
+           (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
+            count >= feature_int(FEAT_MAXBANS))) {
          send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
                     ban->value.ban.banstr);
          count--;
@@ -2386,17 +2412,15 @@ mode_process_clients(struct ParseState *state)
        }
       }
 
-#ifdef NO_OPER_DEOP_LCHAN
       /* don't allow local opers to be deopped on local channels */
       if (MyUser(state->sptr) && state->cli_change[i].client != state->sptr &&
-         IsOperOnLocalChannel(state->cli_change[i].client,
-                              state->chptr->chname)) {
+         IsLocalChannel(state->chptr->chname) &&
+         HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
        send_reply(state->sptr, ERR_ISOPERLCHAN,
                   cli_name(state->cli_change[i].client),
                   state->chptr->chname);
        continue;
       }
-#endif
     }
 
     /* accumulate the change */