added basic ssl support to ircu
[ircu2.10.12-pk.git] / ircd / channel.c
index d481541955530cc2f4fe00a6f446a71b6ff68905..9c0f192d2a3cd79502fda636e5d7ada15bfaec89 100644 (file)
@@ -1224,34 +1224,6 @@ static void send_ban_list(struct Client* cptr, struct Channel* chptr)
   send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
 }
 
-/** Remove bells and commas from channel name
- *
- * @param cn   Channel name to clean, modified in place.
- */
-void clean_channelname(char *cn)
-{
-  int i;
-
-  for (i = 0; cn[i]; i++) {
-    if (i >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))
-        || !IsChannelChar(cn[i])) {
-      cn[i] = '\0';
-      return;
-    }
-    if (IsChannelLower(cn[i])) {
-      cn[i] = ToLower(cn[i]);
-#ifndef FIXME
-      /*
-       * Remove for .08+
-       * toupper(0xd0)
-       */
-      if ((unsigned char)(cn[i]) == 0xd0)
-        cn[i] = (char) 0xf0;
-#endif
-    }
-  }
-}
-
 /** Get a channel block, creating if necessary.
  *  Get Channel block for chname (and allocate a new channel
  *  block, if it didn't exists before).
@@ -1517,6 +1489,20 @@ build_string(char *strptr, int *strptr_i, const char *str1,
   strptr[(*strptr_i)] = '\0';
 }
 
+/** Check a channel for join-delayed members.
+ * @param[in] chan Channel to search.
+ * @return Non-zero if any members are join-delayed; false if none are.
+ */
+static int
+find_delayed_joins(const struct Channel *chan)
+{
+  const struct Membership *memb;
+  for (memb = chan->members; memb; memb = memb->next_member)
+    if (IsDelayedJoin(memb))
+      return 1;
+  return 0;
+}
+
 /** Flush out the modes
  * This is the workhorse of our ModeBuf suite; this actually generates the
  * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
@@ -1596,6 +1582,23 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all)
   else
     app_source = mbuf->mb_source;
 
+  /* Must be set if going -D and some clients are hidden */
+  if ((mbuf->mb_rem & MODE_DELJOINS)
+      && !(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
+      && find_delayed_joins(mbuf->mb_channel)) {
+    mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
+    mbuf->mb_add |= MODE_WASDELJOINS;
+    mbuf->mb_rem &= ~MODE_WASDELJOINS;
+  }
+
+  /* +d must be cleared if +D is set */
+  if ((mbuf->mb_add & MODE_DELJOINS)
+      && (mbuf->mb_channel->mode.mode & MODE_WASDELJOINS)) {
+    mbuf->mb_channel->mode.mode &= ~MODE_WASDELJOINS;
+    mbuf->mb_add &= ~MODE_WASDELJOINS;
+    mbuf->mb_rem |= MODE_WASDELJOINS;
+  }
+
   /*
    * Account for user we're bouncing; we have to get it in on the first
    * bounced MODE, or we could have problems
@@ -1986,7 +1989,7 @@ 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 | ((mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_ADD : MODE_DEL))) {
+  if (mode == (MODE_LIMIT | MODE_DEL)) {
       mbuf->mb_rem |= mode;
       return;
   }
@@ -2052,47 +2055,15 @@ modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
     modebuf_flush_int(mbuf, 0);
 }
 
-/** Check a channel for join-delayed members.
- * @param[in] chan Channel to search.
- * @return Non-zero if any members are join-delayed; false if none are.
- */
-static int
-find_delayed_joins(const struct Channel *chan)
-{
-  const struct Membership *memb;
-  for (memb = chan->members; memb; memb = memb->next_member)
-    if (IsDelayedJoin(memb))
-      return 1;
-  return 0;
-}
-
 /** The exported binding for modebuf_flush()
  *
  * @param mbuf The mode buffer to flush.
- * 
+ *
  * @see modebuf_flush_int()
  */
 int
 modebuf_flush(struct ModeBuf *mbuf)
 {
-  /* Check if MODE_WASDELJOINS should be set: */
-  /* Must be set if going -D and some clients are hidden */
-  if ((mbuf->mb_rem & MODE_DELJOINS)
-      && !(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
-      && find_delayed_joins(mbuf->mb_channel)) {
-    mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
-    mbuf->mb_add |= MODE_WASDELJOINS;
-    mbuf->mb_rem &= ~MODE_WASDELJOINS;
-  }
-  /* Must be cleared if +D is set */
-  if ((mbuf->mb_add & MODE_DELJOINS)
-      && ((mbuf->mb_channel->mode.mode & (MODE_WASDELJOINS | MODE_WASDELJOINS))
-          == (MODE_WASDELJOINS | MODE_WASDELJOINS))) {
-    mbuf->mb_channel->mode.mode &= ~MODE_WASDELJOINS;
-    mbuf->mb_add &= ~MODE_WASDELJOINS;
-    mbuf->mb_rem |= MODE_WASDELJOINS;
-  }
-
   return modebuf_flush_int(mbuf, 1);
 }
 
@@ -2330,15 +2301,41 @@ mode_parse_limit(struct ParseState *state, int *flag_p)
   }
 }
 
-/** Helper function to clean key-like parameters. */
-static void
-clean_key(char *s)
+/** Helper function to validate key-like parameters.
+ *
+ * @param[in] state Parse state for feedback to user.
+ * @param[in] s Key to validate.
+ * @param[in] command String to pass for need_more_params() command.
+ * @return Zero on an invalid key, non-zero if the key was okay.
+ */
+static int
+is_clean_key(struct ParseState *state, char *s, char *command)
 {
-  int t_len = KEYLEN;
+  int ii;
 
-  while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
-    s++;
-  *s = '\0';
+  if (s[0] == '\0') {
+    if (MyUser(state->sptr))
+      need_more_params(state->sptr, command);
+    return 0;
+  }
+  else if (s[0] == ':') {
+    if (MyUser(state->sptr))
+      send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname);
+    return 0;
+  }
+  for (ii = 0; (ii <= KEYLEN) && (s[ii] != '\0'); ++ii) {
+    if ((unsigned char)s[ii] <= ' ' || s[ii] == ',') {
+      if (MyUser(state->sptr))
+        send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname);
+      return 0;
+    }
+  }
+  if (ii > KEYLEN) {
+    if (MyUser(state->sptr))
+      send_reply(state->sptr, ERR_INVALIDKEY, state->chptr->chname);
+    return 0;
+  }
+  return 1;
 }
 
 /*
@@ -2383,14 +2380,10 @@ mode_parse_key(struct ParseState *state, int *flag_p)
     state->done |= DONE_KEY_DEL;
   }
 
-  /* clean up the key string */
-  clean_key(t_str);
-  if (!*t_str || *t_str == ':') { /* warn if empty */
-    if (MyUser(state->sptr))
-      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
-                      "MODE -k");
+  /* If the key is invalid, tell the user and bail. */
+  if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +k" :
+                    "MODE -k"))
     return;
-  }
 
   if (!state->mbuf)
     return;
@@ -2495,14 +2488,10 @@ mode_parse_upass(struct ParseState *state, int *flag_p)
     state->done |= DONE_UPASS_DEL;
   }
 
-  /* clean up the upass string */
-  clean_key(t_str);
-  if (!*t_str || *t_str == ':') { /* warn if empty */
-    if (MyUser(state->sptr))
-      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
-                      "MODE -U");
+  /* If the Upass is invalid, tell the user and bail. */
+  if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +U" :
+                    "MODE -U"))
     return;
-  }
 
   if (!state->mbuf)
     return;
@@ -2642,14 +2631,10 @@ mode_parse_apass(struct ParseState *state, int *flag_p)
     state->done |= DONE_APASS_DEL;
   }
 
-  /* clean up the apass string */
-  clean_key(t_str);
-  if (!*t_str || *t_str == ':') { /* warn if empty */
-    if (MyUser(state->sptr))
-      need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
-                      "MODE -A");
+  /* If the Apass is invalid, tell the user and bail. */
+  if (!is_clean_key(state, t_str, state->dir == MODE_ADD ? "MODE +A" :
+                    "MODE -A"))
     return;
-  }
 
   if (!state->mbuf)
     return;
@@ -2933,6 +2918,7 @@ mode_process_bans(struct ParseState *state)
        len -= banlen;
       } else {
        if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
+            !(state->mbuf->mb_dest & MODEBUF_DEST_OPMODE) &&
            (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
             count > feature_int(FEAT_MAXBANS))) {
          send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
@@ -3003,17 +2989,19 @@ mode_parse_client(struct ParseState *state, int *flag_p)
     if (colon != NULL) {
       *colon++ = '\0';
       req_oplevel = atoi(colon);
-      if (!(state->flags & MODE_PARSE_FORCE)
+      if (*flag_p == CHFL_VOICE || state->dir == MODE_DEL) {
+        /* Ignore the colon and its argument. */
+      } else if (!(state->flags & MODE_PARSE_FORCE)
           && state->member
           && (req_oplevel < OpLevel(state->member)
               || (req_oplevel == OpLevel(state->member)
                   && OpLevel(state->member) < MAXOPLEVEL)
-              || req_oplevel > MAXOPLEVEL))
+              || req_oplevel > MAXOPLEVEL)) {
         send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
                    t_str, state->chptr->chname,
                    OpLevel(state->member), req_oplevel, "op",
                    OpLevel(state->member) == req_oplevel ? "the same" : "a higher");
-      else if (req_oplevel <= MAXOPLEVEL)
+      else if (req_oplevel <= MAXOPLEVEL)
         oplevel = req_oplevel;
     }
     /* find client we're manipulating */
@@ -3208,10 +3196,19 @@ mode_parse_mode(struct ParseState *state, int *flag_p)
         (state->add & (MODE_SECRET | MODE_PRIVATE)));
 }
 
-/*
+/**
  * This routine is intended to parse MODE or OPMODE commands and effect the
- * changes (or just build the bounce buffer).  We pass the starting offset
- * as a 
+ * changes (or just build the bounce buffer).
+ *
+ * \param[out] mbuf Receives parsed representation of mode change.
+ * \param[in] cptr Connection that sent the message to this server.
+ * \param[in] sptr Original source of the message.
+ * \param[in] chptr Channel whose modes are being changed.
+ * \param[in] parc Number of valid strings in \a parv.
+ * \param[in] parv Text arguments representing mode change, with the
+ *   zero'th element containing a string like "+m" or "-o".
+ * \param[in] flags Set of bitwise MODE_PARSE_* flags.
+ * \param[in] member If non-null, the channel member attempting to change the modes.
  */
 int
 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
@@ -3371,7 +3368,9 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
           } else {
             /* Server is desynced; bounce the mode and deop the source
              * to fix it. */
-            state.mbuf->mb_dest &= ~MODEBUF_DEST_CHANNEL;
+            state.flags &= ~MODE_PARSE_SET;
+            state.flags |= MODE_PARSE_BOUNCE;
+            state.mbuf->mb_dest &= ~(MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK4);
             state.mbuf->mb_dest |= MODEBUF_DEST_BOUNCE | MODEBUF_DEST_HACK2;
             if (!IsServer(state.cptr))
               state.mbuf->mb_dest |= MODEBUF_DEST_DEOP;
@@ -3639,3 +3638,12 @@ void CheckDelayedJoins(struct Channel *chan)
                                      "%H -d", chan);
   }
 }
+
+/** Send a join for the user if (s)he is a hidden member of the channel.
+ */
+void RevealDelayedJoinIfNeeded(struct Client *sptr, struct Channel *chptr)
+{
+  struct Membership *member = find_member_link(chptr, sptr);
+  if (member && IsDelayedJoin(member))
+    RevealDelayedJoin(member);
+}