Example #1
0
/** Set a channel topic or report an error.
 * @param[in] sptr Original topic setter.
 * @param[in] cptr Neighbor that sent the topic message.
 * @param[in] chptr Channel to set topic on.
 * @param[in] topic New topic.
 * @param[in] ts Timestamp that topic was set (0 for current time).
 */
static void do_settopic(struct Client *sptr, struct Client *cptr,
                        struct Channel *chptr, char *topic, time_t ts)
{
    struct Client *from;
    int newtopic;

    if (feature_bool(FEAT_HIS_BANWHO) && IsServer(sptr))
        from = &his;
    else
        from = sptr;
    /* Note if this is just a refresh of an old topic, and don't
     * send it to all the clients to save bandwidth.  We still send
     * it to other servers as they may have split and lost the topic.
     */
    newtopic=ircd_strncmp(chptr->topic,topic,TOPICLEN)!=0;
    /* setting a topic */
    ircd_strncpy(chptr->topic, topic, TOPICLEN);
    ircd_strncpy(chptr->topic_nick, cli_name(from), NICKLEN);
    chptr->topic_time = ts ? ts : TStime();
    /* Fixed in 2.10.11: Don't propagate local topics */
    if (!IsLocalChannel(chptr->chname))
        sendcmdto_serv(sptr, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
                       chptr->creationtime, chptr->topic_time, chptr->topic);
    if (newtopic)
        sendcmdto_channel(from, CMD_TOPIC, chptr, NULL, SKIP_SERVERS,
                          "%H :%s", chptr, chptr->topic);
    /* if this is the same topic as before we send it to the person that
     * set it (so they knew it went through ok), but don't bother sending
     * it to everyone else on the channel to save bandwidth
     */
    else if (MyUser(sptr))
        sendcmdto_one(sptr, CMD_TOPIC, sptr, "%H :%s", chptr, chptr->topic);
}
Example #2
0
/** Handle a WALLVOICES message from a local client.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the name of the channel to which to send
 * \li \a parv[\a parc - 1] is the message to send
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int m_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Channel *chptr;
  const char *ch;

  assert(0 != cptr);
  assert(cptr == sptr);

  if (parc < 2 || EmptyString(parv[1]))
    return send_reply(sptr, ERR_NORECIPIENT, "WALLVOICES");

  if (parc < 3 || EmptyString(parv[parc - 1]))
    return send_reply(sptr, ERR_NOTEXTTOSEND);

  if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
    if (client_can_send_to_channel(sptr, chptr, 0) && !(chptr->mode.mode & MODE_NONOTICE)) {
      if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
          check_target_limit(sptr, chptr, chptr->chname, 0))
        return 0;

#if 0
      /* +cC checks */
      if (chptr->mode.mode & MODE_NOCOLOUR)
        for (ch=parv[parc - 1];*ch;ch++)
          if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) {
            return 0;
          }

      if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(parv[parc - 1],"\001ACTION ",8))
        for (ch=parv[parc - 1];*ch;)
          if (*ch++==1) {
            return 0;
          }
#endif
      RevealDelayedJoinIfNeeded(sptr, chptr);
      sendcmdto_channel(sptr, CMD_WALLVOICES, chptr, cptr,
                        SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES,
                        "%H :+ %s", chptr, parv[parc - 1]);
    }
    else
      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
  }
  else
    send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);

  return 0;
}
Example #3
0
/** Handle a WALLVOICES message from a server.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the name of the channel to which to send
 * \li \a parv[\a parc - 1] is the message to send
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int ms_wallvoices(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Channel *chptr;
  assert(0 != cptr);
  assert(0 != sptr);

  if (parc < 3 || !IsUser(sptr))
    return 0;

  if (!IsLocalChannel(parv[1]) && (chptr = FindChannel(parv[1]))) {
    if (client_can_send_to_channel(sptr, chptr, 1)) {
      sendcmdto_channel(sptr, CMD_WALLVOICES, chptr, cptr,
                        SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES,
                        "%H :+ %s", chptr, parv[parc - 1]);
    } else
      send_reply(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
  }
  return 0;
}
Example #4
0
/** Handle a KICK message from a local connection.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the channel name to kick someone from
 * \li \a parv[2] is the nickname of the client to kick
 * \li \a parv[\a parc - 1] (optional) is the kick comment
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client *who;
  struct Channel *chptr;
  struct Membership *member = 0;
  struct Membership* member2;
  char *name, *comment;

  if (parc < 3 || *parv[1] == '\0')
    return need_more_params(sptr, "KICK");

  name = parv[1];

  /* simple checks */
  if (!(chptr = get_channel(sptr, name, CGT_NO_CREATE)))
    return send_reply(sptr, ERR_NOSUCHCHANNEL, name);

#if defined(DDB) || defined(SERVICES)
  if (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2)
      || !(IsChanOwner(member2) || IsChanOp(member2)))
#else
  if (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2)
      || !IsChanOp(member2))
#endif
    return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name);

  if (!(who = find_chasing(sptr, parv[2], 0)))
    return 0; /* find_chasing sends the reply for us */

  /* Don't allow the channel service to be kicked */
  if (IsChannelService(who))
    return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname);

  /* Prevent kicking opers from local channels -DM- */
  if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN))
    return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname);

  /* check if kicked user is actually on the channel */
  if (!(member = find_member_link(chptr, who)) || IsZombie(member))
    return send_reply(sptr, ERR_USERNOTINCHANNEL, cli_name(who), chptr->chname);

#if defined(UNDERNET)
  /* Don't allow to kick member with a higher op-level,
   * or members with the same op-level unless both are MAXOPLEVEL.
   */
  if (OpLevel(member) < OpLevel(member2)
      || (OpLevel(member) == OpLevel(member2)
          && OpLevel(member) < MAXOPLEVEL))
    return send_reply(sptr, ERR_NOTLOWEROPLEVEL, cli_name(who), chptr->chname,
	OpLevel(member2), OpLevel(member), "kick",
	OpLevel(member) == OpLevel(member2) ? "the same" : "a higher");
#elif defined(DDB) || defined(SERVICES)
  /* Don't allow to kick channel owner */
  if (IsChanOwner(member) && !IsAnOper(sptr))
    return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname);
#endif


  /* We rely on ircd_snprintf to truncate the comment */
  comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1];

  if (!IsLocalChannel(name))
    sendcmdto_serv(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, comment);

  if (IsDelayedJoin(member)) {
    /* If it's a delayed join, only send the KICK to the person doing
     * the kicking and the victim */
    if (MyUser(who))
      sendcmdto_one(sptr, CMD_KICK, who, "%H %C :%s", chptr, who, comment);
    sendcmdto_one(who, CMD_JOIN, sptr, "%H", chptr);
    sendcmdto_one(sptr, CMD_KICK, sptr, "%H %C :%s", chptr, who, comment);
  } else
    sendcmdto_channel(sptr, CMD_KICK, chptr, NULL, SKIP_SERVERS,
                      "%H %C :%s", chptr, who, comment);

  make_zombie(member, who, cptr, sptr, chptr);

  return 0;
}
Example #5
0
/** Handle a KICK message from a server connection.
 *
 * \a parv has the following elements:
 * \li \a parv[1] is the channel name to kick someone from
 * \li \a parv[2] is the numnick of the client to kick
 * \li \a parv[\a parc - 1] is the kick comment
 *
 * See @ref m_functions for discussion of the arguments.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] parc Number of arguments.
 * @param[in] parv Argument vector.
 */
int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client *who;
  struct Channel *chptr;
  struct Membership *member = 0, *sptr_link = 0;
  char *name, *comment;

  if (parc < 3 || *parv[1] == '\0')
    return need_more_params(sptr, "KICK");

  name = parv[1];
  comment = parv[parc - 1];

  /* figure out who gets kicked from what */
  if (IsLocalChannel(name) ||
      !(chptr = get_channel(sptr, name, CGT_NO_CREATE)) ||
      !(who = findNUser(parv[2])))
    return 0;

  /* We go ahead and pass on the KICK for users not on the channel */
  member = find_member_link(chptr, who);
  if (member && IsZombie(member))
  {
    /* We might get a KICK from a zombie's own server because the user
     * net-rode during a burst (which always generates a KICK) *and*
     * was kicked via another server.  In that case, we must remove
     * the user from the channel.
     */
    if (sptr == cli_user(who)->server)
    {
      remove_user_from_channel(who, chptr);
    }
    /* Otherwise, we treat zombies like they are not channel members. */
    member = 0;
  }

  /* Send HACK notice, but not for servers in BURST */
  /* 2002-10-17: Don't send HACK if the users local server is kicking them */
  if (IsServer(sptr) &&
      !IsBurstOrBurstAck(sptr) &&
      sptr!=cli_user(who)->server)
    sendto_opmask(0, SNO_HACK4, "HACK: %C KICK %H %C %s", sptr, chptr,
                  who, comment);

  /* Unless someone accepted it downstream (or the user isn't on the channel
   * here), if kicker is not on channel, or if kicker is not a channel
   * operator, bounce the kick
   */
#if defined(DDB) || defined(SERVICES)
  if (!IsServer(sptr) && member && cli_from(who) != cptr && !IsService(cli_user(sptr)->server) &&
      (!(sptr_link = find_member_link(chptr, sptr)) || !(IsChanOwner(sptr_link) || IsChanOp(sptr_link)))) {
#else
  if (!IsServer(sptr) && member && cli_from(who) != cptr &&
      (!(sptr_link = find_member_link(chptr, sptr)) || !IsChanOp(sptr_link))) {
#endif
    sendto_opmask(0, SNO_HACK2, "HACK: %C KICK %H %C %s", sptr, chptr,
                  who, comment);

    sendcmdto_one(who, CMD_JOIN, cptr, "%H", chptr);

    /* Reop/revoice member */
    if (IsChanOp(member) || HasVoice(member)) {
      struct ModeBuf mbuf;

      modebuf_init(&mbuf, sptr, cptr, chptr,
		   (MODEBUF_DEST_SERVER |  /* Send mode to a server */
		    MODEBUF_DEST_DEOP   |  /* Deop the source */
		    MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */

#if defined(UNDERNET)
      if (IsChanOp(member))
	modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who, OpLevel(member));
      if (HasVoice(member))
	modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who, MAXOPLEVEL + 1);
#else
      if (IsChanOp(member))
	modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who, 0);
      if (HasVoice(member))
	modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who, 0);
#endif

      modebuf_flush(&mbuf);
    }
  } else {
    /* Propagate kick... */
    sendcmdto_serv(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, comment);

    if (member) { /* and tell the channel about it */
      if (IsDelayedJoin(member)) {
        if (MyUser(who))
          sendcmdto_one(IsServer(sptr) ? &his : sptr, CMD_KICK,
                        who, "%H %C :%s", chptr, who, comment);
      } else {
        sendcmdto_channel(IsServer(sptr) ? &his : sptr, CMD_KICK,
                          chptr, NULL, SKIP_SERVERS, "%H %C :%s",
                          chptr, who, comment);
      }

      make_zombie(member, who, cptr, sptr, chptr);
    }
  }

  return 0;
}