Пример #1
0
/*
 * m_quit - client message handler 
 *
 * parv[0]        = sender prefix
 * parv[parc - 1] = comment
 */
int m_quit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  assert(0 != cptr);
  assert(0 != sptr);
  assert(cptr == sptr);

  if (cli_user(sptr)) {
    struct Membership* chan;
    for (chan = cli_user(sptr)->channel; chan; chan = chan->next_channel) {
        if (!IsZombie(chan) && !IsDelayedJoin(chan) && !member_can_send_to_channel(chan, 0))
        return exit_client(cptr, sptr, sptr, "Signed off");
    }
  }
  if (parc > 1 && !BadPtr(parv[parc - 1]) && !IsMute(sptr))
    return exit_client_msg(cptr, sptr, sptr, "Quit: %s", parv[parc - 1]);
  else
    return exit_client(cptr, sptr, sptr, "Quit");
}
Пример #2
0
/*
 * ms_part - server message handler
 *
 * parv[0] = sender prefix
 * parv[1] = channel
 * parv[parc - 1] = comment
 */
int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
  struct Channel *chptr;
  struct Membership *member;
  struct JoinBuf parts;
  unsigned int flags;
  char *p = 0;
  char *name;

  ClrFlag(sptr, FLAG_TS8);

  /* check number of arguments */
  if (parc < 2 || parv[1][0] == '\0')
    return need_more_params(sptr, "PART");

  /* init join/part buffer */
  joinbuf_init(&parts, sptr, cptr, JOINBUF_TYPE_PART,
	       (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0,
	       0);

  /* scan through channel list */
  for (name = ircd_strtok(&p, parv[1], ","); name;
       name = ircd_strtok(&p, 0, ",")) {

    flags = 0;

    chptr = get_channel(sptr, name, CGT_NO_CREATE); /* look up channel */

    if (!chptr || IsLocalChannel(name) ||
	!(member = find_member_link(chptr, sptr)))
      continue; /* ignore from remote clients */

    if (IsZombie(member)) /* figure out special flags... */
      flags |= CHFL_ZOMBIE;

    if (IsDelayedJoin(member))
      flags |= CHFL_DELAYED;

    /* part user from channel */
    joinbuf_join(&parts, chptr, flags);
  }

  return joinbuf_flush(&parts); /* flush channel parts */
}
Пример #3
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)
   {
     struct Membership *member;

     /* If the member is delayed-join, show them. */
     member = find_channel_member(sptr, chptr);
     if (member && IsDelayedJoin(member))
       RevealDelayedJoin(member);

     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);
}
Пример #4
0
/** Searches for and handles a 0 in a join list.
 * @param[in] cptr Client that sent us the message.
 * @param[in] sptr Original source of message.
 * @param[in] chanlist List of channels to join.
 * @return First token in \a chanlist after the final 0 entry, which
 * may be its nul terminator (if the final entry is a 0 entry).
 */
static char *
last0(struct Client *cptr, struct Client *sptr, char *chanlist)
{
  char *p;
  int join0 = 0;

  for (p = chanlist; p[0]; p++) /* find last "JOIN 0" */
    if (p[0] == '0' && (p[1] == ',' || p[1] == '\0')) {
      if (p[1] == ',')
        p++;
      chanlist = p + 1;
      join0 = 1;
    } else {
      while (p[0] != ',' && p[0] != '\0') /* skip past channel name */
	p++;

      if (!p[0]) /* hit the end */
	break;
    }

  if (join0) {
    struct JoinBuf part;
    struct Membership *member;

    joinbuf_init(&part, sptr, cptr, JOINBUF_TYPE_PARTALL,
                 "Left all channels", 0);

    joinbuf_join(&part, 0, 0);

    while ((member = cli_user(sptr)->channel))
      joinbuf_join(&part, member->channel,
                   IsZombie(member) ? CHFL_ZOMBIE :
                   IsDelayedJoin(member) ? CHFL_DELAYED :
                   0);

    joinbuf_flush(&part);
  }

  return chanlist;
}
Пример #5
0
/*
 * ms_kick - server message handler
 *
 * parv[0] = sender prefix
 * parv[1] = channel
 * parv[2] = client to kick
 * parv[parc-1] = kick comment
 */
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;

  ClrFlag(sptr, FLAG_TS8);

  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_butone(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 (!IsServer(sptr) && member && cli_from(who) != cptr &&
      (!(sptr_link = find_member_link(chptr, sptr)) || !IsChanOp(sptr_link))) {
    sendto_opmask_butone(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 (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);

      modebuf_flush(&mbuf);
    }
  } else {
    /* Propagate kick... */
    sendcmdto_serv_butone(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_butserv_butone(IsServer(sptr) ? &his : sptr, CMD_KICK,
                                         chptr, NULL, 0, "%H %C :%s", chptr, who,
                                         comment);
      }

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

  return 0;
}
Пример #6
0
/*
 * m_kick - generic message handler
 *
 * parv[0] = sender prefix
 * parv[1] = channel
 * parv[2] = client to kick
 * parv[parc-1] = kick comment
 */
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;

  ClrFlag(sptr, FLAG_TS8);

  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 (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2)
      || !IsChanOp(member2))
    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);

  /* 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");

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

  if (!IsLocalChannel(name))
    sendcmdto_serv_butone(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);
    CheckDelayedJoins(chptr);
  } else
    sendcmdto_channel_butserv_butone(sptr, CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who,
                                     comment);

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

  return 0;
}
Пример #7
0
void do_names(struct Client* sptr, struct Channel* chptr, int filter)
{ 
  int mlen;
  int idx;
  int flag;
  int needs_space; 
  int len; 
  char buf[BUFSIZE];
  struct Client *c2ptr;
  struct Membership* member;
  
  assert(chptr);
  assert(sptr);
  assert((filter&NAMES_ALL) != (filter&NAMES_VIS));

  /* Tag Pub/Secret channels accordingly. */

  strcpy(buf, "* ");
  if (PubChannel(chptr))
    *buf = '=';
  else if (SecretChannel(chptr))
    *buf = '@';
 
  len = strlen(chptr->chname);
  strcpy(buf + 2, chptr->chname);
  strcpy(buf + 2 + len, " :");

  idx = len + 4;
  flag = 1;
  needs_space = 0;

  if (!ShowChannel(sptr, chptr)) /* Don't list private channels unless we are on them. */
    return;

  /* Iterate over all channel members, and build up the list. */

  mlen = strlen(cli_name(&me)) + 10 + strlen(cli_name(sptr));
  
  for (member = chptr->members; member; member = member->next_member)
  {
    c2ptr = member->user;

    if (((filter&NAMES_VIS)!=0) && IsInvisible(c2ptr))
      continue;

    if (IsZombie(member) && member->user != sptr)
      continue;

    if (IsDelayedJoin(member) && (member->user != sptr) && !(filter & NAMES_DEL))
        continue;

    if ((!IsDelayedJoin(member) || (member->user == sptr)) && (filter & NAMES_DEL))
        continue;

    if (needs_space)
      buf[idx++] = ' ';
    needs_space=1;
    if (IsZombie(member))
      buf[idx++] = '!';
    else if (IsChanOp(member))
      buf[idx++] = '@';
    else if (HasVoice(member))
      buf[idx++] = '+';
    strcpy(buf + idx, cli_name(c2ptr));
    idx += strlen(cli_name(c2ptr));
    flag = 1;
    if (mlen + idx + NICKLEN + 5 > BUFSIZE)
      /* space, modifier, nick, \r \n \0 */
    {
      send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf);
      idx = len + 4;
      flag = 0;
      needs_space=0;
    }
  }
  if (flag)
    send_reply(sptr, (filter & NAMES_DEL) ? RPL_DELNAMREPLY : RPL_NAMREPLY, buf); 
  if (filter&NAMES_EON)
    send_reply(sptr, RPL_ENDOFNAMES, chptr->chname);
}
Пример #8
0
/*
 * Send whois information for acptr to sptr
 */
static void do_whois(struct Client* sptr, struct Client *acptr, int parc)
{
  struct Client *a2cptr=0;
  struct Channel *chptr=0;
  int mlen;
  int len;
  static char buf[512];
  
  const struct User* user = cli_user(acptr);
  const char* name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr);  
  a2cptr = feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr)
      && sptr != acptr ? &his : user->server;
  assert(user);
  send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
		   cli_info(acptr));

  /* Display the channels this user is on. */
  if (!IsChannelService(acptr))
  {
    struct Membership* chan;
    mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name);
    len = 0;
    *buf = '\0';
    for (chan = user->channel; chan; chan = chan->next_channel)
    {
       chptr = chan->channel;
       
       if (!ShowChannel(sptr, chptr)
           && !(IsOper(sptr) && IsLocalChannel(chptr->chname)))
          continue;

       if (acptr != sptr && IsZombie(chan))
          continue;

       /* Don't show local channels when HIS is defined, unless it's a
	* remote WHOIS --ULtimaTe_
	*/
       if (IsLocalChannel(chptr->chname) && (acptr != sptr) && (parc == 2)
           && feature_bool(FEAT_HIS_WHOIS_LOCALCHAN) && !IsAnOper(sptr))
	  continue;

       if (len+strlen(chptr->chname) + mlen > BUFSIZE - 5)
       {
          send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS, "%s :%s", name, buf);
          *buf = '\0';
          len = 0;
       }
       if (IsDeaf(acptr))
         *(buf + len++) = '-';
       if (!ShowChannel(sptr, chptr))
         *(buf + len++) = '*';
       if (IsDelayedJoin(chan) && (sptr != acptr))
         *(buf + len++) = '<';
       else if (IsChanOp(chan))
         *(buf + len++) = '@';
       else if (HasVoice(chan))
         *(buf + len++) = '+';
       else if (IsZombie(chan))
         *(buf + len++) = '!';
       if (len)
          *(buf + len) = '\0';
       strcpy(buf + len, chptr->chname);
       len += strlen(chptr->chname);
       strcat(buf + len, " ");
       len++;
     }
     if (buf[0] != '\0')
        send_reply(sptr, RPL_WHOISCHANNELS, name, buf);
  }

  send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr),
             cli_info(a2cptr));

  if (user)
  {
    if (user->away)
       send_reply(sptr, RPL_AWAY, name, user->away);

    if (SeeOper(sptr,acptr))
       send_reply(sptr, RPL_WHOISOPERATOR, name);

    if (IsAccount(acptr))
      send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);

    if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr))
      send_reply(sptr, RPL_WHOISACTUALLY, name, user->username,
                 user->realhost, ircd_ntoa(&cli_ip(acptr)));

    /* Hint: if your looking to add more flags to a user, eg +h, here's
     *       probably a good place to add them :)
     */

    if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) ||
                             (sptr == acptr || IsAnOper(sptr) || parc >= 3)))
       send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
                  cli_firsttime(acptr));
  }
}