Пример #1
0
/*
 * ms_tmode()
 *
 * inputs	- parv[0] = UID
 *		  parv[1] = TS
 *		  parv[2] = channel name
 *		  parv[3] = modestring
 */
static void
ms_tmode(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
{
  struct Channel *chptr = NULL;
  struct Membership *member = NULL;

  if ((chptr = hash_find_channel(parv[2])) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
               ID_or_name(&me, client_p), ID_or_name(source_p, client_p), parv[2]);
    return;
  }

  if (atol(parv[1]) > chptr->channelts)
    return;

  if (IsServer(source_p))
    set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3, chptr->chname);
  else
  {
    member = find_channel_link(source_p, chptr);

    /* XXX are we sure we just want to bail here? */
    if (has_member_flags(member, CHFL_DEOPPED))
      return;

    set_channel_mode(client_p, source_p, chptr, member, parc - 3, parv + 3, chptr->chname);
  }
}
Пример #2
0
/* part_one_client()
 *
 * inputs	- pointer to server
 * 		- pointer to source client to remove
 *		- char pointer of name of channel to remove from
 * output	- none
 * side effects	- remove ONE client given the channel name 
 */
static void
part_one_client(struct Client *client_p, struct Client *source_p,
                const char *name, char *reason)
{
  struct Channel *chptr = NULL;
  struct Membership *ms = NULL;

  if ((chptr = hash_find_channel(name)) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
               me.name, source_p->name, name);
    return;
  }

  if ((ms = find_channel_link(source_p, chptr)) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
               me.name, source_p->name, name);
    return;
  }

  if (MyConnect(source_p) && !IsOper(source_p))
    check_spambot_warning(source_p, NULL);

  /*
   *  Remove user from the old channel (if any)
   *  only allow /part reasons in -m chans
   */
  if(msg_has_colors(reason) && (chptr->mode.mode & MODE_NOCOLOR)) 
    reason = strip_color(reason); 
  
  if (reason[0] && (!MyConnect(source_p) ||
      ((can_send(chptr, source_p, ms) &&
       (source_p->firsttime + ConfigFileEntry.anti_spam_exit_message_time)
        < CurrentTime))))
  {
    sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
                  ":%s PART %s :%s", ID(source_p), chptr->chname,
                  reason);
    sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
                  ":%s PART %s :%s", source_p->name, chptr->chname,
                  reason);
    sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s PART %s :%s",
                         source_p->name, source_p->username,
                         source_p->host, chptr->chname, reason);
  }
  else
  {
    sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
                  ":%s PART %s", ID(source_p), chptr->chname);
    sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
                  ":%s PART %s", source_p->name, chptr->chname);
    sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s PART %s",
                         source_p->name, source_p->username,
                         source_p->host, chptr->chname);
  }

  remove_user_from_channel(ms);
}
Пример #3
0
/*! \brief MODE command handler
 *
 * \param source_p Pointer to allocated Client struct from which the message
 *                 originally comes from.  This can be a local or remote client.
 * \param parc     Integer holding the number of supplied arguments.
 * \param parv     Argument vector where parv[0] .. parv[parc-1] are non-NULL
 *                 pointers.
 * \note Valid arguments for this command are:
 *      - parv[0] = command
 *      - parv[1] = channel or nick name
 *      - parv[2] = modes to be added or removed
 */
static int
m_mode(struct Client *source_p, int parc, char *parv[])
{
  struct Channel *chptr = NULL;

  if (EmptyString(parv[1]))
  {
    sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "MODE");
    return 0;
  }

  /* Now, try to find the channel in question */
  if (!IsChanPrefix(*parv[1]))
  {
    /* If here, it has to be a non-channel name */
    set_user_mode(source_p, parc, parv);
    return 0;
  }

  if ((chptr = hash_find_channel(parv[1])) == NULL)
  {
    sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]);
    return 0;
  }

  /* Now known the channel exists */
  if (parc < 3)
  {
    char modebuf[MODEBUFLEN] = "";
    char parabuf[MODEBUFLEN] = "";

    channel_modes(chptr, source_p, modebuf, parabuf);
    sendto_one_numeric(source_p, &me, RPL_CHANNELMODEIS, chptr->name, modebuf, parabuf);
    sendto_one_numeric(source_p, &me, RPL_CREATIONTIME, chptr->name, chptr->creationtime);
    return 0;
  }

  /*
   * bounce all modes from people we deop on sjoin
   * servers have always gotten away with murder,
   * including telnet servers *g* - Dianora
   */
  if (IsServer(source_p) || HasFlag(source_p, FLAGS_SERVICE))
    set_channel_mode(source_p, chptr, NULL, parc - 2, parv + 2);
  else
  {
    struct Membership *member = find_channel_link(source_p, chptr);

    /* Finish the flood grace period... */
    if (MyClient(source_p) && !IsFloodDone(source_p))
      if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0')))
        flood_endgrace(source_p);

    set_channel_mode(source_p, chptr, member, parc - 2, parv + 2);
  }

  return 0;
}
Пример #4
0
/*
 * m_mode - MODE command handler
 * parv[0] - sender
 * parv[1] - channel
 */
static void
m_mode(struct Client *client_p, struct Client *source_p,
       int parc, char *parv[])
{
  struct Channel *chptr = NULL;
  struct Membership *member;
  static char modebuf[MODEBUFLEN];
  static char parabuf[MODEBUFLEN];

  if (parv[1][0] == '\0')
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
               me.name, source_p->name, "MODE");
    return;
  }

  /* Now, try to find the channel in question */
  if (!IsChanPrefix(parv[1][0]))
  {
    /* if here, it has to be a non-channel name */
    set_user_mode(client_p, source_p, parc, parv);
    return;
  }

  if (!check_channel_name(parv[1]))
  { 
    sendto_one(source_p, form_str(ERR_BADCHANNAME),
               me.name, source_p->name, parv[1]);
    return;
  }

  chptr = hash_find_channel(parv[1]);

  if (chptr == NULL)
  {
      /* if chptr isn't found locally, it =could= exist
       * on the uplink. So ask.
       */
      
      /* LazyLinks */
      /* only send a mode upstream if a local client sent this request
       * -davidt
       */
      if (MyClient(source_p) && !ServerInfo.hub && uplink &&
	   IsCapable(uplink, CAP_LL))
	{
	  sendto_one(uplink, ":%s MODE %s %s",
                     ID_or_name(source_p, uplink),
		     parv[1], (parv[2] ? parv[2] : ""));
	  return;
	}
      else
	{
	  sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
		     me.name, parv[0], parv[1]);
	  return;
	}
    }

  /* Now known the channel exists */
  if (parc < 3)
  {
    channel_modes(chptr, source_p, modebuf, parabuf);
    sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
               me.name, parv[0], parv[1], modebuf, parabuf);
    sendto_one(source_p, form_str(RPL_CREATIONTIME),
               me.name, parv[0], parv[1], chptr->channelts);
  }
  /* bounce all modes from people we deop on sjoin
   * servers have always gotten away with murder,
   * including telnet servers *g* - Dianora
   *
   * XXX Is it worth the bother to make an ms_mode() ? - Dianora
   */
  else if (IsServer(source_p))
  {
    set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2,
                     chptr->chname);
  }
  else
  {
    member = find_channel_link(source_p, chptr);

    if (!has_member_flags(member, CHFL_DEOPPED))
    {
      /* Finish the flood grace period... */
      if (MyClient(source_p) && !IsFloodDone(source_p))
      {
        if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0')))
          flood_endgrace(source_p);
      }

      set_channel_mode(client_p, source_p, chptr, member, parc - 2, parv + 2,
                       chptr->chname);
    }
  }
}
Пример #5
0
/* build_target_list()
 *
 * inputs	- pointer to given source (oper/client etc.)
 *		- pointer to list of nicks/channels
 *		- pointer to table to place results
 *		- pointer to text (only used if source_p is an oper)
 * output	- number of valid entities
 * side effects	- target_table is modified to contain a list of
 *		  pointers to channels or clients
 *		  if source client is an oper
 *		  all the classic old bizzare oper privmsg tricks
 *		  are parsed and sent as is, if prefixed with $
 *		  to disambiguate.
 *
 */
static int
build_target_list(int p_or_n, const char *command, struct Client *source_p,
                  char *nicks_channels, const char *text)
{
  int type = 0;
  char *p = NULL, *nick = NULL;
  char *target_list = NULL;
  struct Channel *chptr = NULL;
  struct Client *target_p = NULL;

  target_list = nicks_channels;

  ntargets = 0;

  for (nick = strtoken(&p, target_list, ","); nick;
       nick = strtoken(&p,        NULL, ","))
  {
    const char *with_prefix = NULL;

    /*
     * Channels are privmsg'd a lot more than other clients, moved up
     * here plain old channel msg?
     */
    if (IsChanPrefix(*nick))
    {
      if ((chptr = hash_find_channel(nick)))
      {
        if (!duplicate_ptr(chptr))
        {
          if (ntargets >= ConfigGeneral.max_targets)
          {
            sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
                               nick, ConfigGeneral.max_targets);
            return 1;
          }

          targets[ntargets].ptr = chptr;
          targets[ntargets++].type = ENTITY_CHANNEL;
        }
      }
      else
      {
        if (p_or_n != NOTICE)
          sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
      }

      continue;
    }

    /* Look for a PRIVMSG/NOTICE to another client */
    if ((target_p = find_person(source_p, nick)))
    {
      if (!duplicate_ptr(target_p))
      {
        if (ntargets >= ConfigGeneral.max_targets)
        {
          sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
                             nick, ConfigGeneral.max_targets);
          return 1;
        }

        targets[ntargets].ptr = target_p;
        targets[ntargets].type = ENTITY_CLIENT;
        targets[ntargets++].flags = 0;
      }

      continue;
    }

    /* @#channel or +#channel message ? */
    type = 0;
    with_prefix = nick;

    /* Allow %+@ if someone wants to do that */
    while (1)
    {
      if (*nick == '@')
        type |= CHFL_CHANOP;
      else if (*nick == '%')
        type |= CHFL_CHANOP | CHFL_HALFOP;
      else if (*nick == '+')
        type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
      else
        break;
      ++nick;
    }

    if (type)
    {
      if (EmptyString(nick))  /* If it's a '\0' dump it, there is no recipient */
      {
        sendto_one_numeric(source_p, &me, ERR_NORECIPIENT, command);
        continue;
      }

      /*
       * At this point, nick+1 should be a channel name i.e. #foo or &foo
       * if the channel is found, fine, if not report an error
       */
      if ((chptr = hash_find_channel(nick)))
      {
        if (IsClient(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
        {
          if (!has_member_flags(find_channel_link(source_p, chptr),
                                CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
          {
            sendto_one_numeric(source_p, &me, ERR_CHANOPRIVSNEEDED, with_prefix);
            return -1;
          }
        }

        if (!duplicate_ptr(chptr))
        {
          if (ntargets >= ConfigGeneral.max_targets)
          {
            sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
                               nick, ConfigGeneral.max_targets);
            return 1;
          }

          targets[ntargets].ptr = chptr;
          targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
          targets[ntargets++].flags = type;
        }
      }
      else
      {
        if (p_or_n != NOTICE)
          sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
      }

      continue;
    }

    if (*nick == '$' || strchr(nick, '@'))
      handle_special(p_or_n, command, source_p, nick, text);
    else
    {
      if (p_or_n != NOTICE)
      {
        if (!IsDigit(*nick) || MyClient(source_p))
          sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
      }
    }
  }

  return 1;
}
Пример #6
0
/*
** m_invite
**      parv[0] - sender prefix
**      parv[1] - user to invite
**      parv[2] - channel name
**      parv[3] - invite timestamp
*/
static void
m_invite(struct Client *client_p, struct Client *source_p,
         int parc, char *parv[])
{
  struct Client *target_p = NULL;
  struct Channel *chptr = NULL;
  struct Membership *ms = NULL;

  if (IsServer(source_p))
    return;

  if (EmptyString(parv[2]))
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
               me.name, source_p->name, "INVITE");
    return;
  }

  if (MyClient(source_p) && !IsFloodDone(source_p))
    flood_endgrace(source_p);

  if ((target_p = find_person(client_p, parv[1])) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHNICK),
               me.name, source_p->name, parv[1]);
    return;
  }

  /* Do not send local channel invites to users if they are not on the
   * same server as the person sending the INVITE message. 
   */
  /* Possibly should be an error sent to source_p */
  /* done .. there should be no problem because MyConnect(source_p) should
   * always be true if parse() and such is working correctly --is
   */
  if (!MyConnect(target_p) && (*parv[2] == '&'))
  {
    if (ConfigServerHide.hide_servers == 0)
      sendto_one(source_p, form_str(ERR_USERNOTONSERV),
                 me.name, source_p->name, target_p->name);
    return;
  }

  if ((chptr = hash_find_channel(parv[2])) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
               me.name, source_p->name, parv[2]);
    return;
  }

  if (MyConnect(source_p) && (ms = find_channel_link(source_p, chptr)) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
               me.name, source_p->name, chptr->chname);
    return;
  }

  if (MyConnect(source_p) && !has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP))
  {
    sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
               me.name, source_p->name, chptr->chname);
    return;
  }

  if ((chptr->mode.mode & MODE_OPERONLY))
  {
    if (MyConnect(source_p) && !IsOper(source_p))
    {
      sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
                 me.name, source_p->name, chptr->chname);
      return;
    }
  }

  if (IsMember(target_p, chptr))
  {
    sendto_one(source_p, form_str(ERR_USERONCHANNEL),
               me.name, source_p->name, target_p->name, chptr->chname);
    return;
  }

  if (MyConnect(source_p))
  {
    sendto_one(source_p, form_str(RPL_INVITING), me.name,
               source_p->name, target_p->name, chptr->chname);

    if (target_p->away)
      sendto_one(source_p, form_str(RPL_AWAY),
                 me.name, source_p->name, target_p->name,
                 target_p->away);
  }
  else if (parc > 3 && IsDigit(*parv[3]))
    if (atoi(parv[3]) > chptr->channelts)
      return;

  if (MyConnect(target_p))
  {
    sendto_one(target_p, ":%s!%s@%s INVITE %s :%s",
               source_p->name, source_p->username,
               source_p->host,
               target_p->name, chptr->chname);

    if (chptr->mode.mode & MODE_INVITEONLY)
    {
      sendto_channel_local(CHFL_CHANOP|CHFL_HALFOP, 0, chptr,
                             ":%s NOTICE %s :%s is inviting %s to %s.",
                             me.name, chptr->chname, source_p->name,
                             target_p->name, chptr->chname);
      sendto_channel_remote(source_p, client_p, CHFL_CHANOP|CHFL_HALFOP,
                              NOCAPS, NOCAPS, chptr,
                              ":%s NOTICE %s :%s is inviting %s to %s.",
                              source_p->name, chptr->chname, source_p->name,
                              target_p->name, chptr->chname);

      /* Add the invite if channel is +i */
      add_invite(chptr, target_p);
    }
  }
  else if (target_p->from != client_p)
    sendto_one(target_p, ":%s INVITE %s %s %lu",
               ID_or_name(source_p, target_p->from),
               ID_or_name(target_p, target_p->from),
               chptr->chname, (unsigned long)chptr->channelts);
}
Пример #7
0
/* m_topic()
 *  parv[0] = sender prefix
 *  parv[1] = channel name
 *  parv[2] = new topic, if setting topic
 */
static void
m_topic(struct Client *client_p, struct Client *source_p,
        int parc, char *parv[])
{
  struct Channel *chptr = NULL;
  char *p;
  struct Membership *ms;
  const char *from, *to;

  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
  {
    from = me.id;
    to = source_p->id;
  }
  else
  {
    from = me.name;
    to = source_p->name;
  }

  if ((p = strchr(parv[1], ',')) != NULL)
    *p = '\0';

  if (EmptyString(parv[1]))
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
               from, to, "TOPIC");
    return;
  }

  if (MyClient(source_p) && !IsFloodDone(source_p))
    flood_endgrace(source_p);

  if (IsChanPrefix(*parv[1]))
  {
    if ((chptr = hash_find_channel(parv[1])) == NULL)
    {
      sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
                 from, to, parv[1]);
      return;
    }

    /* setting topic */
    if (parc > 2)
    {
      if ((ms = find_channel_link(source_p, chptr)) == NULL && !IsService(source_p))
      {
        sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name,
                   source_p->name, parv[1]);
        return;
      }

      if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
          has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) || IsGod(source_p) ||
          IsService(source_p))
      {
        char topic_info[USERHOST_REPLYLEN]; 
        if(!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP) && 
                IsGod(source_p) && MyClient(source_p) &&
                (chptr->mode.mode & MODE_TOPICLIMIT) != 0)
        {              
          char tmp[IRCD_BUFSIZE];           
          ircsprintf(tmp, "%s is using God mode: TOPIC %s %s", source_p->name, 
                  chptr->chname, parv[2]);              
          sendto_gnotice_flags(UMODE_SERVNOTICE, L_ALL, me.name, &me, NULL, 
                  tmp);
          oftc_log(tmp);
        }
        ircsprintf(topic_info, "%s!%s@%s",
                   source_p->name, source_p->username, source_p->host);
        set_channel_topic(chptr, parv[2], topic_info, CurrentTime);

        sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
                      ":%s TOPIC %s :%s",
                      ID(source_p), chptr->chname,
                      chptr->topic == NULL ? "" : chptr->topic);
        sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
                      ":%s TOPIC %s :%s",
                      source_p->name, chptr->chname,
                      chptr->topic == NULL ? "" : chptr->topic);
        sendto_channel_local(ALL_MEMBERS, NO,
                             chptr, ":%s!%s@%s TOPIC %s :%s",
                             source_p->name,
                             source_p->username,
                             source_p->host,
                             chptr->chname, chptr->topic == NULL ?
                             "" : chptr->topic);
      }
      else
        sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
                   from, to, chptr->chname);
    }
    else /* only asking for topic */
    {
      if (!SecretChannel(chptr) || IsMember(source_p, chptr))
      {
        if (chptr->topic == NULL)
          sendto_one(source_p, form_str(RPL_NOTOPIC),
                     from, to, chptr->chname);
        else
        {
          sendto_one(source_p, form_str(RPL_TOPIC),
                     from, to,
                     chptr->chname, chptr->topic);

          sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
                     from, to, chptr->chname,
                     chptr->topic_info,
                     chptr->topic_time);
        }
      }
      else
      {
        sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
                   from, to, chptr->chname);
        return;
      }
    }
  }
  else
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
               from, to, parv[1]);
  }
}
Пример #8
0
/* build_target_list()
 *
 * inputs	- pointer to given client_p (server)
 *		- pointer to given source (oper/client etc.)
 *		- pointer to list of nicks/channels
 *		- pointer to table to place results
 *		- pointer to text (only used if source_p is an oper)
 * output	- number of valid entities
 * side effects	- target_table is modified to contain a list of
 *		  pointers to channels or clients
 *		  if source client is an oper
 *		  all the classic old bizzare oper privmsg tricks
 *		  are parsed and sent as is, if prefixed with $
 *		  to disambiguate.
 *
 */
static int
build_target_list(int p_or_n, const char *command, struct Client *client_p,
		  struct Client *source_p, char *nicks_channels, char *text)
{
	int type;
	char *p = NULL, *nick, *target_list, ncbuf[IRCD_BUFSIZE];
	struct Channel *chptr = NULL;
	struct Client *target_p = NULL;

	/* Sigh, we can't mutilate parv[1] incase we need it to send to a hub */
	if(!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
	{
		strlcpy(ncbuf, nicks_channels, sizeof(ncbuf));
		target_list = ncbuf;
	}
	else
		  target_list = nicks_channels;	/* skip strcpy for non-lazyleafs */

	ntargets = 0;

	for(nick = strtoken(&p, target_list, ","); nick; nick = strtoken(&p, NULL, ","))
	{
		char *with_prefix;
		/*
		 * channels are privmsg'd a lot more than other clients, moved up
		 * here plain old channel msg?
		 */

		if(IsChanPrefix(*nick))
		{
			/* ignore send of local channel to a server (should not happen) */
			if(*nick == '&' && IsServer(client_p))
				continue;

			if((chptr = hash_find_channel(nick)) != NULL)
			{
				if(!duplicate_ptr(chptr))
				{
					if(ntargets >= ConfigFileEntry.max_targets)
					{
						sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
							   ID_or_name(&me, client_p),
							   ID_or_name(source_p, client_p), nick,
							   ConfigFileEntry.max_targets);
						return (1);
					}
					targets[ntargets].ptr = (void *) chptr;
					targets[ntargets++].type = ENTITY_CHANNEL;
				}
			}
			else
			{
				if(!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
					return -1;
				else if(p_or_n != NOTICE)
					sendto_one(source_p, form_str(ERR_NOSUCHNICK),
						   ID_or_name(&me, client_p),
						   ID_or_name(source_p, client_p), nick);
			}
			continue;
		}

		/* look for a privmsg to another client */
		if((target_p = find_person(client_p, nick)) != NULL)
		{
			if(!duplicate_ptr(target_p))
			{
				if(ntargets >= ConfigFileEntry.max_targets)
				{
					sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
						   ID_or_name(&me, client_p),
						   ID_or_name(source_p, client_p), nick,
						   ConfigFileEntry.max_targets);
					return (1);
				}
				targets[ntargets].ptr = (void *) target_p;
				targets[ntargets].type = ENTITY_CLIENT;
				targets[ntargets++].flags = 0;
			}
			continue;
		}

		/* @#channel or +#channel message ? */

		type = 0;
		with_prefix = nick;
		/*  allow ~&%+@ if someone wants to do that */
		for(;;)
		{
#ifdef CHANAQ
			if(*nick == '~')
				type |= CHFL_OWNER;
			else if(*nick == '&')
				type |= CHFL_OWNER | CHFL_PROTECTED;
			else
#endif
			if(*nick == '@')
				type |= CHFL_OWNER | CHFL_PROTECTED | CHFL_CHANOP;
#ifdef HALFOPS
			else if(*nick == '%')
				type |= CHFL_OWNER | CHFL_PROTECTED | CHFL_CHANOP | CHFL_HALFOP;
#endif
			else if(*nick == '+')
				type |= CHFL_OWNER | CHFL_PROTECTED | CHFL_CHANOP | CHFL_HALFOP |
					CHFL_VOICE;
			else
				break;
			nick++;
		}

		if(type != 0)
		{
			/* suggested by Mortiis */
			if(*nick == '\0')	/* if its a '\0' dump it, there is no recipient */
			{
				sendto_one(source_p, form_str(ERR_NORECIPIENT),
					   ID_or_name(&me, client_p),
					   ID_or_name(source_p, client_p), command);
				continue;
			}

			/* At this point, nick+1 should be a channel name i.e. #foo or &foo
			 * if the channel is found, fine, if not report an error
			 */

			if((chptr = hash_find_channel(nick)) != NULL)
			{
				if(!has_member_flags(find_channel_link(source_p, chptr),
						     CHFL_OWNER | CHFL_PROTECTED | CHFL_CHANOP |
						     CHFL_HALFOP | CHFL_VOICE))
				{
					sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
						   ID_or_name(&me, client_p),
						   ID_or_name(source_p, client_p), with_prefix);
					return (-1);
				}

				if(!duplicate_ptr(chptr))
				{
					if(ntargets >= ConfigFileEntry.max_targets)
					{
						sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
							   ID_or_name(&me, client_p),
							   ID_or_name(source_p, client_p), nick,
							   ConfigFileEntry.max_targets);
						return (1);
					}
					targets[ntargets].ptr = (void *) chptr;
					targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
					targets[ntargets++].flags = type;
				}
			}
			else
			{
				if(!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
					return -1;
				else if(p_or_n != NOTICE)
					sendto_one(source_p, form_str(ERR_NOSUCHNICK),
						   ID_or_name(&me, client_p),
						   ID_or_name(source_p, client_p), nick);
			}
			continue;
		}

		if((*nick == '$') || strchr(nick, '@') != NULL)
		{
			handle_special(p_or_n, command, client_p, source_p, nick, text);
		}
		else
		{
			if(!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
				return -1;
			else if(p_or_n != NOTICE)
			{
				if(!IsDigit(*nick) || MyClient(source_p))
					sendto_one(source_p, form_str(ERR_NOSUCHNICK),
						   ID_or_name(&me, client_p),
						   ID_or_name(source_p, client_p), nick);
			}
		}
		/* continue; */
	}

	return (1);
}
Пример #9
0
/*! \brief TOPIC command handler
 *
 * \param source_p Pointer to allocated Client struct from which the message
 *                 originally comes from.  This can be a local or remote client.
 * \param parc     Integer holding the number of supplied arguments.
 * \param parv     Argument vector where parv[0] .. parv[parc-1] are non-NULL
 *                 pointers.
 * \note Valid arguments for this command are:
 *      - parv[0] = command
 *      - parv[1] = channel name
 *      - parv[2] = topic text, if setting topic
 */
static int
m_topic(struct Client *source_p, int parc, char *parv[])
{
  struct Channel *chptr = NULL;

  if (EmptyString(parv[1]))
  {
    sendto_one_numeric(source_p, &me, ERR_NEEDMOREPARAMS, "TOPIC");
    return 0;
  }

  if (!IsFloodDone(source_p))
    flood_endgrace(source_p);

  if ((chptr = hash_find_channel(parv[1])) == NULL)
  {
    sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, parv[1]);
    return 0;
  }

  /* setting topic */
  if (parc > 2)
  {
    const struct Membership *member = NULL;

    if ((member = find_channel_link(source_p, chptr)) == NULL)
    {
      sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->name);
      return 0;
    }

    if (!(chptr->mode.mode & MODE_TOPICLIMIT) ||
        has_member_flags(member, CHFL_CHANOP|CHFL_HALFOP))
    {
      char topic_info[USERHOST_REPLYLEN];

      snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name,
               source_p->username, source_p->host);
      channel_set_topic(chptr, parv[2], topic_info, CurrentTime, 1);

      sendto_server(source_p, 0, 0, ":%s TOPIC %s :%s",
                    source_p->id, chptr->name,
                    chptr->topic);
      sendto_channel_local(0, chptr, ":%s!%s@%s TOPIC %s :%s",
                           source_p->name,
                           source_p->username,
                           source_p->host,
                           chptr->name, chptr->topic);
    }
    else
      sendto_one_numeric(source_p, &me, ERR_CHANOPRIVSNEEDED, chptr->name);
  }
  else /* only asking for topic */
  {
    if (!SecretChannel(chptr) || IsMember(source_p, chptr))
    {
      if (chptr->topic[0] == '\0')
        sendto_one_numeric(source_p, &me, RPL_NOTOPIC, chptr->name);
      else
      {
        sendto_one_numeric(source_p, &me, RPL_TOPIC,
                           chptr->name, chptr->topic);
        sendto_one_numeric(source_p, &me, RPL_TOPICWHOTIME, chptr->name,
                           chptr->topic_info,
                           chptr->topic_time);
      }
    }
    else
      sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->name);
  }

  return 0;
}
Пример #10
0
/* m_kick()
 *  parv[0] = sender prefix
 *  parv[1] = channel
 *  parv[2] = client to kick
 *  parv[3] = kick comment
 */
static void 
m_kick(struct Client *client_p, struct Client *source_p,
       int parc, char *parv[])
{
  struct Client *who;
  struct Channel *chptr;
  int chasing = 0;
  int gmode_used = 0;
  char *comment;
  char *name;
  char *p = NULL;
  char *user;
  const char *from, *to;
  struct Membership *ms = NULL;
  struct Membership *ms_target;

  if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
  {
    from = me.id;
    to = source_p->id;
  }
  else
  {
    from = me.name;
    to = source_p->name;
  }

  if (*parv[2] == '\0')
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
               from, to, "KICK");
    return;
  }

  if (MyClient(source_p) && !IsFloodDone(source_p))
    flood_endgrace(source_p);

  comment = (EmptyString(parv[3])) ? parv[2] : parv[3];
  if (strlen(comment) > (size_t)KICKLEN)
    comment[KICKLEN] = '\0';

  name = parv[1];
  while (*name == ',')
    name++;

  if ((p = strchr(name,',')) != NULL)
    *p = '\0';
  if (*name == '\0')
    return;

  if ((chptr = hash_find_channel(name)) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
               from, to, name);
    return;
  }

  if (!IsServer(source_p))
  {
    if ((ms = find_channel_link(source_p, chptr)) == NULL)
    {
      if (MyConnect(source_p))
      {
        sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
                  me.name, source_p->name, name);
        return;
      }
    }

    if(chptr->mode.mode & MODE_NOCOLOR && msg_has_colors(comment))
        comment = strip_color(comment);
    if (!has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP))
    {
    /* was a user, not a server, and user isn't seen as a chanop here */
      if (IsGod(source_p) && MyConnect(source_p))
        gmode_used = TRUE;
      else if (MyConnect(source_p))
      {
        /* user on _my_ server, with no chanops.. so go away */
        sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
            me.name, source_p->name, name);
        return;
      }

      if (chptr->channelts == 0 && !IsGod(source_p))
      {
        /* If its a TS 0 channel, do it the old way */
        sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
              me.name, source_p->name, name);
        return;
      }
      /* Its a user doing a kick, but is not showing as chanop locally
       * its also not a user ON -my- server, and the channel has a TS.
       * There are two cases we can get to this point then...
       *
       *     1) connect burst is happening, and for some reason a legit
       *        op has sent a KICK, but the SJOIN hasn't happened yet or 
       *        been seen. (who knows.. due to lag...)
       *
       *     2) The channel is desynced. That can STILL happen with TS
       *        
       *     Now, the old code roger wrote, would allow the KICK to 
       *     go through. Thats quite legit, but lets weird things like
       *     KICKS by users who appear not to be chanopped happen,
       *     or even neater, they appear not to be on the channel.
       *     This fits every definition of a desync, doesn't it? ;-)
       *     So I will allow the KICK, otherwise, things are MUCH worse.
       *     But I will warn it as a possible desync.
       *
       *     -Dianora
       */
    }
  }

  user = parv[2];

  while (*user == ',')
    user++;

  if ((p = strchr(user, ',')) != NULL)
    *p = '\0';

  if (*user == '\0')
    return;

  if ((who = find_chasing(client_p, source_p, user, &chasing)) == NULL)
    return;

  if ((ms_target = find_channel_link(who, chptr)) != NULL)
  {
    if (IsGod(who))
    {
      char tmp[IRCD_BUFSIZE];
      ircsprintf(tmp, "%s is using God mode: to evade KICK from %s: %s %s %s",
          who->name, source_p->name, chptr->chname, parv[2], parv[3] ? parv[3] : "");
      sendto_gnotice_flags(UMODE_SERVNOTICE, L_ALL, me.name, &me, NULL, tmp);
      oftc_log(tmp);

      return;
    }

    if(IsService(who))
      return;

#ifdef HALFOPS
    /* half ops cannot kick other halfops on private channels */
    if (has_member_flags(ms, CHFL_HALFOP) && !has_member_flags(ms, CHFL_CHANOP))
    {
      if (((chptr->mode.mode & MODE_PRIVATE) && has_member_flags(ms_target,
        CHFL_CHANOP|CHFL_HALFOP)) || has_member_flags(ms_target, CHFL_CHANOP))
      {
        sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
                   me.name, source_p->name, name);
        return;
      }
    }
#endif

    /* jdc
     * - In the case of a server kicking a user (i.e. CLEARCHAN),
     *   the kick should show up as coming from the server which did
     *   the kick.
     * - Personally, flame and I believe that server kicks shouldn't
     *   be sent anyways.  Just waiting for some oper to abuse it...
     */
    if (IsServer(source_p))
      sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s KICK %s %s :%s",
                           source_p->name, name, who->name, comment);
    else
      sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s KICK %s %s :%s",
                           source_p->name, source_p->username,
                           source_p->host, name, who->name, comment);

    sendto_server(client_p, NULL, chptr, CAP_TS6, NOCAPS, NOFLAGS,
                  ":%s KICK %s %s :%s",
                  ID(source_p), chptr->chname, ID(who), comment);
    sendto_server(client_p, NULL, chptr, NOCAPS, CAP_TS6, NOFLAGS,
                  ":%s KICK %s %s :%s", source_p->name, chptr->chname,
                  who->name, comment);

    remove_user_from_channel(ms_target);
    if(gmode_used)
    {
      char tmp[IRCD_BUFSIZE];
      ircsprintf(tmp, "%s is using God mode: KICK %s %s %s",
          source_p->name, chptr->chname, parv[2], parv[3] ? parv[3] : "");
      sendto_gnotice_flags(UMODE_SERVNOTICE, L_ALL, me.name, &me, NULL, tmp);
      oftc_log(tmp);
    }
  }
  else
    sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
               from, to, user, name);
}
Пример #11
0
/*
 * m_mode - MODE command handler
 * parv[0] - sender
 * parv[1] - channel
 */
static void
m_mode(struct Client *client_p, struct Client *source_p,
       int parc, char *parv[])
{
  struct Channel *chptr = NULL;
  struct Membership *member;
  static char modebuf[MODEBUFLEN];
  static char parabuf[MODEBUFLEN];

  if (EmptyString(parv[1]))
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
               me.name, source_p->name, "MODE");
    return;
  }

  /* Now, try to find the channel in question */
  if (!IsChanPrefix(*parv[1]))
  {
    /* if here, it has to be a non-channel name */
    set_user_mode(client_p, source_p, parc, parv);
    return;
  }

  if ((chptr = hash_find_channel(parv[1])) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
	       ID_or_name(&me, source_p->from),
	       ID_or_name(source_p, source_p->from),
	       parv[1]);
    return;
  }

  /* Now known the channel exists */
  if (parc < 3)
  {
    channel_modes(chptr, source_p, modebuf, parabuf);
    sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
               me.name, source_p->name, chptr->chname, modebuf, parabuf);
    sendto_one(source_p, form_str(RPL_CREATIONTIME),
               me.name, source_p->name, chptr->chname, chptr->channelts);
  }
  /* bounce all modes from people we deop on sjoin
   * servers have always gotten away with murder,
   * including telnet servers *g* - Dianora
   *
   * XXX Is it worth the bother to make an ms_mode() ? - Dianora
   */
  else if (IsServer(source_p))
  {
    set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2,
                     chptr->chname);
  }
  else
  {
    member = find_channel_link(source_p, chptr);

    if (!has_member_flags(member, CHFL_DEOPPED))
    {
      /* Finish the flood grace period... */
      if (MyClient(source_p) && !IsFloodDone(source_p))
      {
        if (!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0')))
          flood_endgrace(source_p);
      }

      set_channel_mode(client_p, source_p, chptr, member, parc - 2, parv + 2,
                       chptr->chname);
    }
  }
}
Пример #12
0
/* m_topic()
 *  parv[0] = sender prefix
 *  parv[1] = channel name
 *  parv[2] = new topic, if setting topic
 */
static void
m_topic(struct Client *client_p, struct Client *source_p,
        int parc, char *parv[])
{
  struct Channel *chptr = NULL;

  if (EmptyString(parv[1]))
  {
    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
               me.name, source_p->name, "TOPIC");
    return;
  }

  if (!IsFloodDone(source_p))
    flood_endgrace(source_p);

  if ((chptr = hash_find_channel(parv[1])) == NULL)
  {
    sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
               me.name, source_p->name, parv[1]);
    return;
  }

  /* setting topic */
  if (parc > 2)
  {
    struct Membership *ms;

    if ((ms = find_channel_link(source_p, chptr)) == NULL)
    {
      sendto_one(source_p, form_str(ERR_NOTONCHANNEL), me.name,
                 source_p->name, parv[1]);
      return;
    }

    if (!(chptr->mode.mode & MODE_TOPICLIMIT) ||
        has_member_flags(ms, CHFL_CHANOP|CHFL_HALFOP))
    {
      char topic_info[USERHOST_REPLYLEN]; 

      snprintf(topic_info, sizeof(topic_info), "%s!%s@%s", source_p->name,
               source_p->username, source_p->host);
      set_channel_topic(chptr, parv[2], topic_info, CurrentTime, 1);

      sendto_server(client_p, CAP_TS6, NOCAPS,
                    ":%s TOPIC %s :%s",
                    ID(source_p), chptr->chname,
                    chptr->topic);
      sendto_server(client_p, NOCAPS, CAP_TS6,
                    ":%s TOPIC %s :%s",
                    source_p->name, chptr->chname,
                    chptr->topic);
      sendto_channel_local(ALL_MEMBERS, 0,
                           chptr, ":%s!%s@%s TOPIC %s :%s",
                           source_p->name,
                           source_p->username,
                           source_p->host,
                           chptr->chname, chptr->topic);
    }
    else
      sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
                 me.name, source_p->name, chptr->chname);
  }
  else /* only asking for topic */
  {
    if (!SecretChannel(chptr) || IsMember(source_p, chptr))
    {
      if (chptr->topic[0] == '\0')
        sendto_one(source_p, form_str(RPL_NOTOPIC),
                   me.name, source_p->name, chptr->chname);
      else
      {
        sendto_one(source_p, form_str(RPL_TOPIC),
                   me.name, source_p->name,
                   chptr->chname, chptr->topic);
        sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
                   me.name, source_p->name, chptr->chname,
                   chptr->topic_info,
                   chptr->topic_time);
      }
    }
    else
      sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
                 me.name, source_p->name, chptr->chname);
  }
}