Example #1
0
/*
** m_okick
**      parv[0] = sender prefix
**      parv[1] = channel
**      parv[2] = client to kick
**      parv[3] = kick comment
*/
static void m_okick(struct Client *client_p,
                  struct Client *source_p,
                  int parc,
                  char *parv[])
{
  struct Client *who;
  struct Channel *chptr;
  int   chasing = 0;
  char  *comment;
  char  *name;
  char  *p = NULL;
  char  *user;
  static char     buf[BUFSIZE];

  if (*parv[2] == '\0')
    {
      sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "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) TOPICLEN)
    comment[TOPICLEN] = '\0';

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

  name = parv[1];

  chptr = hash_find_channel(name);
  if (!chptr)
    {
      sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
                 me.name, parv[0], name);
      return;
    }


  if( (p = strchr(parv[2],',')) )
    *p = '\0';

  user = parv[2]; /* strtoken(&p2, parv[2], ","); */

  if (!(who = find_chasing(source_p, user, &chasing)))
    {
      return;
    }

  if (IsMember(who, chptr))
    {
      sendto_channel_local(ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
          me.name, chptr->chname, who->name, comment);
      sendto_server(&me, chptr, NOCAPS, NOCAPS,
                    ":%s KICK %s %s :%s",
                    me.name, chptr->chname,
                    who->name, comment);
      remove_user_from_channel(chptr, who);
   }
}
Example #2
0
/*
 * m_lljoin
 *      parv[0] = sender prefix
 *      parv[1] = channel
 *      parv[2] = nick ("!nick" == cjoin)
 *      parv[3] = key (optional)
 *
 * If a lljoin is received, from our uplink, join
 * the requested client to the given channel, or ignore it
 * if there is an error.
 *
 *   Ok, the way this works. Leaf client tries to join a channel, 
 * it doesn't exist so the join does a cburst request on behalf of the
 * client, and aborts that join. The cburst sjoin's the channel if it
 * exists on the hub, and sends back an LLJOIN to the leaf. Thats where
 * this is now..
 *
 */
static void
ms_lljoin(struct Client *client_p, struct Client *source_p,
          int parc, char *parv[])
{
  char *chname = NULL;
  char *nick = NULL;
  char *key = NULL;
  int  flags;
  int  i;
  struct Client *target_p;
  struct Channel *chptr;

  if (uplink && !IsCapable(uplink,CAP_LL))
  {
      sendto_realops_flags(UMODE_ALL, L_ALL,
			   "*** LLJOIN requested from non LL server %s",
			   client_p->name);
      return;
  }

  chname = parv[1];
  if(chname == NULL)
    return;

  nick = parv[2];
  if(nick == NULL)
    return;

  if (parc >3)
    key = parv[3];

  flags = 0;

  target_p = find_person(client_p, nick);

  if (!target_p)
    return;

  if (!MyClient(target_p))
    return;

  if (!check_channel_name(chname, 0))
  {
    sendto_gnotice_flags(UMODE_DEBUG, L_ALL, me.name, &me, NULL,
                         "*** Too long or invalid channel name from %s: %s",
                         target_p->name, chname);
    return;
  }

  chptr = make_channel(chname);
  flags = CHFL_CHANOP;
   
  if(!chptr)
    return;

  if (dlink_list_length(&chptr->members) == 0)
    flags = CHFL_CHANOP;
  else
    flags = 0;

  /* XXX in m_join.c :( */
  /* check_spambot_warning(target_p, chname); */

  /* They _could_ join a channel twice due to lag */
  if(chptr)
  {
    if (IsMember(target_p, chptr))    /* already a member, ignore this */
      return;
  }
  else
  {
    sendto_one(target_p, form_str(ERR_UNAVAILRESOURCE),
               me.name, nick, chptr->chname);
    return;
  }

  if ((i = can_join(target_p, chptr, key)))
  {
    sendto_one(target_p, form_str(i),
               me.name, nick, chptr->chname);
    return;
  }

  if ((dlink_list_length(&target_p->channel) >= ConfigChannel.max_chans_per_user) &&
      (!IsOper(target_p) || (dlink_list_length(&target_p->channel) >=
                             ConfigChannel.max_chans_per_user*3)))
  {
      sendto_one(target_p, form_str(ERR_TOOMANYCHANNELS),
		 me.name, nick, chptr->chname );
      return; 
  }
  
  if (flags == CHFL_CHANOP)
  {
      chptr->channelts = CurrentTime;

      sendto_one(uplink,
		 ":%s SJOIN %lu %s + :@%s",
		 me.name,
		 (unsigned long) chptr->channelts,
		 chptr->chname,
		 nick);
  }

  sendto_one(uplink,
             ":%s SJOIN %lu %s + :%s",
	     me.name,
	     (unsigned long) chptr->channelts,
	     chptr->chname,
	     nick);

  add_user_to_channel(chptr, target_p, flags, YES);

  sendto_channel_local(ALL_MEMBERS, NO, chptr,
		       ":%s!%s@%s JOIN :%s",
		       target_p->name,
		       target_p->username,
		       target_p->host,
		       chptr->chname);
  
  if (flags & CHFL_CHANOP)
  {
    chptr->mode.mode |= MODE_TOPICLIMIT;
    chptr->mode.mode |= MODE_NOPRIVMSGS;
      
    sendto_channel_local(ALL_MEMBERS, NO, chptr,
                         ":%s MODE %s +nt",
                         me.name, chptr->chname);
    sendto_one(uplink, 
               ":%s MODE %s +nt",
               me.name, chptr->chname);
  }

  channel_member_names(target_p, chptr, 1);
}
Example #3
0
/* parse_resv()
 *
 * inputs	- source_p, NULL supported
 *		- thing to resv
 *		- time_t if tkline
 *		- reason
 * outputs	- none
 * side effects	- parse resv, create if valid
 */
static void
parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason)
{
  if (IsChanPrefix(*name))
  {
    struct MaskItem *conf = NULL;

    if ((conf = create_resv(name, reason, NULL)) == NULL)
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":A RESV has already been placed on channel: %s", name);

      return;
    }

    conf->setat = CurrentTime;
    SetConfDatabase(conf);

    if (tkline_time)
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":A %d minute %s RESV has been placed on channel: %s",
                          tkline_time/60, (MyClient(source_p) ? "local" : "remote"), name);

      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
                           "%s has placed a %d minute %s RESV on channel: %s [%s]",
                           get_oper_name(source_p),
                           tkline_time/60,
                           (MyClient(source_p) ? "local" : "remote"),
                           conf->name, conf->reason);
      ilog(LOG_TYPE_RESV, "%s added temporary %d min. RESV for [%s] [%s]",
           get_oper_name(source_p), (int)tkline_time/60,
           conf->name, conf->reason);
      conf->until = CurrentTime + tkline_time;
    }
    else
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":A %s RESV has been placed on channel %s",
                          (MyClient(source_p) ? "local" : "remote"), name);

      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
                           "%s has placed a %s RESV on channel %s : [%s]",
                           get_oper_name(source_p),
                           (MyClient(source_p) ? "local" : "remote"),
                           conf->name, conf->reason);
      ilog(LOG_TYPE_RESV, "%s added RESV for [%s] [%s]",
           get_oper_name(source_p), conf->name, conf->reason);
    }
  }
  else
  {
    struct MaskItem *conf = NULL;

    if (!valid_wild_card_simple(name))
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":Please include at least %u non-wildcard characters with the resv",
                          ConfigGeneral.min_nonwildcard_simple);

      return;
    }

    if (!HasUMode(source_p, UMODE_ADMIN) && has_wildcards(name))
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":You must be an admin to perform a wildcard RESV");

      return;
    }

    if ((conf = create_resv(name, reason, NULL)) == NULL)
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":A RESV has already been placed on nick %s", name);

      return;
    }

    conf->setat = CurrentTime;
    SetConfDatabase(conf);

    if (tkline_time)
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":A %d minute %s RESV has been placed on nick %s : [%s]",
                          tkline_time/60, (MyClient(source_p) ? "local" : "remote"),
                          conf->name, conf->reason);

      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
                           "%s has placed a %d minute %s RESV on nick %s : [%s]",
                           get_oper_name(source_p), tkline_time/60,
                           (MyClient(source_p) ? "local" : "remote"),
                           conf->name, conf->reason);
      ilog(LOG_TYPE_RESV, "%s added temporary %d min. RESV for [%s] [%s]",
           get_oper_name(source_p), (int)tkline_time/60, conf->name, conf->reason);
      conf->until = CurrentTime + tkline_time;
    }
    else
    {
      if (IsClient(source_p))
        sendto_one_notice(source_p, &me, ":A %s RESV has been placed on nick %s : [%s]",
                          (MyClient(source_p) ? "local" : "remote"), conf->name, conf->reason);

      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
                           "%s has placed a %s RESV on nick %s : [%s]",
                           get_oper_name(source_p),
                           (MyClient(source_p) ? "local" : "remote"),
                           conf->name, conf->reason);
      ilog(LOG_TYPE_RESV, "%s added RESV for [%s] [%s]",
           get_oper_name(source_p), conf->name, conf->reason);
    }
  }
}
Example #4
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]);
  }
}
Example #5
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);
}
Example #6
0
/*
** m_kick
**      parv[1] = channel
**      parv[2] = client to kick
**      parv[3] = kick comment
*/
static int
m_kick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct membership *msptr;
	struct Client *who;
	struct Channel *chptr;
	int chasing = 0;
	char *comment;
	const char *name;
	char *p = NULL;
	char text[10];
	const char *user;
	static char buf[BUFSIZE];
	int is_override = 0;

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

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

	name = parv[1];

	chptr = find_channel(name);
	if(chptr == NULL)
	{
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
		return 0;
	}

	user = parv[2];		/* strtoken(&p2, parv[2], ","); */

	if(!(who = find_chasing(source_p, user, &chasing)))
	{
		return 0;
	}

	if(!IsServer(source_p))
	{
		msptr = find_channel_membership(chptr, source_p);

		if((msptr == NULL) && MyConnect(source_p))
		{
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					   form_str(ERR_NOTONCHANNEL), name);
			return 0;
		}

		if(!can_kick_deop(msptr, find_channel_membership(chptr, who)))
		{
			if(MyConnect(source_p))
			{
				if(IsOverride(source_p))
					is_override = 1;
				else
				{
					sendto_one(source_p, ":%s 482 %s %s :You do not have the proper privileges to kick this user",
							me.name, source_p->name, name);
					return 0;
				}
			}

			/* If its a TS 0 channel, do it the old way */
			else if(chptr->channelts == 0)
			{
				sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
					   get_id(&me, source_p), get_id(source_p, source_p), name);
				return 0;
			}
		}

		/* 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
		 */
	}

	if((p = strchr(parv[2], ',')))
		*p = '\0';

	msptr = find_channel_membership(chptr, who);

	if(msptr != NULL)
	{
		if(MyClient(source_p) && IsService(who))
		{
			sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
				   me.name, source_p->name, who->name, chptr->chname);
			return 0;
		}

		if(MyClient(source_p) && chptr->mode.mode & MODE_NOKICK)
		{
			sendto_one_numeric(source_p, ERR_NOKICK,
					form_str(ERR_NOKICK),
					chptr->chname);
			return 0;
		}

		if (MyClient(source_p) && chptr->mode.mode & MODE_NOOPERKICK && IsOper(who))
		{
			sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
					"Overriding KICK from %s on %s in %s (channel is +M)",
					source_p->name, who->name, chptr->chname);
			sendto_one_numeric(source_p, ERR_ISCHANSERVICE,
					"%s %s :Cannot kick IRC operators from that channel.",
					who->name, chptr->chname);
			return 0;
		}

		if(MyClient(source_p))
		{
			hook_data_channel_approval hookdata;

			hookdata.client = source_p;
			hookdata.chptr = chptr;
			hookdata.target = who;
			hookdata.approved = 1;

			call_hook(h_can_kick, &hookdata);

			if (!hookdata.approved)
				return 0;
		}

		comment = LOCAL_COPY((EmptyString(parv[3])) ? who->name : parv[3]);
		if(strlen(comment) > (size_t) REASONLEN)
			comment[REASONLEN] = '\0';

		if(is_override)
		{
			sendto_wallops_flags(UMODE_WALLOP, &me,
					"%s is overriding KICK [%s] on [%s] [%s]",
					get_oper_name(source_p), who->name, chptr->chname, comment);
			sendto_server(NULL, chptr, NOCAPS, NOCAPS,
					":%s WALLOPS :%s is overriding KICK [%s] on [%s] [%s]",
					me.name, get_oper_name(source_p), who->name, chptr->chname, comment);
		}

		/* 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, chptr, ":%s KICK %s %s :%s",
					     source_p->name, name, who->name, comment);
		else
			sendto_channel_local(ALL_MEMBERS, 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, chptr, CAP_TS6, NOCAPS,
			      ":%s KICK %s %s :%s",
			      use_id(source_p), chptr->chname, use_id(who), comment);
		remove_user_from_channel(msptr);

		rb_snprintf(text, sizeof(text), "K%s", who->id);

		/* we don't need to track NOREJOIN stuff unless it's our client being kicked */
		if(MyClient(who) && chptr->mode.mode & MODE_NOREJOIN)
			channel_metadata_time_add(chptr, text, rb_current_time(), "KICKNOREJOIN");
	}
	else if (MyClient(source_p))
		sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
				   form_str(ERR_USERNOTINCHANNEL), user, name);

	return 0;
}
Example #7
0
int
m_scan_idle(struct Client *cptr, struct Client *sptr, int parc, char *parv[], char *varparv[])
{
	struct Client *ptr, *target = NULL;
	char *eptr, buffer[321];
	int idle_time, check_time, len = 0, count = 0;

	if(MyClient(sptr) && !HasUmode(sptr, UMODE_USER_AUSPEX))
	{
		if(SeesOperMessages(sptr))
			sendto_one(sptr,":%s NOTICE %s :You have no a umode", me.name, parv[0]);
		else
			sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}

	if(parc < 3)
	{
		if (!IsServer(sptr))
			sendto_one(sptr, form_str(ERR_NEEDMOREPARAMS),
					me.name, parv[0], "SCAN IDLE");
		return 0;
	}

	idle_time = strtoul(parv[2], &eptr, 10);
	if(eptr == parv[2])
		return 0;
	/* Store the timestamp which last_sent should be >= to save time */
	check_time = CurrentTime - idle_time;

	/* If the query is for another server, pass it on and return. */
	if(parc > 3)
	{
		if(MyClient(sptr) && !HasUmode(sptr, UMODE_REMOTEINFO))
		{
			if(SeesOperMessages(sptr))
				sendto_one(sptr,":%s NOTICE %s :You have no S umode(cannot send remote)", me.name, parv[0]);
			else
				sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
			return 0;
		}

		if(!irccmp(parv[3], "GLOBAL") || !irccmp(parv[3], "*"))
			sendto_serv_butone(cptr, ":%s SCAN IDLE %d *", parv[0], idle_time);
		else if((target = find_server(parv[3])) == NULL) {
			sendto_one(sptr, form_str(ERR_NOSUCHSERVER),
					me.name, parv[0], parv[3]);
			return 0;
		}else if(!IsMe(target)) { /* But only if the query is not on us... */

			sendto_prefix_one(target, sptr, ":%s SCAN IDLE %d %s", parv[0],
					idle_time, target->name);
			return 0;
		}
	}

	buffer[0] = '\0';
	for(ptr = local_cptr_list; ptr; ptr = ptr->next_local_client)
	{
		if(ptr->user->last_sent < check_time)
			continue;

		if(len + strlen(ptr->name) > 319)
		{
			buffer[len - 1] = '\0'; /* Strip the trailing space */
			send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer);
			buffer[0] = '\0';
			len = 0;
		}

		strcat(buffer, ptr->name);
		strcat(buffer, " ");
		len += strlen(ptr->name) + 1;
		count++;
	}

	if(buffer[0])
	{
		buffer[len - 1] = '\0';
		send_markup(sptr, &me, "SCAN-IDLE", "%d %s", idle_time, buffer);
	}

	send_markup(sptr, &me, "IDLE-END", "End of idle listing");
	if(count > 0 || target || parc == 3) /* Don't give a summary for globals if no results matched */
		send_markup(sptr, &me, "SCAN-SUMMARY", "%d matched", count);

	return 0;
}
Example #8
0
/*
 * m_mode - MODE command handler
 * parv[1] - channel
 */
static int
m_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr = NULL;
	struct membership *msptr;
	int n = 2;
	const char *dest;
	int operspy = 0;

	dest = parv[1];

	if(IsOperSpy(source_p) && *dest == '!')
	{
		dest++;
		operspy = 1;

		if(EmptyString(dest))
		{
			sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
				   me.name, source_p->name, "MODE");
			return 0;
		}
	}

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

	if(!check_channel_name(dest))
	{
		sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]);
		return 0;
	}

	chptr = find_channel(dest);

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

	/* Now know the channel exists */
	if(parc < n + 1)
	{
		if(operspy)
			report_operspy(source_p, "MODE", chptr->chname);

		sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
			   me.name, source_p->name, parv[1],
			   operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p));

		sendto_one(source_p, form_str(RPL_CREATIONTIME),
			   me.name, source_p->name, parv[1], chptr->channelts);
	}
	else
	{
		msptr = find_channel_membership(chptr, source_p);

		/* 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, msptr, parc - n, parv + n);
	}

	return 0;
}
Example #9
0
/*
 * msg_channel
 *
 * inputs	- flag privmsg or notice
 * 		- pointer to command "PRIVMSG" or "NOTICE"
 *		- pointer to client_p
 *		- pointer to source_p
 *		- pointer to channel
 * output	- NONE
 * side effects	- message given channel
 */
static void
msg_channel(int p_or_n, char *command,
            struct Client *client_p,
            struct Client *source_p, struct Channel *chptr, char *text)
{
  struct Channel *vchan = NULL;
  char *chname = NULL;
  int result;

  chname = RootChan(chptr)->chname;

#ifdef VCHANS
  if (HasVchans(chptr))
    vchan = map_vchan(chptr, source_p);
#endif
  
  if (!vchan)
    vchan = chptr;

  if (MyClient(source_p))
  {
    /* idle time shouldnt be reset by notices --fl */
    if ((p_or_n != NOTICE) && source_p->user)
      source_p->user->last = CurrentTime;
  }

  /* chanops and voiced can flood their own channel with impunity */
  if ((result = can_send(vchan, source_p)))
  {
    if (result == CAN_SEND_NOTREG)
	{
	  if (p_or_n != NOTICE)
	    sendto_one(source_p, form_str(source_p,ERR_CANNOTSENDNOTREG),
		       me.name, source_p->name, chname);
	  return;
	}
    if (result == CAN_SEND_OPV ||
        !flood_attack_channel(p_or_n, source_p, vchan, chname))
    {
		dlink_node *ptr;
		struct Ban *banptr;
		char strbuf[BUFSIZE+1], buf[TOPICLEN+1];
		char *word, *subst, *p = buf;
		int drop = 0;

		if (MyClient(source_p) && IsPerson(source_p))
		if (!is_chan_op(vchan, source_p) && NoRepeatChannel(vchan))
		if (check_repeat(source_p, vchan, text)) {
			sendto_one(source_p, form_str(source_p,ERR_NOREPEATING),
				me.name, source_p->name, chname);
			return;
		}

	  if (NoColorChannel(vchan)) 
	    /*strip_color(text);*/
	    text = strip_color(text, 0);

	  strncpy(strbuf, text, BUFSIZE)[BUFSIZE] = 0;

	  if (MyClient(source_p) && IsPerson(source_p))
	  if (!is_chan_op(vchan, source_p))
	  for (ptr = vchan->substlist.head; ptr; ptr = ptr->next, p = buf) {
		  banptr = ptr->data; 
		  strncpy(buf, banptr->banstr, TOPICLEN)[TOPICLEN] = 0;

		  while (*p) 
			  if (*p++ == '$')
				  *(p-1) = ' ';

		  subst = strchr(buf, '/'); if (subst) {
			  *subst++ = 0; word = buf;
			  if (strstr(strbuf, word) && !irccmp(subst, "&"))
			  	drop = 1;
			  replace(strbuf, word, subst, BUFSIZE);
			  strbuf[BUFSIZE] = 0;
		  }
	  }

      if (!drop) {
	  if (PaceChannel(vchan) && (vchan->msgs < MAX_PACEMSG))
	    add_pace_msg(vchan, client_p, source_p, command, strbuf);
	  else
      	sendto_channel_butone(client_p, source_p, vchan, command, ":%s", strbuf);
      }
    }
  }
  else
  {
    if (p_or_n != NOTICE)
      sendto_one(source_p, form_str(source_p,ERR_CANNOTSENDTOCHAN),
                 me.name, source_p->name, chname);
  }
}
Example #10
0
/*! \brief NICK 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] = nickname
 */
static int
m_nick(struct Client *source_p, int parc, char *parv[])
{
  char nick[NICKLEN + 1] = "";
  struct Client *target_p = NULL;
  struct MaskItem *conf = NULL;

  assert(MyClient(source_p));

  if (parc < 2 || EmptyString(parv[1]))
  {
    sendto_one_numeric(source_p, &me, ERR_NONICKNAMEGIVEN);
    return 0;
  }

  /* Mark end of grace period, to prevent nickflooding */
  if (!IsFloodDone(source_p))
    flood_endgrace(source_p);

  /* Terminate nick to NICKLEN */
  strlcpy(nick, parv[1], IRCD_MIN(sizeof(nick), ConfigServerInfo.max_nick_length + 1));

  /* Check the nickname is ok */
  if (!valid_nickname(nick, 1))
  {
    sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, "Erroneous Nickname");
    return 0;
  }

  if (!HasFlag(source_p, FLAGS_EXEMPTRESV) &&
      !(HasUMode(source_p, UMODE_OPER) && HasOFlag(source_p, OPER_FLAG_NICK_RESV)) &&
      (conf = find_matching_name_conf(CONF_NRESV, nick, NULL, NULL, 0)))
  {
    ++conf->count;
    sendto_one_numeric(source_p, &me, ERR_ERRONEUSNICKNAME, nick, conf->reason);
    sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
                         "Forbidding reserved nick %s from user %s",
                         nick, get_client_name(source_p, HIDE_IP));
    return 0;
  }

  if ((target_p = hash_find_client(nick)) == NULL)
    change_local_nick(source_p, nick);
  else if (target_p == source_p)
  {
    /*
     * If (target_p == source_p) the client is changing nicks between
     * equivalent nicknames ie: [nick] -> {nick}
     */

    /* Check the nick isn't exactly the same */
    if (strcmp(target_p->name, nick))
      change_local_nick(source_p, nick);
  }
  else if (IsUnknown(target_p))
  {
    /*
     * If the client that has the nick isn't registered yet (nick but no
     * user) then drop the unregged client
     */
    exit_client(target_p, "Overridden by other sign on");
    change_local_nick(source_p, nick);
  }
  else
    sendto_one_numeric(source_p, &me, ERR_NICKNAMEINUSE, target_p->name);

  return 0;
}
Example #11
0
/*
 * m_topic
 *      parv[1] = channel name
 *	parv[2] = new topic, if setting topic
 */
static int
m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr = NULL;
	struct membership *msptr;
	char *p = NULL;
	const char *name;
	int operspy = 0;

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

	name = parv[1];

	if(IsOperAuspex(source_p) && parv[1][0] == '!')
	{
		name++;
		operspy = 1;

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

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

	if(!IsChannelName(name))
	{
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
				   form_str(ERR_NOSUCHCHANNEL), name);
		return 0;
	}

	chptr = find_channel(name);

	if(chptr == NULL)
	{
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
				form_str(ERR_NOSUCHCHANNEL), name);
		return 0;
	}

	/* setting topic */
	if(parc > 2)
	{
		char topic_info[USERHOST_REPLYLEN];
		char topic[BUFSIZE];

		msptr = find_channel_membership(chptr, source_p);

		if(msptr == NULL)
		{
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					form_str(ERR_NOTONCHANNEL), name);
			return 0;
		}

		if(MyClient(source_p) && !is_chanop_voiced(msptr) &&
				!IsOper(source_p) &&
				!add_channel_target(source_p, chptr))
		{
			sendto_one(source_p, form_str(ERR_TARGCHANGE),
				   me.name, source_p->name, chptr->chname);
			return 0;
		}

		if(MyClient(source_p) && !(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
					is_chanop(msptr)) &&
				 can_send(chptr, source_p, msptr)))
		{
			if(IsOverride(source_p))
				sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
						"%s is overriding TOPIC on [%s]",
						get_oper_name(source_p), chptr->chname);
			else
			{
				sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
						get_id(&me, source_p),
						get_id(source_p, source_p), name);
				return 0;
			}
		}

		rb_strlcpy(topic, parv[2], BUFSIZE);
		strip_colour(topic);

		rb_sprintf(topic_info, "%s!%s@%s",
				source_p->name, source_p->username, source_p->host);
		set_channel_topic(chptr, topic, topic_info, rb_current_time());

		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
				":%s TOPIC %s :%s",
				use_id(source_p), chptr->chname,
				chptr->topic == NULL ? "" : chptr->topic);
		sendto_channel_local(ALL_MEMBERS,
				chptr, ":%s!%s@%s TOPIC %s :%s",
				source_p->name, source_p->username,
				source_p->host, chptr->chname,
				chptr->topic == NULL ? "" : chptr->topic);
	}
	else if(MyClient(source_p))
	{
		if(operspy)
			report_operspy(source_p, "TOPIC", chptr->chname);
		if(!IsMember(source_p, chptr) && SecretChannel(chptr) &&
				!operspy)
		{
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					form_str(ERR_NOTONCHANNEL), name);
			return 0;
		}
		if(chptr->topic == NULL)
			sendto_one(source_p, form_str(RPL_NOTOPIC),
					me.name, source_p->name, name);
		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);
		}
	}

	return 0;
}
Example #12
0
/* change_local_nick()
 *
 * inputs       - pointer to server
 *              - pointer to client
 *              - nick
 * output       -
 * side effects - changes nick of a LOCAL user
 */
static void
change_local_nick(struct Client *source_p, const char *nick)
{
  int samenick = 0;

  assert(source_p->name[0] && !EmptyString(nick));
  assert(MyClient(source_p));

  /*
   * Client just changing his/her nick. If he/she is
   * on a channel, send note of change to all clients
   * on that channel. Propagate notice to other servers.
   */
  if ((source_p->connection->nick.last_attempt +
       ConfigGeneral.max_nick_time) < CurrentTime)
    source_p->connection->nick.count = 0;

  if (ConfigGeneral.anti_nick_flood &&
      !HasUMode(source_p, UMODE_OPER) &&
      source_p->connection->nick.count >
      ConfigGeneral.max_nick_changes)
  {
    sendto_one_numeric(source_p, &me, ERR_NICKTOOFAST, nick,
                       ConfigGeneral.max_nick_time);
    return;
  }

  source_p->connection->nick.last_attempt = CurrentTime;
  source_p->connection->nick.count++;

  samenick = !irccmp(source_p->name, nick);

  if (!samenick)
  {
    source_p->tsinfo = CurrentTime;
    clear_ban_cache_client(source_p);
    watch_check_hash(source_p, RPL_LOGOFF);

    if (HasUMode(source_p, UMODE_REGISTERED))
    {
      unsigned int oldmodes = source_p->umodes;
      char modebuf[IRCD_BUFSIZE] = "";

      DelUMode(source_p, UMODE_REGISTERED);
      send_umode(source_p, source_p, oldmodes, modebuf);
    }
  }

  sendto_realops_flags(UMODE_NCHANGE, L_ALL, SEND_NOTICE,
                       "Nick change: From %s to %s [%s@%s]",
                       source_p->name, nick, source_p->username, source_p->host);
  sendto_common_channels_local(source_p, 1, 0, ":%s!%s@%s NICK :%s",
                               source_p->name, source_p->username,
                               source_p->host, nick);
  whowas_add_history(source_p, 1);

  sendto_server(source_p, 0, 0, ":%s NICK %s :%lu",
                source_p->id, nick, (unsigned long)source_p->tsinfo);

  hash_del_client(source_p);
  strlcpy(source_p->name, nick, sizeof(source_p->name));
  hash_add_client(source_p);

  if (!samenick)
    watch_check_hash(source_p, RPL_LOGON);

  /* fd_desc is long enough */
  fd_note(&source_p->connection->fd, "Nick: %s", source_p->name);
}
static  int     m_message(struct Client *cptr,
                          struct Client *sptr,
                          int parc,
                          char *parv[],
                          int notice)
{
  struct Client       *acptr;
#ifdef NEED_TLD_FOR_MASS_NOTICE
  char  *s;
#endif
  struct Channel *chptr;
  char  *nick, *server, *host;
  char  errbuf[BUFSIZE];
  const char *cmd;
  int type=0, msgs=0;
#ifdef FLUD
  int flud;
#endif

  cmd = notice ? MSG_NOTICE : MSG_PRIVATE;

  if (parc < 2 || *parv[1] == '\0')
    {
      sendto_one(sptr, form_str(ERR_NORECIPIENT),
                 me.name, parv[0], cmd);
      return -1;
    }

  if (parc < 3 || *parv[2] == '\0')
    {
      sendto_one(sptr, form_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
      return -1;
    }

  if (MyConnect(sptr))
    {
#ifdef ANTI_SPAMBOT
#ifndef ANTI_SPAMBOT_WARN_ONLY
      /* if its a spambot, just ignore it */
      if(sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT)
        return 0;
#endif
#endif
#ifdef NO_DUPE_MULTI_MESSAGES
      if (strchr(parv[1],','))
        parv[1] = canonize(parv[1]);
#endif
    }


  /*
  ** channels are privmsg'd a lot more than other clients, moved up here
  ** plain old channel msg ?
  */
  while(msgs < MAX_MULTI_MESSAGES)
  {
     if(!msgs)
        nick = strtok(parv[1], ",");
     else
        nick = strtok(NULL, ",");

     if(!nick && msgs == 0)
        nick = parv[1];
     else if(!nick)
        break;

  if( IsChanPrefix(*nick)
      && (IsPerson(sptr) && (chptr = hash_find_channel(nick, NullChn))))
    {
#ifdef FLUD
#ifdef DEATHFLUD
      if(!notice && check_for_ctcp(parv[2])
         && check_for_flud(sptr, NULL, chptr, 1))
        return 0;
      if((flud = check_for_spam(sptr, NULL, chptr, parv[2])))
        {
          if (check_for_flud(sptr, NULL, chptr, flud))
            return 0;
        }
#else /* DEATHFLUD */
      if(!notice)
	if(check_for_ctcp(parv[2]))
	  check_for_flud(sptr, NULL, chptr, 1);
#endif /* DEATHFLUD */
#endif /* FLUD */

      /* 
       * Channel color blocking. Usually set with the +c chanmode.
       * - Andre Guibert de Bruet <*****@*****.**>
       */
      if(chptr->mode.mode & MODE_NOCOLOR)
	strip_colour(parv[2]);

      switch (can_send(sptr, chptr))
        {
        case 0:
          sendto_channel_message_butone(cptr, sptr, chptr, cmd, parv[2]);
          break;
        case MODE_QUIETUNIDENT:
          if (!notice)
            sendto_one(sptr, form_str(ERR_QUIETUNIDENT),
                       me.name, parv[0], nick);
          break;
        case MODE_MODERATED:
          if (chptr->mode.mode & MODE_OPMODERATE)
            {
              /* The flag MODE_OPMODERATE will instruct sendto_channel_type()
	       * to put bare #channel in the message (instead of @#channel);
	       * it will still be sent to ops and servers with ops only.
	       * Strange things will happen if the user is not banned
	       * remotely.
	       * -- jilles
	       */
              sendto_channel_type(cptr, sptr, chptr,
			      MODE_CHANOP | MODE_OPMODERATE, nick, cmd,
			      parv[2]);
            }
          else
            {
              if (!notice)
                sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN),
                           me.name, parv[0], nick);
            }
          break;
        default:
          break;
        }
      msgs++;
      continue;
    }
      
  /*
  ** @# type of channel msg?
  */

  if(*nick == '@')
    type = MODE_CHANOP;
  else if(*nick == '+')
    type = MODE_CHANOP|MODE_VOICE;

  if(type)
    {
      /* Strip if using DALnet chanop/voice prefix. */
      if (*(nick+1) == '@' || *(nick+1) == '+')
        {
          nick++;
          *nick = '@';
          type = MODE_CHANOP|MODE_VOICE;
        }

      /* suggested by Mortiis */
      if(!*nick)        /* if its a '\0' dump it, there is no recipient */
        {
          sendto_one(sptr, form_str(ERR_NORECIPIENT),
                     me.name, parv[0], cmd);
          return -1;
        }

      if (!IsPerson(sptr))      /* This means, servers can't send messages */
        return -1;

      /* 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+1, NullChn)) )
        {
#ifdef FLUD
#ifdef DEATHFLUD
          if(!notice && check_for_ctcp(parv[2])
             && check_for_flud(sptr, NULL, chptr, 1))
            return 0;
          if((flud = check_for_spam(sptr, NULL, chptr, parv[2])))
            {
              if (check_for_flud(sptr, NULL, chptr, flud))
                return 0;
            }
#else /* DEATHFLUD */
          if(!notice)
            if(check_for_ctcp(parv[2]))
              check_for_flud(sptr, NULL, chptr, 1);
#endif /* DEATHFLUD */
#endif /* FLUD */

          if (!is_chan_op(sptr,chptr))
            {
              if (!notice)
                {
                  sendto_one(sptr, form_str(ERR_CANNOTSENDTOCHAN),
                             me.name, parv[0], nick);
                }
	msgs++;
	continue;
            }
          else
            {
              sendto_channel_type(cptr,
                                  sptr,
                                  chptr,
                                  type,
                                  nick+1,
                                  cmd,
                                  parv[2]);
            }
        }
      else
        {
	  if (!IsServer(sptr))
	    sendto_one(sptr, form_str(ERR_NOSUCHNICK),
		       me.name, parv[0], nick);
	  msgs++;
	  continue;
        }
      return 0;
    }

  /*
  ** nickname addressed?
  */
  if ((acptr = find_person(nick, NULL)))
    {
#ifdef FLUD
#ifdef DEATHFLUD
      if(!notice && MyConnect(sptr) && check_for_ctcp(parv[2])
         && check_for_flud(sptr, acptr, NULL, 1))
        return 0;
      if(MyConnect(sptr) && (flud = check_for_spam(sptr, acptr, NULL, parv[2])))
        {
          if (check_for_flud(sptr, acptr, NULL, flud))
            return 0;
        }
#else /* DEATHFLUD */
      if(!notice && MyConnect(sptr))
	if(check_for_ctcp(parv[2]))
	  if(check_for_flud(sptr, acptr, NULL, 1))
	    return 0;
#endif /* DEATHFLUD */
#endif /* FLUD */
#ifdef ANTI_DRONE_FLOOD
      if(MyConnect(acptr) && IsClient(sptr) && !NoFloodProtection(sptr) && DRONETIME)
        {
          if((acptr->first_received_message_time+DRONETIME) < CurrentTime)
            {
              acptr->received_number_of_privmsgs=1;
              acptr->first_received_message_time = CurrentTime;
              acptr->drone_noticed = 0;
            }
          else
            {
              if(acptr->received_number_of_privmsgs > DRONECOUNT)
                {
                  if(acptr->drone_noticed == 0) /* tiny FSM */
                    {
                      sendto_ops_flag(UMODE_BOTS,
				      "Possible Drone Flooder %s [%s@%s] on %s target: %s",
				      sptr->name, sptr->username,
				      sptr->host,
				      sptr->user->server, acptr->name);
                      acptr->drone_noticed = 1;
                    }
                  /* heuristic here, if target has been getting a lot
                   * of privmsgs from clients, and sendq is above halfway up
                   * its allowed sendq, then throw away the privmsg, otherwise
                   * let it through. This adds some protection, yet doesn't
                   * DOS the client.
                   * -Dianora
                   */
                  if(DBufLength(&acptr->sendQ) > (get_sendq(acptr)/2UL))
                    {
                      if(acptr->drone_noticed == 1) /* tiny FSM */
                        {
                          sendto_ops_flag(UMODE_BOTS,
					  "ANTI_DRONE_FLOOD SendQ protection activated for %s",
					  acptr->name);

                          sendto_one(acptr,     
				     ":%s NOTICE %s :*** Notice -- Server drone flood protection activated for %s",
                                     me.name, acptr->name, acptr->name);
                          acptr->drone_noticed = 2;
                        }
                    }

                  if(DBufLength(&acptr->sendQ) <= (get_sendq(acptr)/4UL))
                    {
                      if(acptr->drone_noticed == 2)
                        {
                          sendto_one(acptr,     
                                     ":%s NOTICE %s :*** Notice -- Server drone flood protection de-activated for %s",
                                     me.name, acptr->name, acptr->name);
                          acptr->drone_noticed = 1;
                        }
                    }
                  if(acptr->drone_noticed > 1)
                    return 0;
                }
              else
                acptr->received_number_of_privmsgs++;
            }
        }
#endif

      /*
       * Simple herustic here... If PRIVMSG is locked down via
       * F:noidprivmsg:1, then act like every client is +E.
       * Otherwise, assume the normal behaviour. All in a nice
       * single if statement. --nenolod
       */
      if (MyClient(sptr) && sptr != acptr &&
	   (GlobalSetOptions.noidprivmsg != 0 ||
	   HasUmode(acptr,UMODE_BLOCK_NOTID)) 
	   && !HasUmode(sptr,UMODE_IDENTIFIED)
	   && !sptr->user->servlogin[0]
	   && !HasUmode(acptr,UMODE_DONTBLOCK)
	   && !HasUmode(sptr,UMODE_DONTBLOCK))
        {
	  /* Replace errbuf with either the default or custom message,
	   * then send the numeric on...
	   *    --nenolod
	   */
	  if (GlobalSetOptions.noidprivmsg != 0 &&
		GlobalSetOptions.noidprivmsg_notice[0])
	    {
	      strncpy_irc(errbuf, GlobalSetOptions.noidprivmsg_notice, BUFSIZE);
	    }
	  else
	    {
	      ircsnprintf(errbuf, BUFSIZE, get_str(STR_NOTID_DEFAULT),
		nick);
	    }

          sendto_one(sptr, form_str(ERR_BLOCKING_NOTID),
	      me.name, parv[0], errbuf);
	  return 0;
        }

#ifdef  SILENCE
      /* only check silence masks at the recipient's server -- jilles */
      if (!MyConnect(acptr) || !is_silenced(sptr, acptr)) {
#endif
        if (MyConnect(sptr) && acptr->user && (sptr != acptr))
          {
#ifdef  NCTCP
            /* NCTCP (umode +C) checks  -- PMA */
            if (parv[2][0] == 1) /* is CTCP */
	      /* Huh? No way, NOCTCP means NOCTCP. */
/*               if (!HasUmode(sptr,UMODE_IMMUNE) && */
/*                   !HasUmode(acptr,UMODE_IMMUNE)) */
	      if (HasUmode(acptr,UMODE_NOCTCP) ||            /* block to +C */
		  (notice && HasUmode(sptr,UMODE_NOCTCP)))   /* block replies from +C */
		return 0;                                    /* kill it! */
#endif /* NCTCP */
            if (!notice && acptr->user->away)
              sendto_one(sptr, form_str(RPL_AWAY), me.name,
                         parv[0], acptr->name,
                         acptr->user->away);
          }
        {
          /* here's where we actually send the message */
          int is_ctcp = check_for_ctcp(parv[2]);
          int cap = is_ctcp ? CAP_IDENTIFY_CTCP : CAP_IDENTIFY_MSG;
          sendto_prefix_one(acptr, sptr, ":%s %s %s :%s%s",
                            parv[0], cmd, nick,
                            !(acptr->caps & cap) ? "" :
                            (HasUmode(sptr, UMODE_IDENTIFIED) ? "+" : "-"),
                            parv[2]);
        }
#ifdef SILENCE
      }
#endif

      msgs++;
      continue;
    }

  /* Everything below here should be reserved for opers 
   * as pointed out by Mortiis, user%[email protected] 
   * syntax could be used to flood without FLUD protection
   * its also a delightful way for non-opers to find users who
   * have changed nicks -Dianora
   *
   * Grrr it was pointed out to me that x@service is valid
   * for non-opers too, and wouldn't allow for flooding/stalking
   * -Dianora
   *
   * Valid or not, @servername is unacceptable, it reveals what server
   * a person is on. Auspexen only.
   *  -- asuffield
   */

        
  /*
  ** the following two cases allow masks in NOTICEs
  ** (for OPERs only) (with +M -- asuffield)
  **
  ** Armin, 8Jun90 ([email protected])
  */
  if ((*nick == '$' || *nick == '>'))
    {

      if(!HasUmode(sptr,UMODE_MASSNOTICE))
        {
          sendto_one(sptr, form_str(ERR_NOSUCHNICK),
                     me.name, parv[0], nick);
          return -1;
        }

#ifdef NEED_TLD_FOR_MASS_NOTICE
      if (!(s = (char *)strrchr(nick, '.')))
        {
          sendto_one(sptr, form_str(ERR_NOTOPLEVEL),
                     me.name, parv[0], nick);
          msgs++;
	  continue;
        }
      while (*++s)
        if (*s == '.' || *s == '*' || *s == '?')
          break;
      if (*s == '*' || *s == '?')
        {
          sendto_one(sptr, form_str(ERR_WILDTOPLEVEL),
                     me.name, parv[0], nick);
	  msgs++;
	  continue;
        }
#endif /* NEED_TLD_FOR_MASS_NOTICE */
        
      sendto_match_butone(IsServer(cptr) ? cptr : NULL, 
                          sptr, nick + 1,
                          (*nick == '>') ? MATCH_HOST :
                          MATCH_SERVER,
                          ":%s %s %s :%s", parv[0],
                          cmd, nick, parv[2]);
      msgs++;
      continue;
    }
        
  /*
  ** user[%host]@server addressed?
  */
  if ((server = (char *)strchr(nick, '@')) &&
      (acptr = find_server(server + 1)))
    {
      int count = 0;

      /* Disable the whole farping mess for non-auspexen
       *  -- asuffield
       */
      if (!HasUmode(sptr,UMODE_AUSPEX))
        {
          sendto_one(sptr, form_str(ERR_NOSUCHNICK),
                     me.name, parv[0], nick);
 	  msgs++;
	  continue;
        }

      /* Disable the user%host@server form for non-opers
       * -Dianora
       */

      /* Disabled. This isn't very useful and I don't feel like mucking around with privs for it
       *  -- asuffield */
      if((char *)strchr(nick,'%'))
        {
          sendto_one(sptr, form_str(ERR_NOSUCHNICK),
                     me.name, parv[0], nick);
 	  msgs++;
	  continue;
        }
        
      /*
      ** Not destined for a user on me :-(
      */
      if (!IsMe(acptr))
        {
          sendto_one(acptr,":%s %s %s :%s", parv[0],
                     cmd, nick, parv[2]);
          msgs++;
          continue;
        }

      *server = '\0';

      /* special case opers@server */
      /* We don't want this on OPN -- asuffield */
#if 0
      if(!irccmp(nick,"opers") && SendWallops(sptr))
        {
          sendto_realops("To opers: From %s: %s",sptr->name,parv[2]);
          msgs++;
          continue;
        }
#endif
        
      if ((host = (char *)strchr(nick, '%')))
        *host++ = '\0';

      /*
      ** Look for users which match the destination host
      ** (no host == wildcard) and if one and one only is
      ** found connected to me, deliver message!
      */
      acptr = find_userhost(nick, host, NULL, &count);
      if (server)
        *server = '@';
      if (host)
        *--host = '%';
      if (acptr)
        {
          if (count == 1)
            sendto_prefix_one(acptr, sptr,
                              ":%s %s %s :%s",
                              parv[0], cmd,
                              nick, parv[2]);
          else if (!notice)
            sendto_one(sptr,
                       form_str(ERR_TOOMANYTARGETS),
                       me.name, parv[0], nick, MAX_MULTI_MESSAGES);
        }
      if (acptr)
	{
	  msgs++;
	  continue;
	}
    }
  /* Let's not send these remotely for channels */
  if (MyConnect(sptr) || (nick[0] != '#'))
    sendto_one(sptr, form_str(ERR_NOSUCHNICK), me.name,
	       parv[0], nick);
  msgs++;
  }
  if (strtok(NULL, ","))
    sendto_one(sptr, form_str(ERR_TOOMANYTARGETS),
                     me.name, parv[0], cmd, MAX_MULTI_MESSAGES);
  return 0;
}
Example #14
0
/*
** m_kill
**	parv[0] = sender prefix
**	parv[1] = kill victim(s) - comma separated list
**	parv[2] = kill path
*/
DLLFUNC int  m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient *acptr;
	anUser *auser;
	char inpath[HOSTLEN * 2 + USERLEN + 5];
	char *oinpath = get_client_name(cptr, FALSE);
	char *user, *path, *killer, *nick, *p, *s;
	int  chasing = 0, kcount = 0;



	if (parc < 2 || *parv[1] == '\0')
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
		    me.name, parv[0], "KILL");
		return 0;
	}

	user = parv[1];
	path = parv[2];		/* Either defined or NULL (parc >= 2!!) */

	strlcpy(inpath, oinpath, sizeof inpath);

#ifndef ROXnet
	if (IsServer(cptr) && (s = (char *)index(inpath, '.')) != NULL)
		*s = '\0';	/* Truncate at first "." */
#endif

	if (!IsPrivileged(cptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}
	if (IsAnOper(cptr))
	{
		if (BadPtr(path))
		{
			sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
			    me.name, parv[0], "KILL");
			return 0;
		}
		if (strlen(path) > (size_t)TOPICLEN)
			path[TOPICLEN] = '\0';
	}

	if (MyClient(sptr))
		user = (char *)canonize(user);

	for (p = NULL, nick = strtoken(&p, user, ","); nick;
	    nick = strtoken(&p, NULL, ","))
	{

		chasing = 0;

		if (!(acptr = find_client(nick, NULL)))
		{
			/*
			   ** If the user has recently changed nick, we automaticly
			   ** rewrite the KILL for this new nickname--this keeps
			   ** servers in synch when nick change and kill collide
			 */
			if (!(acptr =
			    get_history(nick, (long)KILLCHASETIMELIMIT)))
			{
				sendto_one(sptr, err_str(ERR_NOSUCHNICK),
				    me.name, parv[0], nick);
				continue;
			}
			sendto_one(sptr,
			    ":%s %s %s :*** KILL changed from %s to %s",
			    me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], nick, acptr->name);
			chasing = 1;
		}
		if ((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr))
		    || (MyConnect(acptr) && MyClient(cptr)
		    && !OPCanLKill(cptr)))
		{
			sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
			    parv[0]);
			continue;
		}
		if (IsServer(acptr) || IsMe(acptr))
		{
			sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
			    me.name, parv[0]);
			continue;
		}
		if (!IsPerson(acptr))
		{
			/* Nick exists but user is not registered yet: IOTW "doesn't exist". -- Syzop */
			sendto_one(sptr, err_str(ERR_NOSUCHNICK),
			    me.name, parv[0], nick);
			continue;
		}

		if (IsServices(acptr) && !(IsNetAdmin(sptr) || IsULine(sptr)))
		{
			sendto_one(sptr, err_str(ERR_KILLDENY), me.name,
			    parv[0], parv[1]);
			return 0;
		}
		/* From here on, the kill is probably going to be successful. */

		kcount++;

		if (!IsServer(sptr) && (kcount > MAXKILLS))
		{
			sendto_one(sptr,
			    ":%s %s %s :*** Too many targets, kill list was truncated. Maximum is %d.",
			    me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", parv[0], MAXKILLS);
			break;
		}
		if (!IsServer(cptr))
		{
			/*
			   ** The kill originates from this server, initialize path.
			   ** (In which case the 'path' may contain user suplied
			   ** explanation ...or some nasty comment, sigh... >;-)
			   **
			   **   ...!operhost!oper
			   **   ...!operhost!oper (comment)
			 */
			strlcpy(inpath, GetHost(cptr), sizeof inpath);
			if (kcount < 2) {	/* Only check the path the first time
					   around, or it gets appended to itself. */
				if (!BadPtr(path))
				{
					(void)ircsprintf(buf, "%s%s (%s)",
					    cptr->name,
					    IsOper(sptr) ? "" : "(L)", path);
					path = buf;
				}
				else
					path = cptr->name;
			}
		}
		else if (BadPtr(path))
			path = "*no-path*";	/* Bogus server sending??? */
		/*
		   ** Notify all *local* opers about the KILL (this includes the one
		   ** originating the kill, if from this server--the special numeric
		   ** reply message is not generated anymore).
		   **
		   ** Note: "acptr->name" is used instead of "user" because we may
		   **    have changed the target because of the nickname change.
		 */

		auser = acptr->user;

		sendto_snomask_normal(SNO_KILLS,
		    "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s",
		    acptr->name, auser->username,
		    IsHidden(acptr) ? auser->virthost : auser->realhost,
		    parv[0], inpath, path);
#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
		if (IsOper(sptr))
			syslog(LOG_DEBUG, "KILL From %s For %s Path %s!%s",
			    parv[0], acptr->name, inpath, path);
#endif
		/*
		 * By otherguy
		*/
                ircd_log
                    (LOG_KILL, "KILL (%s) by  %s(%s!%s)",
                           make_nick_user_host
                     (acptr->name, acptr->user->username, GetHost(acptr)),
                            parv[0],
                            inpath,
                            path);
		/*
		   ** And pass on the message to other servers. Note, that if KILL
		   ** was changed, the message has to be sent to all links, also
		   ** back.
		   ** Suicide kills are NOT passed on --SRB
		 */
		if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
		{
			sendto_serv_butone(cptr, ":%s KILL %s :%s!%s",
			    parv[0], acptr->name, inpath, path);
			if (chasing && IsServer(cptr))
				sendto_one(cptr, ":%s KILL %s :%s!%s",
				    me.name, acptr->name, inpath, path);
			acptr->flags |= FLAGS_KILLED;
		}

		/*
		   ** Tell the victim she/he has been zapped, but *only* if
		   ** the victim is on current server--no sense in sending the
		   ** notification chasing the above kill, it won't get far
		   ** anyway (as this user don't exist there any more either)
		 */
		if (MyConnect(acptr))
			sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s",
			    parv[0], acptr->name, inpath, path);
		/*
		   ** Set FLAGS_KILLED. This prevents exit_one_client from sending
		   ** the unnecessary QUIT for this. (This flag should never be
		   ** set in any other place)
		 */
		if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))

			(void)ircsprintf(buf2, "[%s] Local kill by %s (%s)",
			    me.name, sptr->name,
			    BadPtr(parv[2]) ? sptr->name : parv[2]);
		else
		{
			if ((killer = index(path, ' ')))
			{
				while ((killer >= path) && *killer && *killer != '!')
					killer--;
				if (!*killer)
					killer = path;
				else
					killer++;
			}
			else
				killer = path;
			(void)ircsprintf(buf2, "Killed (%s)", killer);
		}

		if (MyClient(sptr))
			RunHook3(HOOKTYPE_LOCAL_KILL, sptr, acptr, parv[2]);
		if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER)
			return FLUSH_BUFFER;
	}
	return 0;
}
Example #15
0
/*
 * Note: At least at protocol level ERROR has only one parameter,
 * although this is called internally from other functions
 * --msa
 *
 *      parv[0] = sender prefix
 *      parv[*] = parameters
 */
void m_error(struct Client *client_p, struct Client *source_p,
             int parc, char *parv[])
{
  if (MyClient(source_p))
    exit_client(client_p, source_p, source_p, "ERROR");
}
Example #16
0
/*
 * msg_channel_flags
 *
 * inputs	- flag 0 if PRIVMSG 1 if NOTICE. RFC 
 *		  say NOTICE must not auto reply
 *		- pointer to command, "PRIVMSG" or "NOTICE"
 *		- pointer to client_p
 *		- pointer to source_p
 *		- pointer to channel
 *		- flags
 *		- pointer to text to send
 * output	- NONE
 * side effects	- message given channel either chanop or voice
 */
static void
msg_channel_flags(int p_or_n, char *command, struct Client *client_p,
                  struct Client *source_p, struct Channel *chptr,
                  int flags, char *text)
{
  struct Channel *vchan = NULL;
  char *chname = NULL;
  int type;
  char c;

  if (flags & MODE_VOICE)
  {
    type = ONLY_CHANOPS_HALFOPS_VOICED;
    c = '+';
  }
  else if (flags & MODE_HALFOP)
  {
    type = ONLY_CHANOPS_HALFOPS;
    c = '%';
  }
  else
  {
    type = ONLY_CHANOPS;
    c = '@';
  }

  chname = RootChan(chptr)->chname;

#ifdef VCHANS
  if (HasVchans(chptr))
    vchan = map_vchan(chptr, source_p);
#endif

  if (!vchan)
    vchan = chptr;

  if (NoColorChannel(vchan)) 
    /*strip_color(text);*/
    text = strip_color(text, 0);

  if (MyClient(source_p))
  {
    /* idletime shouldnt be reset by notice --fl */
    if ((p_or_n != NOTICE) && source_p->user)
      source_p->user->last = CurrentTime;

    sendto_channel_local_butone(source_p, type, vchan, ":%s!%s@%s %s %c%s :%s",
                                source_p->name, source_p->username,
                                source_p->host, command, c, chname, text);
  }
  else
  {
    /*
     * another good catch, lee.  we never would echo to remote clients anyway,
     * so use slightly less intensive sendto_channel_local()
     */
    sendto_channel_local(type, vchan, ":%s!%s@%s %s %c%s :%s",
                         source_p->name, source_p->username,
                         source_p->host, command, c, chname, text);
  }

  if (chptr->chname[0] == '&')
    return;

  sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_UID, vchan,
                ":%s %s %c%s :%s", source_p->name, command, c,
                vchan->chname, text);
  sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_UID, NOCAPS, vchan,
                ":%s %s %c%s :%s", ID(source_p), command, c,
                vchan->chname, text);

  /* non CAP_CHW servers? */
}
Example #17
0
/*
 * do_svssno() 
 * parv[0] - sender
 * parv[1] - username to change snomask for
 * parv[2] - snomasks to change
 * show_change determines whether to show the change to the user
 */
int  do_svssno(aClient *cptr, aClient *sptr, int parc, char *parv[], int show_change)
{
	char *p;
	aClient *acptr;
	int what = MODE_ADD, i;

	if (!IsULine(sptr))
		return 0;

	if (parc < 2)
		return 0;

	if (parv[1][0] == '#') 
		return 0;

	if (!(acptr = find_person(parv[1], NULL)))
		return 0;

	if (hunt_server_token(cptr, sptr,
	                      show_change ? MSG_SVS2SNO : MSG_SVSSNO,
	                      show_change ? TOK_SVS2SNO : TOK_SVSSNO,
	                      "%s %s", 1, parc, parv) != HUNTED_ISME)
	{
		return 0;
	}

	if (MyClient(acptr))
	{
		if (parc == 2)
			acptr->user->snomask = 0;
		else
		{
			for (p = parv[2]; p && *p; p++) {
				switch (*p) {
					case '+':
						what = MODE_ADD;
						break;
					case '-':
						what = MODE_DEL;
						break;
					default:
				 	 for (i = 0; i <= Snomask_highest; i++)
				 	 {
				 	 	if (!Snomask_Table[i].flag)
				 	 		continue;
		 	 			if (*p == Snomask_Table[i].flag)
				 	 	{
				 	 		if (what == MODE_ADD)
					 	 		acptr->user->snomask |= Snomask_Table[i].mode;
			 			 	else
			 	 				acptr->user->snomask &= ~Snomask_Table[i].mode;
				 	 	}
				 	 }				
				}
			}
		}
	}

	if (show_change)
		sendto_one(acptr, rpl_str(RPL_SNOMASK), me.name, acptr->name, get_sno_str(acptr));

	return 0;
}
Example #18
0
/*
 * msg_client
 *
 * inputs	- flag 0 if PRIVMSG 1 if NOTICE. RFC 
 *		  say NOTICE must not auto reply
 *		- pointer to command, "PRIVMSG" or "NOTICE"
 * 		- pointer to source_p source (struct Client *)
 *		- pointer to target_p target (struct Client *)
 *		- pointer to text
 * output	- NONE
 * side effects	- message given channel either chanop or voice
 */
static void
msg_client(int p_or_n, char *command,
           struct Client *source_p, struct Client *target_p, char *text)
{
  if (MyClient(source_p))
  {
    /* reset idle time for message only if its not to self 
     * and its not a notice */
    if ((p_or_n != NOTICE) && (source_p != target_p) && source_p->user)
      source_p->user->last = CurrentTime;
      
    if (IsSetSSLaccept(target_p)) {
#ifdef HAVE_LIBCRYPTO
  		int fd = source_p->localClient->fd;
  		fde_t *F = (fd > -1)? &fd_table[fd] : NULL;
  	
  		if (F && !F->ssl) {
#endif
  			sendto_one(source_p, form_str(source_p,ERR_SSLACCEPTONLY),
  				me.name, source_p->name, target_p->name);
  			return;
  			
#ifdef HAVE_LIBCRYPTO
		}
#endif
	}
  }

  if (MyConnect(source_p) && (p_or_n != NOTICE) &&
      target_p->user && target_p->user->away)
    sendto_one(source_p, form_str(source_p,RPL_AWAY), me.name,
               source_p->name, target_p->name, target_p->user->away);

  if (MyClient(target_p))
  {
    if (IsSetRegAccept(target_p) && !(source_p->svsflags & FLAGS_SVS_IDENT))
	{
	  if (p_or_n != NOTICE)
	    sendto_one(source_p, form_str(source_p,ERR_REGACCEPTONLY),
		       me.name, source_p->name, target_p->name);
	    return;
	}

	if (ConfigFileEntry.spam_wait && (p_or_n != NOTICE) &&
	((target_p->localClient->last_join_time + ConfigFileEntry.spam_wait > CurrentTime) ||
	(target_p->localClient->last_leave_time + ConfigFileEntry.spam_wait > CurrentTime)))
	{
		sendto_anywhere(source_p, target_p, 
			"NOTICE %s :*** I'm joining/leaving a chan, please try again in a few seconds.",
			source_p->name);
		return;
	}

    if (!IsServer(source_p) && IsSetCallerId(target_p))
    {
      /* Here is the anti-flood bot/spambot code -db */
      if (accept_message(source_p, target_p) || (source_p == target_p) ||
          find_z_conf((char *)source_p->user->server))
      {
        sendto_one(target_p, ":%s!%s@%s %s %s :%s",
                   source_p->name,
                   source_p->username,
                   source_p->host, 
                   command, target_p->name, translate(target_p, text));
      }
      else
      {
        /* check for accept, flag recipient incoming message */
        if (p_or_n != NOTICE)
          sendto_anywhere(source_p, target_p,
                          "NOTICE %s :*** I'm in +g mode (server side ignore).",
                          source_p->name);

        if ((target_p->localClient->last_caller_id_time +
             ConfigFileEntry.caller_id_wait) < CurrentTime)
        {
          if (p_or_n != NOTICE)
            sendto_anywhere(source_p, target_p,
                            "NOTICE %s :*** I've been informed you messaged me.",
                            source_p->name);

          sendto_one(target_p,
                     ":%s NOTICE %s :*** Client %s [%s@%s] is messaging you and you are +g",
                     me.name, target_p->name,
                     source_p->name, source_p->username, source_p->host);

          target_p->localClient->last_caller_id_time = CurrentTime;

        }
        /* Only so opers can watch for floods */
        (void)flood_attack_client(p_or_n, source_p, target_p);
      }
    }
    else
    {
      /* If the client is remote, we dont perform a special check for
       * flooding.. as we wouldnt block their message anyway.. this means
       * we dont give warnings.. we then check if theyre opered 
       * (to avoid flood warnings), lastly if theyre our client
       * and flooding    -- fl */
      if (!MyClient(source_p) || IsOper(source_p) ||
          (MyClient(source_p) &&
           !flood_attack_client(p_or_n, source_p, target_p)))
        sendto_anywhere(target_p, source_p, "%s %s :%s",
                        command, target_p->name, translate(target_p, text));
    }
  }
  else
    /* The target is a remote user.. same things apply  -- fl */
  if (!MyClient(source_p) || IsOper(source_p) ||
        (MyClient(source_p)
           && !flood_attack_client(p_or_n, source_p, target_p)))
    sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
                    text);
  return;
}
Example #19
0
/*
 * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
 * the need for complicated requests like WHOIS. It returns user/host
 * information only (no spurious AWAY labels or channels).
 */
static void
m_userhost(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
{
	struct Client *target_p;
	char buf[IRCD_BUFSIZE];
	char response[NICKLEN * 2 + USERLEN + HOSTLEN + 30];
	char *t;
	int i, n;		/* loop counter */
	int cur_len;
	int rl;

	cur_len = ircsprintf(buf, form_str(RPL_USERHOST), me.name, parv[0], "");
	t = buf + cur_len;

	for(i = 0; i < 5; i++)
	{
		if(parv[i + 1] == NULL)
			break;

		if((target_p = find_person(client_p, parv[i + 1])) != NULL)
		{
			/*
			 * Show real IP for USERHOST on yourself.
			 * This is needed for things like mIRC, which do a server-based
			 * lookup (USERHOST) to figure out what the clients' local IP
			 * is.  Useful for things like NAT, and dynamic dial-up users.
			 */
			/*
			 * If a lazyleaf relayed us this request, we don't know
			 * the clients real IP.
			 * So, if you're on a lazyleaf, and you send a userhost
			 * including your nick and the nick of someone not known to
			 * the leaf, you'll get your spoofed IP.  tough.
			 */
			if(MyClient(target_p) && (target_p == source_p))
			{
				rl = ircsprintf(response, "%s%s=%c%s@%s ",
						target_p->name,
						IsOper(target_p) ? "*" : "",
						(target_p->away) ? '-' : '+',
						target_p->username, target_p->sockhost);
			}
			else
			{
				rl = ircsprintf(response, "%s%s=%c%s@%s ",
						target_p->name,
						IsOper(target_p) ? "*" : "",
						(target_p->away) ? '-' : '+',
						target_p->username, target_p->host);
			}

			if((rl + cur_len) < (IRCD_BUFSIZE - 10))
			{
				ircsprintf(t, "%s", response);
				t += rl;
				cur_len += rl;
			}
			else
				break;
		}
		else if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
		{
			t = buf;
			for(n = 0; n < 5; n++)
			{
				if(parv[n + 1])
				{
					rl = ircsprintf(t, "%s ", parv[n + 1]);
					t += rl;
				}
				else
					break;
			}
			/* Relay upstream, and let hub reply */
			sendto_one(uplink, ":%s USERHOST %s", parv[0], buf);
			return;
		}
	}

	sendto_one(source_p, "%s", buf);
}
Example #20
0
/*
** m_pong
**      parv[0] = sender prefix
**      parv[1] = origin
**      parv[2] = destination
*/
int     m_pong(struct Client *cptr,
               struct Client *sptr,
               int parc,
               char *parv[])
{
  struct Client *acptr = NULL;
  char  *origin, *destination;

  if (parc < 2 || *parv[1] == '\0')
    {
      sendto_one(sptr, form_str(ERR_NOORIGIN), me.name, parv[0]);
      return 0;
    }

  origin = parv[1];
  destination = parv[2];

#ifdef HLC
        /* for HLC --fabulous */
        if ((IsServer(cptr)) && (parv[2]) && (IsDigit(*parv[2]))) {
          sentping = 0;
          receivedat = atoi(parv[2]);
        }
#endif

  /* Now attempt to route the PONG, comstud pointed out routable PING
   * is used for SPING.  routable PING should also probably be left in
   *        -Dianora
   * That being the case, we will route, but only for registered clients (a
   * case can be made to allow them only from servers). -Shadowfax
   */
  if (!EmptyString(destination) && irccmp(destination, me.name) != 0
                && IsRegistered(sptr))
    {
      if ((acptr = find_client(destination, NULL)) ||
          (acptr = find_server(destination)))
        sendto_one(acptr,":%s PONG %s %s",
                   parv[0], origin, destination);
      else
        {
          sendto_one(sptr, form_str(ERR_NOSUCHSERVER),
                     me.name, parv[0], destination);
          return 0;
        }
    }
  else
    {
      if (MyConnect(sptr))
      {
        sptr->flags &= ~FLAGS_PINGSENT;
#ifdef NEED_SPLITCODE
#ifdef SPLIT_PONG
        if (IsServer(sptr))
          got_server_pong = 1;
#endif
#endif
        if(MyClient(sptr) && cptr->user)
          check_idle_actions(cptr);                
      }
    }
  return 0;
}
Example #21
0
static int
me_svslogin(struct Client *client_p, struct Client *source_p,
            int parc, const char *parv[])
{
    struct Client *target_p, *exist_p;
    char nick[NICKLEN+1], login[NICKLEN+1];
    char user[USERLEN+1], host[HOSTLEN+1];
    int valid = 0;

    if(!(source_p->flags & FLAGS_SERVICE))
        return 0;

    if((target_p = find_client(parv[1])) == NULL)
        return 0;

    if(!MyClient(target_p) && !IsUnknown(target_p))
        return 0;

    if(clean_nick(parv[2])) {
        rb_strlcpy(nick, parv[2], NICKLEN + 1);
        valid |= NICK_VALID;
    } else if(*target_p->name)
        rb_strlcpy(nick, target_p->name, NICKLEN + 1);
    else
        strcpy(nick, "*");

    if(clean_username(parv[3])) {
        rb_strlcpy(user, parv[3], USERLEN + 1);
        valid |= USER_VALID;
    } else
        rb_strlcpy(user, target_p->username, USERLEN + 1);

    if(clean_host(parv[4])) {
        rb_strlcpy(host, parv[4], HOSTLEN + 1);
        valid |= HOST_VALID;
    } else
        rb_strlcpy(host, target_p->host, HOSTLEN + 1);

    if(*parv[5] == '*') {
        if(target_p->user)
            rb_strlcpy(login, target_p->user->suser, NICKLEN + 1);
        else
            login[0] = '\0';
    } else if(!strcmp(parv[5], "0"))
        login[0] = '\0';
    else
        rb_strlcpy(login, parv[5], NICKLEN + 1);

    /* Login (mostly) follows nick rules. */
    if(*login && !clean_nick(login))
        return 0;

    if((exist_p = find_person(nick)) && target_p != exist_p) {
        char buf[BUFSIZE];

        if(MyClient(exist_p))
            sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)",
                       me.name, exist_p->name);

        exist_p->flags |= FLAGS_KILLED;
        kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)",
                                me.name);

        rb_snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
                    me.name);
        exit_client(NULL, exist_p, &me, buf);
    } else if((exist_p = find_client(nick)) && IsUnknown(exist_p) && exist_p != target_p) {
        exit_client(NULL, exist_p, &me, "Overridden");
    }

    if(*login) {
        /* Strip leading digits, unless it's purely numeric. */
        const char *p = login;
        while(IsDigit(*p))
            p++;
        if(!*p)
            p = login;

        sendto_one(target_p, form_str(RPL_LOGGEDIN), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
                   nick, user, host, p, p);
    } else
        sendto_one(target_p, form_str(RPL_LOGGEDOUT), me.name, EmptyString(target_p->name) ? "*" : target_p->name,
                   nick, user, host);

    if(IsUnknown(target_p)) {
        struct User *user_p = make_user(target_p);

        if(valid & NICK_VALID)
            strcpy(target_p->preClient->spoofnick, nick);

        if(valid & USER_VALID)
            strcpy(target_p->preClient->spoofuser, user);

        if(valid & HOST_VALID)
            strcpy(target_p->preClient->spoofhost, host);

        rb_strlcpy(user_p->suser, login, NICKLEN + 1);
    } else {
        char note[NICKLEN + 10];

        send_signon(NULL, target_p, nick, user, host, rb_current_time(), login);

        rb_snprintf(note, NICKLEN + 10, "Nick: %s", target_p->name);
        rb_note(target_p->localClient->F, note);
    }

    return 0;
}
Example #22
0
/*
 * parse a buffer.
 *
 * NOTE: parse() should not be called recusively by any other functions!
 */
int parse(aClient *cptr, char *pbuffer, char *bufend)
{
  aClient *from = cptr;
  char  *ch;
  char  *s;
  size_t i;
  char* numeric = 0;
  unsigned int paramcount;
  struct Message *mptr;

  Debug((DEBUG_DEBUG, "Parsing %s: %s",
         get_client_name(cptr, TRUE), pbuffer));

  if (IsDead(cptr))
    return -1;

  s = sender;
  *s = '\0';

  for (ch = pbuffer; *ch == ' '; ch++)   /* skip spaces */
    /* null statement */ ;

  para[0] = from->name;
  if (*ch == ':')
    {
      ch++;

      /*
      ** Copy the prefix to 'sender' assuming it terminates
      ** with SPACE (or NULL, which is an error, though).
      */
      for (i = 0; *ch && *ch != ' '; i++ )
	{
	  if (i < (sizeof(sender)-1))
	    *s++ = *ch; /* leave room for NULL */
	  ch++;
	}
      *s = '\0';
      i = 0;

      /*
      ** Actually, only messages coming from servers can have
      ** the prefix--prefix silently ignored, if coming from
      ** a user client...
      **
      ** ...sigh, the current release "v2.2PL1" generates also
      ** null prefixes, at least to NOTIFY messages (e.g. it
      ** puts "sptr->nickname" as prefix from server structures
      ** where it's null--the following will handle this case
      ** as "no prefix" at all --msa  (": NOTICE nick ...")
      */
      if (*sender && IsServer(cptr))
        {
          from = find_client(sender, (aClient *) NULL);
          if (!from || !match(from->name, sender))
            from = find_server(sender);

          para[0] = sender;
          
          /* Hmm! If the client corresponding to the
           * prefix is not found--what is the correct
           * action??? Now, I will ignore the message
           * (old IRC just let it through as if the
           * prefix just wasn't there...) --msa
           */
          if (!from)
            {
	      sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Unknown prefix (%s) from (%s)",
				     sender, cptr->name);
              Debug((DEBUG_ERROR, "Unknown prefix (%s)(%s) from (%s)",
                     sender, pbuffer, cptr->name));
              ServerStats->is_unpf++;

              remove_unknown(cptr, sender, pbuffer);

              return -1;
            }
          if (from->from != cptr)
            {
              ServerStats->is_wrdi++;
              Debug((DEBUG_ERROR, "Message (%s) coming from (%s)",
                     buffer, cptr->name));
	      sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Message coming from (%s), but %s is at %s",
				     cptr->name, from->name, from->from->name);

              return cancel_clients(cptr, from, pbuffer);
            }
        }
      while (*ch == ' ')
        ch++;
    }

  if (*ch == '\0')
    {
      ServerStats->is_empt++;
      Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
             cptr->name, from->name));
      if (IsServer(cptr))
	sendto_ops_flag_butone(cptr, UMODE_DEBUG, "Empty message from %s:%s",
			       cptr->name, from->name);
      return(-1);
    }

  /*
  ** Extract the command code from the packet.  Point s to the end
  ** of the command code and calculate the length using pointer
  ** arithmetic.  Note: only need length for numerics and *all*
  ** numerics must have parameters and thus a space after the command
  ** code. -avalon
  *
  * ummm???? - Dianora
  */

  if( *(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */
      IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)) )
    {
      mptr = (struct Message *)NULL;
      numeric = ch;
      paramcount = MAXPARA;
      ServerStats->is_num++;
      s = ch + 3;       /* I know this is ' ' from above if */
      *s++ = '\0';      /* blow away the ' ', and point s to next part */
    }
  else
    {
      s = strchr(ch, ' ');      /* moved from above,now need it here */
      if (s)
        *s++ = '\0';

      mptr = tree_parse(ch);

      if (!mptr || !mptr->cmd)
        {
          /*
           * Note: Give error message *only* to recognized
           * persons. It's a nightmare situation to have
           * two programs sending "Unknown command"'s or
           * equivalent to each other at full blast....
           * If it has got to person state, it at least
           * seems to be well behaving. Perhaps this message
           * should never be generated, though...  --msa
           * Hm, when is the buffer empty -- if a command
           * code has been found ?? -Armin
	   *
	   * Same thing goes for remote commands. If their local
	   * server accepted it, then we should not be sending
	   * a warning message.
	   */
          if (pbuffer[0] != '\0')
            {
              if (IsPerson(from) && MyClient(from))
                sendto_one(from,
                           ":%s %d %s %s :Unknown command",
                           me.name, ERR_UNKNOWNCOMMAND,
                           from->name, ch);
              Debug((DEBUG_ERROR,"Unknown (%s) from %s",
                     ch, get_client_name(cptr, TRUE)));
            }
          ServerStats->is_unco++;
          return(-1);
        }

      paramcount = mptr->parameters;
      i = bufend - ((s) ? s : ch);
      mptr->bytes += i;

      /* Allow only 1 msg per 2 seconds
       * (on average) to prevent dumping.
       * to keep the response rate up,
       * bursts of up to 5 msgs are allowed
       * -SRB
       * Opers can send 1 msg per second, burst of ~20
       * -Taner
       */
      if ((mptr->flags & 1) && !(IsServer(cptr)))
        {
#ifdef NO_OPER_FLOOD
#ifndef TRUE_NO_OPER_FLOOD
	  /* note: both have to be defined for the real no-flood */
          if (NoFloodProtection(cptr))
            /* "randomly" (weighted) increase the since */
            cptr->since += (cptr->receiveM % 5) ? 1 : 0;
          else
#else
          if (!NoFloodProtection(cptr))
#endif
#endif
            cptr->since += (2 + i / 120);
        }
    }
  /*
  ** Must the following loop really be so devious? On
  ** surface it splits the message to parameters from
  ** blank spaces. But, if paramcount has been reached,
  ** the rest of the message goes into this last parameter
  ** (about same effect as ":" has...) --msa
  */

  /* Note initially true: s==NULL || *(s-1) == '\0' !! */

  /* ZZZ hmmmmmmmm whats this then? */
#if 0
  if (me.user)
    para[0] = sender;
#endif

  i = 1;

  if (s)
    {
      if (paramcount > MAXPARA)
        paramcount = MAXPARA;

      for (;;)
        {
	  while(*s == ' ')	/* tabs are not considered space */
	    *s++ = '\0';

          if(!*s)
            break;

          if (*s == ':')
            {
              /*
              ** The rest is single parameter--can
              ** include blanks also.
              */
              para[i++] = s + 1;
              break;
            }
	  else
	    {
	      para[i++] = s;
              if (i > paramcount)
                {
                  break;
                }
              /* scan for end of string, either ' ' or '\0' */
              while (IsNonEOS(*s))
                s++;
	    }
        }
    }

  para[i] = NULL;
  if (mptr == (struct Message *)NULL)
    return (do_numeric(numeric, cptr, from, i, para));

  mptr->count++;

  /* patch to avoid server flooding from unregistered connects */
  /* check allow_unregistered_use flag I've set up instead of function
     comparing *yech* - Dianora */

  if (!IsRegistered(cptr) && !mptr->allow_unregistered_use )
    {
      /* if its from a possible server connection
       * ignore it.. more than likely its a header thats sneaked through
       */

      if(IsHandshake(cptr) || IsConnecting(cptr) || IsServer(cptr))
        return -1;

      sendto_one(from,
                 ":%s %d %s %s :Register first.",
                 me.name, ERR_NOTREGISTERED,
                 BadPtr(from->name) ? "*" : from->name, ch);
      return -1;
    }

  /* Silently drop the messages that can't be used in the honeypot */
  if (IsHoneypot(cptr) && !mptr->allow_honeypot)
    return -1;

  /* Again, instead of function address comparing, see if
   * this function resets idle time as given from mptr
   * if IDLE_FROM_MSG is undefined, the sense of the flag is reversed.
   * i.e. if the flag is 0, then reset idle time, otherwise don't reset it.
   *
   * - Dianora
   */

  if (IsRegisteredUser(from) && mptr->reset_idle)
    {
      /* If a local registered user, propagate anti-idle updates as needed */
      if (MyClient(from) && from->user && ((from->user->last_sent + MAX_IDLE_DESYNC) < CurrentTime))
	{
#if 0
	  /* Note the misnamed message, this indicates that they are NOT idle */
#ifdef HAVE_LONG_LONG
	  sendto_serv_butone(NULL, ":%s IDLE %s %.1lld", cptr->name, from->name, (long long)CurrentTime);
#else
	  sendto_serv_butone(NULL, ":%s IDLE %s %.1ld", cptr->name, from->name, (long)CurrentTime);
#endif
#endif
	  from->user->last_sent = CurrentTime;
	}
      from->user->last = CurrentTime;
    }

  /* don't allow other commands while a list is blocked. since we treat
     them specially with respect to sendq. */
  if ((IsDoingList(cptr)) && (*mptr->func != m_list))
      return -1;
  return (*mptr->func)(cptr, from, i, para);
}
Example #23
0
/*
 * m_topic
 *      parv[1] = channel name
 *	parv[2] = new topic, if setting topic
 */
static int
m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr = NULL;
	struct membership *msptr;
	char *p = NULL;
	const char *name;
	int operspy = 0;

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

	name = parv[1];

	if(IsOperSpy(source_p) && parv[1][0] == '!')
	{
		name++;
		operspy = 1;

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

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

	chptr = find_channel(name);

	if(chptr == NULL)
	{
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
				form_str(ERR_NOSUCHCHANNEL), name);
		return 0;
	}

	/* setting topic */
	if(parc > 2)
	{
		msptr = find_channel_membership(chptr, source_p);

		if(msptr == NULL)
		{
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					form_str(ERR_NOTONCHANNEL), name);
			return 0;
		}

		if(MyClient(source_p) && !is_chanop_voiced(msptr) &&
				!IsOper(source_p) &&
				!add_channel_target(source_p, chptr))
		{
			sendto_one(source_p, form_str(ERR_TARGCHANGE),
				   me.name, source_p->name, chptr->chname);
			return 0;
		}

		if(((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
					get_channel_access(source_p, chptr, msptr, MODE_ADD, NULL) >= CHFL_CHANOP) &&
				(!MyClient(source_p) ||
				 can_send(chptr, source_p, msptr)))
		{
			char topic[TOPICLEN + 1];
			char topic_info[USERHOST_REPLYLEN];
			rb_strlcpy(topic, parv[2], sizeof(topic));
			rb_sprintf(topic_info, "%s!%s@%s",
					source_p->name, source_p->username, source_p->host);

			if (ConfigChannel.strip_topic_colors)
				strip_colour(topic);

			set_channel_topic(chptr, topic, topic_info, rb_current_time());

			sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
					":%s TOPIC %s :%s",
					use_id(source_p), chptr->chname,
					chptr->topic == NULL ? "" : chptr->topic);
			sendto_channel_local(ALL_MEMBERS,
					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),
					get_id(&me, source_p),
					get_id(source_p, source_p), name);
	}
	else if(MyClient(source_p))
	{
		if(operspy)
			report_operspy(source_p, "TOPIC", chptr->chname);
		if(!IsMember(source_p, chptr) && SecretChannel(chptr) &&
				!operspy)
		{
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					form_str(ERR_NOTONCHANNEL), name);
			return 0;
		}
		if(chptr->topic == NULL)
			sendto_one(source_p, form_str(RPL_NOTOPIC),
					me.name, source_p->name, name);
		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,
					(unsigned long)chptr->topic_time);
		}
	}

	return 0;
}
Example #24
0
/*
 * * DoNumeric (replacement for the old do_numeric) *
 * 
 * parc         number of arguments ('sender' counted as one!)
 * parv[0]      pointer to 'sender' (may point to empty string)
 * parv[1]..parv[parc-1] 
 *              pointers to additional parameters, this is a NULL 
 *              terminated list (parv[parc] == NULL).
 * 
 * *WARNING* 
 * Numerics are mostly error reports. If there is something 
 * wrong with the message, just *DROP* it! Don't even think of 
 * sending back a neat error message -- big danger of creating 
 * a ping pong error message...
 */
int do_numeric(int numeric, aClient *cptr, aClient *sptr, int parc, 
	       char *parv[])
{
    aClient    *acptr;
    aChannel   *chptr;
    char       *nick, *p;
    int         i;

    if (parc < 1 || !IsServer(sptr))
	return 0;
    /* Remap low number numerics. */
    if (numeric < 100)
	numeric += 100;
    /*
     * Prepare the parameter portion of the message into 'buffer'. 
     * (Because the buffer is twice as large as the message buffer for
     * the socket, no overflow can occur here... ...on current
     * assumptions--bets are off, if these are changed --msa) 
     * Note: if buffer is non-empty, it will begin with SPACE.
     */
    buffer[0] = '\0';
    if (parc > 1)
    {
	int bpos = 0;
	char *p;

	for (i = 2; i < (parc - 1); i++)
	{
	    buffer[bpos++] = ' ';
	    for(p = parv[i]; *p; p++)
		buffer[bpos++] = *p;
	}
	buffer[bpos++] = ' ';
	buffer[bpos++] = ':';
	for(p = parv[parc - 1]; *p; p++)
	    buffer[bpos++] = *p;
	buffer[bpos] = '\0';
    }
    for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL)
    {
	if ((acptr = find_client(nick, (aClient *) NULL)))
	{
	    int dohide;

	    /*
	     * Drop to bit bucket if for me... ...one might consider
	     * sendto_ops * here... --msa * And so it was done. -avalon *
	     * And regretted. Dont do it that way. Make sure * it goes
	     * only to non-servers. -avalon * Check added to make sure
	     * servers don't try to loop * with numerics which can happen
	     * with nick collisions. * - Avalon
	     */

#ifdef HIDE_NUMERIC_SOURCE
	    dohide = MyClient(acptr) ? 1 : 0;
#else
	    dohide = 0;
#endif

	    if (!IsMe(acptr) && IsPerson(acptr))
		sendto_prefix_one(acptr, dohide ? &me : sptr, ":%s %d %s%s",
				  dohide ? me.name : parv[0], numeric, nick, buffer);
	    else if (IsServer(acptr) && acptr->from != cptr)
		sendto_prefix_one(acptr, sptr, ":%s %d %s%s",
				  parv[0], numeric, nick, buffer);
	}
	else if ((chptr = find_channel(nick, (aChannel *) NULL)))
	{
	    int dohide;

#ifdef HIDE_NUMERIC_SOURCE
	    dohide = 1;
#else
	    dohide = 0;
#endif
	    sendto_channel_butserv(chptr, dohide ? &me : sptr, ":%s %d %s%s",
				   dohide ? me.name : parv[0], numeric, 
				   chptr->chname, buffer);

	    sendto_channel_remote_butone(cptr, sptr, chptr, 
					 parv[0], numeric, 
					 chptr->chname, buffer);

	}
    }
    return 0;
}
Example #25
0
static void 
serv_info(aClient *cptr, char *name)
{
    static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s";
    long        sendK, receiveK, uptime;
    aClient    *acptr;
    DLink      *lp;
    int         i = 0;

    sendK = receiveK = 0;

    for (lp = server_list; lp; lp = lp->next)
    {
        acptr = lp->value.cptr;

#ifdef HIDEULINEDSERVS
        if (IsULine(acptr) && !IsAnOper(cptr))
            continue;
#endif
        sendK += acptr->sendK;
        receiveK += acptr->receiveK;
        sendto_one(cptr, Lformat, me.name, RPL_STATSLINKINFO,
                    name, ( (MyClient(cptr) && IsAdmin(cptr))
                            ? get_client_name(acptr, FALSE)
                            : get_client_name(acptr, HIDEME) ),
                    (int) SBufLength(&acptr->sendQ),
                    (int) acptr->sendM, (int) acptr->sendK,
                    (int) acptr->receiveM, (int) acptr->receiveK,
                    timeofday - acptr->firsttime, timeofday - acptr->since,
                    IsServer(acptr) ? (DoesTS(acptr) ? "TS" : "NoTS") : "-");


        if(RC4EncLink(acptr))
            sendto_one(cptr, ":%s %d %s : - RC4 encrypted", me.name, 
                        RPL_STATSDEBUG, name);

        if(ZipOut(acptr))
        {
            unsigned long ib, ob;
            double rat;

            zip_out_get_stats(acptr->serv->zip_out, &ib, &ob, &rat);
            if(ib)
            {
                sendto_one(cptr, ":%s %d %s : - [O] Zip inbytes %lu, "
                            "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG,
                             name, ib, ob, rat);
            }
        }

        if(ZipIn(acptr))
        {
            unsigned long ib, ob;
            double rat;

            zip_in_get_stats(acptr->serv->zip_in, &ib, &ob, &rat);
            if(ob)
            {
                sendto_one(cptr, ":%s %d %s : - [I] Zip inbytes %lu, "
                            "outbytes %lu (%3.2f%%)", me.name, RPL_STATSDEBUG,
                             name, ib, ob, rat);
            }
        }
        i++;
    }
    sendto_one(cptr, ":%s %d %s :%u total server%s",
           me.name, RPL_STATSDEBUG, name, i, (i == 1) ? "" : "s");
    sendto_one(cptr, ":%s %d %s :Sent total : %7.2f %s",
           me.name, RPL_STATSDEBUG, name, _GMKv(sendK), _GMKs(sendK));
    sendto_one(cptr, ":%s %d %s :Recv total : %7.2f %s",
           me.name, RPL_STATSDEBUG, name, _GMKv(receiveK),
           _GMKs(receiveK));

    uptime = (timeofday - me.since);
    sendto_one(cptr, ":%s %d %s :Server send: %7.2f %s (%4.1f K/s total,"
                     " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name,
                     _GMKv(me.sendK), _GMKs(me.sendK), 
                    (float) ((float) me.sendK / (float) uptime), curSendK);
    sendto_one(cptr, ":%s %d %s :Server recv: %7.2f %s (%4.1f K/s total,"
                     " %4.1f K/s current)", me.name, RPL_STATSDEBUG, name, 
                    _GMKv(me.receiveK), _GMKs(me.receiveK),
                    (float) ((float) me.receiveK / (float) uptime), curRecvK);
}
Example #26
0
static int
m_cmessage(int p_or_n, const char *command,
		struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Client *target_p;
	struct Channel *chptr;
	struct membership *msptr;

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

	if((target_p = find_named_person(parv[1])) == NULL)
	{
		if(p_or_n != NOTICE)
			sendto_one_numeric(source_p, ERR_NOSUCHNICK,
					form_str(ERR_NOSUCHNICK), parv[1]);
		return 0;
	}

	if((chptr = find_channel(parv[2])) == NULL)
	{
		if(p_or_n != NOTICE)
			sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
					form_str(ERR_NOSUCHCHANNEL), parv[2]);
		return 0;
	}

	if((msptr = find_channel_membership(chptr, source_p)) == NULL)
	{
		if(p_or_n != NOTICE)
			sendto_one_numeric(source_p, ERR_NOTONCHANNEL,
					form_str(ERR_NOTONCHANNEL),
					chptr->chname);
		return 0;
	}

	if(!is_chanop_voiced(msptr))
	{
		if(p_or_n != NOTICE)
			sendto_one(source_p, form_str(ERR_VOICENEEDED),
				me.name, source_p->name, chptr->chname);
		return 0;
	}

	if(!IsMember(target_p, chptr))
	{
		if(p_or_n != NOTICE)
			sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
					form_str(ERR_USERNOTINCHANNEL),
					target_p->name, chptr->chname);
		return 0;
	}

	if(MyClient(target_p) && (IsSetCallerId(target_p) || (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])) &&
	   !accept_message(source_p, target_p) && !IsOper(source_p))
	{
		if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])
		{
			if (p_or_n != NOTICE)
				sendto_one_numeric(source_p, ERR_NONONREG,
						form_str(ERR_NONONREG),
						target_p->name);
			return 0;
		}
		if(p_or_n != NOTICE)
			sendto_one_numeric(source_p, ERR_TARGUMODEG,
					form_str(ERR_TARGUMODEG), target_p->name);

		if((target_p->localClient->last_caller_id_time +
		    ConfigFileEntry.caller_id_wait) < rb_current_time())
		{
			if(p_or_n != NOTICE)
				sendto_one_numeric(source_p, RPL_TARGNOTIFY,
						form_str(RPL_TARGNOTIFY),
						target_p->name);

			sendto_one(target_p, form_str(RPL_UMODEGMSG),
				me.name, target_p->name, source_p->name,
				source_p->username, source_p->host);

			target_p->localClient->last_caller_id_time = rb_current_time();
		}

		return 0;
	}

	if(p_or_n != NOTICE)
		source_p->localClient->last = rb_current_time();

	sendto_anywhere(target_p, source_p, command, ":%s", parv[3]);
	return 0;
}
Example #27
0
int m_alias(aClient *cptr, aClient *sptr, int parc, char *parv[], char *cmd)
{
ConfigItem_alias *alias;
aClient *acptr;
int ret;

	if (!(alias = Find_alias(cmd))) 
	{
		sendto_one(sptr, ":%s %d %s %s :Unknown command",
			me.name, ERR_UNKNOWNCOMMAND, parv[0], cmd);
		return 0;
	}
	
	/* If it isn't an ALIAS_COMMAND, we require a paramter ... We check ALIAS_COMMAND LATER */
	if (alias->type != ALIAS_COMMAND && (parc < 2 || *parv[1] == '\0'))
	{
		sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
		return -1;
	}

	if (alias->type == ALIAS_SERVICES) 
	{
		if (SERVICES_NAME && (acptr = find_person(alias->nick, NULL)))
		{
			if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) < 0)
				return ret;
			sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0],
				alias->nick, SERVICES_NAME, parv[1]);
		}
		else
			sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
				parv[0], alias->nick);
	}
	else if (alias->type == ALIAS_STATS) 
	{
		if (STATS_SERVER && (acptr = find_person(alias->nick, NULL)))
		{
			if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) < 0)
				return ret;
			sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0],
				alias->nick, STATS_SERVER, parv[1]);
		}
		else
			sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
				parv[0], alias->nick);
	}
	else if (alias->type == ALIAS_NORMAL) 
	{
		if ((acptr = find_person(alias->nick, NULL))) 
		{
			if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_USERMSG, alias->nick, 0, NULL)) < 0)
				return ret;
			if (MyClient(acptr))
				sendto_one(acptr, ":%s!%s@%s PRIVMSG %s :%s", parv[0], 
					sptr->user->username, GetHost(sptr),
					alias->nick, parv[1]);
			else
				sendto_one(acptr, ":%s PRIVMSG %s :%s", parv[0],
					alias->nick, parv[1]);
		}
		else
			sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
				parv[0], alias->nick);
	}
	else if (alias->type == ALIAS_CHANNEL)
	{
		aChannel *chptr;
		if ((chptr = find_channel(alias->nick, NULL)))
		{
			if (!can_send(sptr, chptr, parv[1], 0))
			{
				if (alias->spamfilter && (ret = dospamfilter(sptr, parv[1], SPAMF_CHANMSG, chptr->chname, 0, NULL)) < 0)
					return ret;
				sendto_channelprefix_butone(sptr,
				    sptr, chptr, PREFIX_ALL,
                                    ":%s PRIVMSG %s :%s", parv[0],
				    chptr->chname, parv[1]);
				return 0;
			}
		}
		sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND), me.name, parv[0],
				cmd, "You may not use this command at this time");
	}
	else if (alias->type == ALIAS_COMMAND) 
	{
		ConfigItem_alias_format *format;
		char *ptr = "";
		if (!(parc < 2 || *parv[1] == '\0'))
			ptr = parv[1]; 
		for (format = alias->format; format; format = (ConfigItem_alias_format *)format->next) 
		{
			if (regexec(&format->expr, ptr, 0, NULL, 0) == 0) 
			{
				/* Parse the parameters */
				int i = 0, j = 0, k = 1;
				char output[1024], current[1024];
				char nums[4];

				bzero(current, sizeof current);
				bzero(output, sizeof output);

				while(format->parameters[i] && j < 500) 
				{
					k = 0;
					if (format->parameters[i] == '%') 
					{
						i++;
						if (format->parameters[i] == '%') 
							output[j++] = '%';
						else if (isdigit(format->parameters[i])) 
						{
							for(; isdigit(format->parameters[i]) && k < 2; i++, k++) {
								nums[k] = format->parameters[i];
							}
							nums[k] = 0;
							i--;
							if (format->parameters[i+1] == '-') {
								strrangetok(ptr, current, ' ', atoi(nums),0);
								i++;
							}
							else 
								strrangetok(ptr, current, ' ', atoi(nums), atoi(nums));
							if (!*current)
								continue;
							if (j + strlen(current)+1 >= 500)
								break;
							strlcat(output, current, sizeof output);
							j += strlen(current);
							
						}
						else if (format->parameters[i] == 'n' ||
							 format->parameters[i] == 'N')
						{
							strlcat(output, parv[0], sizeof output);
							j += strlen(parv[0]);
						}
						else 
						{
							output[j++] = '%';
							output[j++] = format->parameters[i];
						}
						i++;
						continue;
					}
					output[j++] = format->parameters[i++];
				}
				output[j] = 0;
				/* Now check to make sure we have something to send */
				if (strlen(output) == 0)
				{
					sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, cmd);
					return -1;
				}
				
				if (format->type == ALIAS_SERVICES) 
				{
					if (SERVICES_NAME && (acptr = find_person(format->nick, NULL)))
					{
						if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_USERMSG, format->nick, 0, NULL)) < 0)
							return ret;
						sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0],
							format->nick, SERVICES_NAME, output);
					} else
						sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
							parv[0], format->nick);
				}
				else if (format->type == ALIAS_STATS) 
				{
					if (STATS_SERVER && (acptr = find_person(format->nick, NULL)))
					{
						if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_USERMSG, format->nick, 0, NULL)) < 0)
							return ret;
						sendto_one(acptr, ":%s PRIVMSG %s@%s :%s", parv[0],
							format->nick, STATS_SERVER, output);
					} else
						sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
							parv[0], format->nick);
				}
				else if (format->type == ALIAS_NORMAL) 
				{
					if ((acptr = find_person(format->nick, NULL))) 
					{
						if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_USERMSG, format->nick, 0, NULL)) < 0)
							return ret;
						if (MyClient(acptr))
							sendto_one(acptr, ":%s!%s@%s PRIVMSG %s :%s", parv[0], 
							sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost,
							format->nick, output);
						else
							sendto_one(acptr, ":%s PRIVMSG %s :%s", parv[0],
								format->nick, output);
					}
					else
						sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
							parv[0], format->nick);
				}
				else if (format->type == ALIAS_CHANNEL)
				{
					aChannel *chptr;
					if ((chptr = find_channel(format->nick, NULL)))
					{
						if (!can_send(sptr, chptr, output, 0))
						{
							if (alias->spamfilter && (ret = dospamfilter(sptr, output, SPAMF_CHANMSG, chptr->chname, 0, NULL)) < 0)
								return ret;
							sendto_channelprefix_butone(sptr,
							    sptr, chptr, PREFIX_ALL,
			                                    ":%s PRIVMSG %s :%s", parv[0],
							    chptr->chname, parv[1]);
							return 0;
						}
					}
					sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND), me.name,
						 parv[0], cmd, 
						"You may not use this command at this time");
				}
				else if (format->type == ALIAS_REAL)
				{
					int ret;
					char mybuf[500];
					
					snprintf(mybuf, sizeof(mybuf), "%s %s", format->nick, output);

					if (recursive_alias)
					{
						sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND), me.name, parv[0], cmd, "You may not use this command at this time -- recursion");
						return -1;
					}

					recursive_alias = 1;
					ret = parse(sptr, mybuf, mybuf+strlen(mybuf));
					recursive_alias = 0;

					return ret;
				}
				break;
			}
		}
		return 0;
	}
	return 0;
}
Example #28
0
/* m_knock
 *    parv[0] = sender prefix
 *    parv[1] = channel
 *
 *  The KNOCK command has the following syntax:
 *   :<sender> KNOCK <channel>
 *
 *  If a user is not banned from the channel they can use the KNOCK
 *  command to have the server NOTICE the channel operators notifying
 *  they would like to join.  Helpful if the channel is invite-only, the
 *  key is forgotten, or the channel is full (INVITE can bypass each one
 *  of these conditions.  Concept by Dianora <*****@*****.**> and written by
 *  <anonymous>
 */
static int
m_knock(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
    struct Channel *chptr;
    char *p, *name;

    if(MyClient(source_p) && ConfigChannel.use_knock == 0)
    {
        sendto_one(source_p, form_str(ERR_KNOCKDISABLED),
                   me.name, source_p->name);
        return 0;
    }

    name = LOCAL_COPY(parv[1]);

    /* dont allow one knock to multiple chans */
    if((p = strchr(name, ',')))
        *p = '\0';

    if(!IsChannelName(name))
    {
        sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
                           form_str(ERR_NOSUCHCHANNEL), name);
        return 0;
    }

    if((chptr = find_channel(name)) == NULL)
    {
        sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
                           form_str(ERR_NOSUCHCHANNEL), name);
        return 0;
    }

    if(IsMember(source_p, chptr))
    {
        if(MyClient(source_p))
            sendto_one(source_p, form_str(ERR_KNOCKONCHAN),
                       me.name, source_p->name, name);
        return 0;
    }

    if(!((chptr->mode.mode & MODE_INVITEONLY) || (*chptr->mode.key) ||
            (chptr->mode.limit &&
             dlink_list_length(&chptr->members) >= (unsigned long)chptr->mode.limit)))
    {
        sendto_one_numeric(source_p, ERR_CHANOPEN,
                           form_str(ERR_CHANOPEN), name);
        return 0;
    }

    /* cant knock to a +p channel */
    if(HiddenChannel(chptr))
    {
        sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
                           form_str(ERR_CANNOTSENDTOCHAN), name);
        return 0;
    }


    if(MyClient(source_p))
    {
        /* don't allow a knock if the user is banned */
        if(is_banned(chptr, source_p, NULL, NULL, NULL) == CHFL_BAN)
        {
            sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
                               form_str(ERR_CANNOTSENDTOCHAN), name);
            return 0;
        }

        /* local flood protection:
         * allow one knock per user per knock_delay
         * allow one knock per channel per knock_delay_channel
         */
        if(!IsOper(source_p) &&
                (source_p->localClient->last_knock + ConfigChannel.knock_delay) > CurrentTime)
        {
            sendto_one(source_p, form_str(ERR_TOOMANYKNOCK),
                       me.name, source_p->name, name, "user");
            return 0;
        }
        else if((chptr->last_knock + ConfigChannel.knock_delay_channel) > CurrentTime)
        {
            sendto_one(source_p, form_str(ERR_TOOMANYKNOCK),
                       me.name, source_p->name, name, "channel");
            return 0;
        }

        /* ok, we actually can send the knock, tell client */
        source_p->localClient->last_knock = CurrentTime;

        sendto_one(source_p, form_str(RPL_KNOCKDLVR),
                   me.name, source_p->name, name);
    }

    chptr->last_knock = CurrentTime;

    if(ConfigChannel.use_knock)
        sendto_channel_local(ONLY_CHANOPS, chptr, form_str(RPL_KNOCK),
                             me.name, name, name, source_p->name,
                             source_p->username, source_p->host);

    sendto_server(client_p, chptr, CAP_KNOCK|CAP_TS6, NOCAPS,
                  ":%s KNOCK %s", use_id(source_p), name);
    sendto_server(client_p, chptr, CAP_KNOCK, CAP_TS6,
                  ":%s KNOCK %s", source_p->name, name);
    return 0;
}
Example #29
0
/*
 * m_die - DIE command handler
 */
int m_die(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct Client* acptr;
  int      i;

  if (!MyClient(sptr) || !IsAnOper(sptr))
    {
      sendto_one(sptr, form_str(ERR_NOPRIVILEGES), me.name, parv[0]);
      return 0;
    }

  if (!IsOperDie(sptr))
    {
      sendto_one(sptr,":%s NOTICE %s :You have no D flag", me.name, parv[0]);
      return 0;
    }

  if (parc < 2)
    {
      sendto_one(sptr,":%s NOTICE %s :Need server name /die %s",
                 me.name,sptr->name,me.name);
      return 0;
    }
  else
    {
      if (irccmp(parv[1], me.name))
        {
          sendto_one(sptr,":%s NOTICE %s :Mismatch on /die %s",
                     me.name,sptr->name,me.name);
          return 0;
        }
    }

  for (i = 0; i <= highest_fd; i++)
    {
      if (!(acptr = local[i]))
        continue;
      if (IsClient(acptr))
        {
          if(IsAnOper(acptr))
            sendto_one(acptr,
                       ":%s NOTICE %s :Server Terminating. %s",
                       me.name, acptr->name,
                       get_client_name(sptr, HIDE_IP));
          else
            sendto_one(acptr,
                       ":%s NOTICE %s :Server Terminating. %s",
                       me.name, acptr->name,
                       get_client_name(sptr, MASK_IP));
        }
      else if (IsServer(acptr))
        sendto_one(acptr, ":%s ERROR :Terminated by %s",
                   me.name, get_client_name(sptr, MASK_IP));
    }
  flush_connections(0);
  irclog(L_NOTICE, "Server terminated by %s", get_client_name(sptr, HIDE_IP));
  /* 
   * this is a normal exit, tell the os it's ok 
   */
  exit(0);
  /* NOT REACHED */
  return 0;
}
Example #30
0
/*
 *
 *      parc    number of arguments ('sender' counted as one!)
 *      parv[1]..parv[parc-1]
 *              pointers to additional parameters, this is a NULL
 *              terminated list (parv[parc] == NULL).
 *
 * *WARNING*
 *      Numerics are mostly error reports. If there is something
 *      wrong with the message, just *DROP* it! Don't even think of
 *      sending back a neat error message -- big danger of creating
 *      a ping pong error message...
 */
static void
do_numeric(int numeric, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Client *target_p;
	struct Channel *chptr;

	if(parc < 2 || !IsServer(source_p))
		return;

	/* Remap low number numerics. */
	if(numeric < 100)
		numeric += 100;

	/*
	 * Prepare the parameter portion of the message into 'buffer'.
	 * (Because the buffer is twice as large as the message buffer
	 * for the socket, no overflow can occur here... ...on current
	 * assumptions--bets are off, if these are changed --msa)
	 * Note: if buffer is non-empty, it will begin with SPACE.
	 */
	if(parc > 1)
	{
		char *t = buffer;	/* Current position within the buffer */
		int i;
		int tl;		/* current length of presently being built string in t */
		for (i = 2; i < (parc - 1); i++)
		{
			tl = sprintf(t, " %s", parv[i]);
			t += tl;
		}
		sprintf(t, " :%s", parv[parc - 1]);
	}

	if((target_p = find_client(parv[1])) != NULL)
	{
		if(IsMe(target_p))
		{
			/*
			 * We shouldn't get numerics sent to us,
			 * any numerics we do get indicate a bug somewhere..
			 */
			/* ugh.  this is here because of nick collisions.  when two servers
			 * relink, they burst each other their nicks, then perform collides.
			 * if there is a nick collision, BOTH servers will kill their own
			 * nicks, and BOTH will kill the other servers nick, which wont exist,
			 * because it will have been already killed by the local server.
			 *
			 * unfortunately, as we cant guarantee other servers will do the
			 * "right thing" on a nick collision, we have to keep both kills.
			 * ergo we need to ignore ERR_NOSUCHNICK. --fl_
			 */
			/* quick comment. This _was_ tried. i.e. assume the other servers
			 * will do the "right thing" and kill a nick that is colliding.
			 * unfortunately, it did not work. --Dianora
			 */
			/* note, now we send PING on server connect, we can
			 * also get ERR_NOSUCHSERVER..
			 */
			if(numeric != ERR_NOSUCHNICK &&
			   numeric != ERR_NOSUCHSERVER)
				sendto_realops_snomask(SNO_GENERAL, L_ADMIN,
						     "*** %s(via %s) sent a %03d numeric to me: %s",
						     source_p->name,
						     client_p->name, numeric, buffer);
			return;
		}
		else if(target_p->from == client_p)
		{
			/* This message changed direction (nick collision?)
			 * ignore it.
			 */
			return;
		}

		/* csircd will send out unknown umode flag for +a (admin), drop it here. */
		if(numeric == ERR_UMODEUNKNOWNFLAG && MyClient(target_p))
			return;

		/* Fake it for server hiding, if its our client */
		sendto_one(target_p, ":%s %03d %s%s",
			   get_id(source_p, target_p), numeric,
			   get_id(target_p, target_p), buffer);
		return;
	}
	else if((chptr = find_channel(parv[1])) != NULL)
		sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
				     "%03d %s%s",
				     numeric, chptr->chname, buffer);
}