예제 #1
0
void
join_channels(u_short nicknum)
{
	channel *chan;
	u_short i;

	switch (me.servtype) {
		case SERV_IRCNN:
			switch (nicknum) {
				case CS:
					for (i = 0; me.chans[i]; i++) {
						toserv(":%s JOIN %s\r\n", me.sclients[CS].nick, me.chans[i]);
						hackops(me.chans[i], me.sclients[CS].nick);
					}
					break;
				case OS:
					for (i = 0; me.chans[i]; i++) {
						toserv(":%s JOIN %s\r\n", me.sclients[OS].nick, me.chans[i]);
						hackops(me.chans[i], me.sclients[OS].nick);
					}
					if (me.eob == 0) {
						tell_chans("\2[EOB]\2 Receiving burst from %s", me.hub->name);
						me.htmtime = time(NULL);
					}
					/* XXX - eskimo's lame services doesn't know what this channel is */
					toserv(":%s JOIN # 1\r\n", me.sclients[OS].nick);
					hackops("#", me.sclients[OS].nick);
					toserv(":%s MODE # +b *!*@*\r\n", me.sclients[OS].nick);
					toserv(":%s MODE # +inmsl 1\r\n", me.sclients[OS].nick);
				
					/* XXX - reaper sux */
					toserv(":%s JOIN #debug 1\r\n", me.sclients[OS].nick);
					servmode("#debug", me.sclients[OS].nick);
					toserv(":%s MODE #debug +b *!*@*\r\n", me.sclients[OS].nick);
					toserv(":%s MODE #debug +inmsl 1\r\n", me.sclients[OS].nick);
					break;
				default:
					return;
			}
			break;
		case SERV_HYBRD:
			/* :h6.wiz.cx SJOIN 1021703401 #stuff +tn :@wiz6 */
			if (nicknum != CS && nicknum != OS)
				break;
			for (i = 0; me.chans[i]; i++)
				if ((chan = find_channel(me.chans[i]))) {
					toserv(":%s SJOIN %lu %s + :@%s\r\n", me.servname, chan->ts, me.chans[i], me.sclients[nicknum].nick);
					add_user_to_channel(find_client(me.sclients[nicknum].nick), find_channel(me.chans[i]), OP);
				} else {
					toserv(":%s SJOIN %lu %s + :@%s\r\n", me.servname, time(NULL), me.chans[i], me.sclients[nicknum].nick);
					add_user_to_channel(find_client(me.sclients[nicknum].nick), add_channel(me.chans[i], time(NULL), 0), OP);
				}
			break;
	}
}
예제 #2
0
int
m_sjoin(user_t *cptr, int parc, char **parv)
{	/* :h6.wiz.cx SJOIN 1021703401 #stuff +tn :@wiz6 */
	channel *channel;
	time_t ts;
	char *tmp;
	u_short flag;

	if (parc < 4 || (ts = strtol(parv[1], (char **)NULL, 10)) < 0)
		return 0;
	if (!(channel = find_channel(parv[2])))
		channel = add_channel(parv[2], ts, 0);
	if (!(tmp = strtok(parv[4], " ")))
		return 0;
	goto nloop;
	while((tmp = strtok(NULL, " "))) {
nloop:		flag = 0;
		switch (*tmp) {
			case '@':
				flag = OP;
				break;
			case '+':
				flag = VOICE;
				break;
			case '%':
				flag = HALFOP;
				break;
		}
		if (flag != 0)
			tmp++;
		add_user_to_channel(find_client(tmp), channel, flag);
	}
	return 1;
}
예제 #3
0
int
m_join(user_t *cptr, int parc, char **parv)
{
	channel *chan;
	char *ptr;

	if (!cptr || IsServer(cptr) || !parv[1] || !(ptr = strtok(parv[1], ",")))
		return 0;
	goto loopy;
	while ((ptr = strtok(NULL, ","))) {
loopy:		if (ptr[0] != '#')
			continue;
		if (!(chan = find_channel(ptr)))
			chan = add_channel(ptr, 0, 0);
		add_user_to_channel(cptr, chan, 0);
	}
	return 1;
}
예제 #4
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);
}
예제 #5
0
파일: m_ojoin.c 프로젝트: awilfox/charybdis
/*
** mo_ojoin
**      parv[1] = channel
*/
static void
mo_ojoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr;
	int move_me = 0;

	/* admins only */
	if(!IsOperAdmin(source_p))
	{
		sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin");
		return;
	}

	if(*parv[1] == '@' || *parv[1] == '+')
	{
		parv[1]++;
		move_me = 1;
	}

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

	if(IsMember(source_p, chptr))
	{
		sendto_one_notice(source_p, ":Please part %s before using OJOIN", parv[1]);
		return;
	}

	if(move_me == 1)
		parv[1]--;

	sendto_wallops_flags(UMODE_WALLOP, &me,
			     "OJOIN called for %s by %s!%s@%s",
			     parv[1], source_p->name, source_p->username, source_p->host);
	ilog(L_MAIN, "OJOIN called for %s by %s",
	     parv[1], get_oper_name(source_p));
	/* only sends stuff for #channels remotely */
	sendto_server(NULL, chptr, NOCAPS, NOCAPS,
			":%s WALLOPS :OJOIN called for %s by %s!%s@%s",
			me.name, parv[1],
			source_p->name, source_p->username, source_p->host);

	if(*parv[1] == '@')
	{
		add_user_to_channel(chptr, source_p, CHFL_CHANOP);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :@%s",
			      me.id, (long) chptr->channelts, chptr->chname, source_p->id);
		send_channel_join(chptr, source_p);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
				     me.name, chptr->chname, source_p->name);

	}
	else if(*parv[1] == '+')
	{
		add_user_to_channel(chptr, source_p, CHFL_VOICE);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :+%s",
			      me.id, (long) chptr->channelts, chptr->chname, source_p->id);
		send_channel_join(chptr, source_p);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s",
				     me.name, chptr->chname, source_p->name);
	}
	else
	{
		add_user_to_channel(chptr, source_p, CHFL_PEON);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s JOIN %ld %s +",
			      source_p->id, (long) chptr->channelts, chptr->chname);
		send_channel_join(chptr, source_p);
	}

	/* send the topic... */
	if(chptr->topic != NULL)
	{
		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);
	}

	source_p->localClient->last_join_time = rb_current_time();
	channel_member_names(chptr, source_p, 1);
}
예제 #6
0
/* Join a channel, ignoring forwards, +ib, etc. It notifes source_p of any errors joining
 * NB: this assumes a local user.
 */
void user_join_override(struct Client * client_p, struct Client * source_p, struct Client * target_p, const char * channels)
{
	static char jbuf[BUFSIZE];
	struct Channel *chptr = NULL;
	char *name;
	const char *modes;
	char *p = NULL;
	int flags;
	char *chanlist;

	jbuf[0] = '\0';

	if(channels == NULL)
		return;

	/* rebuild the list of channels theyre supposed to be joining.
	 * this code has a side effect of losing keys, but..
	 */
	chanlist = LOCAL_COPY(channels);
	for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p))
	{
		/* check the length and name of channel is ok */
		if(!check_channel_name_loc(target_p, name) || (strlen(name) > LOC_CHANNELLEN))
		{
			sendto_one_numeric(source_p, ERR_BADCHANNAME,
					   form_str(ERR_BADCHANNAME), (unsigned char *) name);
			continue;
		}

		/* join 0 parts all channels */
		if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist)
		{
			(void) strcpy(jbuf, "0");
			continue;
		}

		/* check it begins with # or &, and local chans are disabled */
		else if(!IsChannelName(name) ||
		       (!ConfigChannel.use_local_channels && name[0] == '&'))
		{
			sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
					   form_str(ERR_NOSUCHCHANNEL), name);
			continue;
		}

		if(*jbuf)
			(void) strcat(jbuf, ",");
		(void) rb_strlcat(jbuf, name, sizeof(jbuf));
	}

	for(name = rb_strtok_r(jbuf, ",", &p); name; name = rb_strtok_r(NULL, ",", &p))
	{
		/* JOIN 0 simply parts all channels the user is in */
		if(*name == '0' && !atoi(name))
		{
			if(target_p->user->channel.head == NULL)
				continue;

			do_join_0(&me, target_p);
			continue;
		}
		
		if((chptr = find_channel(name)) != NULL)
		{
			if(IsMember(target_p, chptr))
			{
			/* debugging is fun... */
				sendto_one_notice(source_p, ":*** Notice -- %s is already in %s",
					 target_p->name, chptr->chname);
				return;
			}

			add_user_to_channel(chptr, target_p, CHFL_PEON);
			if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
			{
				chptr->join_count = 0;
				chptr->join_delta = rb_current_time();
			}
			chptr->join_count++;

			sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
					     target_p->name, target_p->username,
					     target_p->host, chptr->chname);

			sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
				      ":%s JOIN %ld %s +",
				      get_id(target_p, client_p), (long) chptr->channelts,
				      chptr->chname);

			del_invite(chptr, target_p);

			if(chptr->topic != NULL)
			{
				sendto_one(target_p, form_str(RPL_TOPIC), me.name,
				   target_p->name, chptr->chname, chptr->topic);
				sendto_one(target_p, form_str(RPL_TOPICWHOTIME),
					   me.name, source_p->name, chptr->chname,
					   chptr->topic_info, chptr->topic_time);
			}

			channel_member_names(chptr, target_p, 1);
		}
		else
		{
			if(!check_channel_name(name))
			{
				sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
					   source_p->name, (unsigned char *) name);
				return;
			}

			/* channel name must begin with & or # */
			if(!IsChannelName(name))
			{
				sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
					   source_p->name, (unsigned char *) name);
				return;
			}

			/* name can't be longer than CHANNELLEN */
			if(strlen(name) > CHANNELLEN)
			{
				sendto_one_notice(source_p, ":Channel name is too long");
				return;
			}

			chptr = get_or_create_channel(target_p, name, NULL);

			flags = CHFL_CHANOP;
			
			if(ConfigChannel.founder_on_channel_create && ConfigChannel.use_founder)
				flags |= CHFL_FOUNDER;

			if(ConfigChannel.admin_on_channel_create && ConfigChannel.use_admin)
				flags |= CHFL_ADMIN;

			add_user_to_channel(chptr, target_p, flags);
			if (chptr->mode.join_num &&
					rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
			{
				chptr->join_count = 0;
				chptr->join_delta = rb_current_time();
			}
			chptr->join_count++;
			
			sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
					     target_p->name, target_p->username,
					     target_p->host, chptr->chname);
		
			/* autochanmodes stuff */
			if(ConfigChannel.autochanmodes)
			{
				char * ch;
				for(ch = ConfigChannel.autochanmodes; *ch != '\0'; ch++)
				{
					chptr->mode.mode |= chmode_table[(unsigned int)*ch].mode_type;
				}
			}
			else
			{
				chptr->mode.mode |= MODE_TOPICLIMIT;
				chptr->mode.mode |= MODE_NOPRIVMSGS;
			}

			modes = channel_modes(chptr, &me);
			sendto_channel_local(ONLY_HALFOPSANDUP, chptr, ":%s MODE %s %s",
					     me.name, chptr->chname, modes);

			sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
				       ":%s SJOIN %ld %s %s :%s%s",
				       me.id, (long) chptr->channelts,
				       chptr->chname, modes,
				       flags & CHFL_FOUNDER ? "~@" : "@",
				       get_id(target_p, client_p));

			target_p->localClient->last_join_time = rb_current_time();
			channel_member_names(chptr, target_p, 1);

			/* we do this to let the oper know that a channel was created, this will be
			 * seen from the server handling the command instead of the server that
			 * the oper is on.
			 */
			sendto_one_notice(source_p, ":*** Notice -- Creating channel %s", chptr->chname);
		}
	}		


	return;
}
예제 #7
0
파일: m_join.c 프로젝트: blank4/unrealircd
/* Routine that actually makes a user join the channel
 * this does no actual checking (banned, etc.) it just adds the user
 */
DLLFUNC void _join_channel(aChannel *chptr, aClient *cptr, aClient *sptr, int flags)
{
    char *parv[] = { 0, 0 };
    /*
       **  Complete user entry to the new channel (if any)
     */
    add_user_to_channel(chptr, sptr, flags);
    /*
       ** notify all other users on the new channel
     */
    if (chptr->mode.mode & MODE_AUDITORIUM)
    {
        if (MyClient(sptr))
            sendto_one(sptr, ":%s!%s@%s JOIN :%s",
                       sptr->name, sptr->user->username,
                       GetHost(sptr), chptr->chname);
        sendto_chanops_butone(NULL, chptr, ":%s!%s@%s JOIN :%s",
                              sptr->name, sptr->user->username,
                              GetHost(sptr), chptr->chname);
    }
    else
        sendto_channel_butserv(chptr, sptr,
                               ":%s JOIN :%s", sptr->name, chptr->chname);

    sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3, sptr->name, MSG_JOIN,
                                 TOK_JOIN, "%s", chptr->chname);

#ifdef JOIN_INSTEAD_OF_SJOIN_ON_REMOTEJOIN
    if ((MyClient(sptr) && !(flags & CHFL_CHANOP)) || !MyClient(sptr))
        sendto_serv_butone_token_opt(cptr, OPT_SJ3, sptr->name, MSG_JOIN,
                                     TOK_JOIN, "%s", chptr->chname);
    if (flags && !(flags & CHFL_DEOPPED))
    {
#endif
        /* I _know_ that the "@%s " look a bit wierd
           with the space and all .. but its to get around
           a SJOIN bug --stskeeps */
        sendto_serv_butone_token_opt(cptr, OPT_SJ3|OPT_SJB64,
                                     me.name, MSG_SJOIN, TOK_SJOIN,
                                     "%B %s :%s%s ", (long)chptr->creationtime,
                                     chptr->chname, chfl_to_sjoin_symbol(flags), sptr->name);
        sendto_serv_butone_token_opt(cptr, OPT_SJ3|OPT_NOT_SJB64,
                                     me.name, MSG_SJOIN, TOK_SJOIN,
                                     "%li %s :%s%s ", chptr->creationtime,
                                     chptr->chname, chfl_to_sjoin_symbol(flags), sptr->name);
#ifdef JOIN_INSTEAD_OF_SJOIN_ON_REMOTEJOIN
    }
#endif

    if (MyClient(sptr))
    {
        /*
           ** Make a (temporal) creationtime, if someone joins
           ** during a net.reconnect : between remote join and
           ** the mode with TS. --Run
         */
        if (chptr->creationtime == 0)
        {
            chptr->creationtime = TStime();
            sendto_serv_butone_token(cptr, me.name,
                                     MSG_MODE, TOK_MODE, "%s + %lu",
                                     chptr->chname, chptr->creationtime);
        }
        del_invite(sptr, chptr);
        if (flags && !(flags & CHFL_DEOPPED))
        {
#ifndef PREFIX_AQ
            if ((flags & CHFL_CHANOWNER) || (flags & CHFL_CHANPROT))
            {
                /* +ao / +qo for when PREFIX_AQ is off */
                sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3,
                                             me.name,
                                             MSG_MODE, TOK_MODE, "%s +o%c %s %s %lu",
                                             chptr->chname, chfl_to_chanmode(flags), sptr->name, sptr->name,
                                             chptr->creationtime);
            } else {
#endif
                /* +v/+h/+o (and +a/+q if PREFIX_AQ is on) */
                sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3,
                                             me.name,
                                             MSG_MODE, TOK_MODE, "%s +%c %s %lu",
                                             chptr->chname, chfl_to_chanmode(flags), sptr->name,
                                             chptr->creationtime);
#ifndef PREFIX_AQ
            }
#endif
        }
        if (chptr->topic)
        {
            sendto_one(sptr, rpl_str(RPL_TOPIC),
                       me.name, sptr->name, chptr->chname, chptr->topic);
            sendto_one(sptr,
                       rpl_str(RPL_TOPICWHOTIME), me.name,
                       sptr->name, chptr->chname, chptr->topic_nick,
                       chptr->topic_time);
        }
        if (chptr->users == 1 && (MODES_ON_JOIN
#ifdef EXTCMODE
                                  || iConf.modes_on_join.extmodes)
#endif
           )
        {
#ifdef EXTCMODE
            int i;
            chptr->mode.extmode =  iConf.modes_on_join.extmodes;
            /* Param fun */
            for (i = 0; i <= Channelmode_highest; i++)
            {
                if (!Channelmode_Table[i].flag || !Channelmode_Table[i].paracount)
                    continue;
                if (chptr->mode.extmode & Channelmode_Table[i].mode)
                {
                    CmodeParam *p;
                    p = Channelmode_Table[i].put_param(NULL, iConf.modes_on_join.extparams[i]);
                    AddListItem(p, chptr->mode.extmodeparam);
                }
            }
#endif
            chptr->mode.mode = MODES_ON_JOIN;
#ifdef NEWCHFLOODPROT
            if (iConf.modes_on_join.floodprot.per)
            {
                chptr->mode.floodprot = MyMalloc(sizeof(ChanFloodProt));
                memcpy(chptr->mode.floodprot, &iConf.modes_on_join.floodprot, sizeof(ChanFloodProt));
            }
#else
            chptr->mode.kmode = iConf.modes_on_join.kmode;
            chptr->mode.per = iConf.modes_on_join.per;
            chptr->mode.msgs = iConf.modes_on_join.msgs;
#endif
            *modebuf = *parabuf = 0;
            channel_modes(sptr, modebuf, parabuf, chptr);
            /* This should probably be in the SJOIN stuff */
            sendto_serv_butone_token(&me, me.name, MSG_MODE, TOK_MODE,
                                     "%s %s %s %lu", chptr->chname, modebuf, parabuf,
                                     chptr->creationtime);
            sendto_one(sptr, ":%s MODE %s %s %s", me.name, chptr->chname, modebuf, parabuf);
        }
        parv[0] = sptr->name;
        parv[1] = chptr->chname;
        do_cmd(cptr, sptr, "NAMES", 2, parv);
        RunHook4(HOOKTYPE_LOCAL_JOIN, cptr, sptr,chptr,parv);
    } else {
        RunHook4(HOOKTYPE_REMOTE_JOIN, cptr, sptr, chptr, parv); /* (rarely used) */
    }

#ifdef NEWCHFLOODPROT
    /* I'll explain this only once:
     * 1. if channel is +f
     * 2. local client OR synced server
     * 3. then, increase floodcounter
     * 4. if we reached the limit AND only if source was a local client.. do the action (+i).
     * Nr 4 is done because otherwise you would have a noticeflood with 'joinflood detected'
     * from all servers.
     */
    if (chptr->mode.floodprot && (MyClient(sptr) || sptr->srvptr->serv->flags.synced) &&
            !IsULine(sptr) && do_chanflood(chptr->mode.floodprot, FLD_JOIN) && MyClient(sptr))
    {
        do_chanflood_action(chptr, FLD_JOIN, "join");
    }
#endif
}
예제 #8
0
/*
 * ms_burst - server message handler
 *
 * --  by Run [email protected]  december 1995 till march 1997
 *
 * parv[0] = sender prefix
 * parv[1] = channel name
 * parv[2] = channel timestamp
 * The meaning of the following parv[]'s depend on their first character:
 * If parv[n] starts with a '+':
 * Net burst, additive modes
 *   parv[n] = <mode>
 *   parv[n+1] = <param> (optional)
 *   parv[n+2] = <param> (optional)
 * If parv[n] starts with a '%', then n will be parc-1:
 *   parv[n] = %<ban> <ban> <ban> ...
 * If parv[n] starts with another character:
 *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
 *   where <mode> defines the mode and op-level
 *   for nick and all following nicks until the
 *   next <mode> field.
 *   Digits in the <mode> field have of two meanings:
 *   1) if it is the first field in this BURST message
 *      that contains digits, and/or when a 'v' is
 *      present in the <mode>:
 *      The absolute value of the op-level.
 *   2) if there are only digits in this field and
 *      it is not the first field with digits:
 *      An op-level increment relative to the previous
 *      op-level.
 *   First all modeless nicks must be emmitted,
 *   then all combinations of modes without ops
 *   (currently that is only 'v') followed by the same
 *   series but then with ops (currently 'o','ov').
 *
 * Example:
 * "A8 B #test 87654321 +ntkAl key secret 123 A8AAG,A8AAC:v,A8AAA:0,A8AAF:2,A8AAD,A8AAB:v1,A8AAE:1 :%ban1 ban2"
 *
 * <mode> list example:
 *
 * "xxx,sss:v,ttt,aaa:123,bbb,ccc:2,ddd,kkk:v2,lll:2,mmm"
 *
 * means
 *
 *  xxx		// first modeless nicks
 *  sss +v	// then opless nicks
 *  ttt +v	// no ":<mode>": everything stays the same
 *  aaa -123	// first field with digit: absolute value
 *  bbb -123
 *  ccc -125	// only digits, not first field: increment
 *  ddd -125
 *  kkk -2 +v	// field with a 'v': absolute value
 *  lll -4 +v	// only digits: increment
 *  mmm -4 +v
 *
 * Anti net.ride code.
 *
 * When the channel already exist, and its TS is larger than
 * the TS in the BURST message, then we cancel all existing modes.
 * If its is smaller then the received BURST message is ignored.
 * If it's equal, then the received modes are just added.
 *
 * BURST is also accepted outside a netburst now because it
 * is sent upstream as reaction to a DESTRUCT message.  For
 * these BURST messages it is possible that the listed channel
 * members are already joined.
 */
int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct ModeBuf modebuf, *mbuf = 0;
  struct Channel *chptr;
  time_t timestamp;
  struct Membership *member, *nmember;
  struct Ban *lp, **lp_p;
  unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST);
  int param, nickpos = 0, banpos = 0;
  char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE];

  if (parc < 3)
    return protocol_violation(sptr,"Too few parameters for BURST");

  if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
    return 0; /* can't create the channel? */

  timestamp = atoi(parv[2]);

  if (chptr->creationtime)	/* 0 for new (empty) channels,
                                   i.e. when this server just restarted. */
  {
    if (parc == 3)		/* Zannel BURST? */
    {
      /* An empty channel without +A set, will cause a BURST message
	 with exactly 3 parameters (because all modes have been reset).
	 If the timestamp on such channels is only a few seconds older
	 from our own, then we ignore this burst: we do not deop our
	 own side.
	 Likewise, we expect the other (empty) side to copy our timestamp
	 from our own BURST message, even though it is slightly larger.

	 The reason for this is to allow people to join an empty
	 non-A channel (a zannel) during a net.split, and not be
	 deopped when the net reconnects (with another zannel). When
	 someone joins a split zannel, their side increments the TS by one.
	 If they cycle a few times then we still don't have a reason to
	 deop them. Theoretically I see no reason not to accept ANY timestamp,
	 but to be sure, we only accept timestamps that are just a few
	 seconds off (one second for each time they cycled the channel). */

      /* Don't even deop users who cycled four times during the net.break. */
      if (timestamp < chptr->creationtime &&
          chptr->creationtime <= timestamp + 4 &&
	  chptr->users != 0)	/* Only do this when WE have users, so that
	  			   if we do this the BURST that we sent has
				   parc > 3 and the other side will use the
				   test below: */
	timestamp = chptr->creationtime; /* Do not deop our side. */
    }
    else if (chptr->creationtime < timestamp &&
             timestamp <= chptr->creationtime + 4 &&
	     chptr->users == 0)
    {
      /* If one side of the net.junction does the above
         timestamp = chptr->creationtime, then the other
	 side must do this: */
      chptr->creationtime = timestamp;	/* Use the same TS on both sides. */
    }
    /* In more complex cases, we might still end up with a
       creationtime desync of a few seconds, but that should
       be synced automatically rather quickly (every JOIN
       caries a timestamp and will sync it; modes by users do
       not carry timestamps and are accepted regardless).
       Only when nobody joins the channel on the side with
       the oldest timestamp before a new net.break occurs
       precisely inbetween the desync, an unexpected bounce
       might happen on reconnect. */
  }

  if (!chptr->creationtime || chptr->creationtime > timestamp) {
    /*
     * Kick local members if channel is +i or +k and our TS was larger
     * than the burst TS (anti net.ride). The modes hack is here because
     * we have to do this before mode_parse, as chptr may go away.
     */
    for (param = 3; param < parc; param++)
    {
      int check_modes;
      if (parv[param][0] != '+')
        continue;
      check_modes = netride_modes(parc - param, parv + param, chptr->mode.key);
      if (check_modes < 0)
      {
        if (chptr->users == 0)
          sub1_from_channel(chptr);
        return protocol_violation(sptr, "Invalid mode string in BURST");
      }
      else if (check_modes)
      {
        /* Clear any outstanding rogue invites */
        mode_invite_clear(chptr);
        for (member = chptr->members; member; member = nmember)
        {
          nmember = member->next_member;
          if (!MyUser(member->user) || IsZombie(member))
            continue;
          /* Kick as netrider if key mismatch *or* remote channel is
           * +i (unless user is an oper) *or* remote channel is +r
           * (unless user has an account).
           */
          if (!(check_modes & MODE_KEY)
              && (!(check_modes & MODE_INVITEONLY) || IsAnOper(member->user))
              && (!(check_modes & MODE_REGONLY) || IsAccount(member->user)))
            continue;
          sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user);
          sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user);
          make_zombie(member, member->user, &me, &me, chptr);
        }
      }
      break;
    }

    /* If the channel had only locals, it went away by now. */
    if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
      return 0; /* can't create the channel? */
  }

  /* turn off burst joined flag */
  for (member = chptr->members; member; member = member->next_member)
    member->status &= ~(CHFL_BURST_JOINED|CHFL_BURST_ALREADY_OPPED|CHFL_BURST_ALREADY_VOICED);

  if (!chptr->creationtime) /* mark channel as created during BURST */
    chptr->mode.mode |= MODE_BURSTADDED;

  /* new channel or an older one */
  if (!chptr->creationtime || chptr->creationtime > timestamp) {
    chptr->creationtime = timestamp;

    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
		 MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
    modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
    chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;

    /* wipe out modes not represented in chptr->mode.mode */
    if (chptr->mode.limit) {
      modebuf_mode_uint(mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit);
      chptr->mode.limit = 0;
    }
    if (chptr->mode.key[0]) {
      modebuf_mode_string(mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0);
      chptr->mode.key[0] = '\0';
    }
    if (chptr->mode.upass[0]) {
      modebuf_mode_string(mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0);
      chptr->mode.upass[0] = '\0';
    }
    if (chptr->mode.apass[0]) {
      modebuf_mode_string(mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0);
      chptr->mode.apass[0] = '\0';
    }

    parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */

    /* mark bans for wipeout */
    for (lp = chptr->banlist; lp; lp = lp->next)
      lp->flags |= BAN_BURST_WIPEOUT;

    /* clear topic set by netrider (if set) */
    if (*chptr->topic) {
      *chptr->topic = '\0';
      *chptr->topic_nick = '\0';
      chptr->topic_time = 0;
      sendcmdto_channel_butserv_butone(&his, CMD_TOPIC, chptr, NULL, 0,
                                       "%H :%s", chptr, chptr->topic);
    }
  } else if (chptr->creationtime == timestamp) {
    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
		 MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);

    parse_flags |= MODE_PARSE_SET; /* set new modes */
  }

  param = 3; /* parse parameters */
  while (param < parc) {
    switch (*parv[param]) {
    case '+': /* parameter introduces a mode string */
      param += mode_parse(mbuf, cptr, sptr, chptr, parc - param,
			  parv + param, parse_flags, NULL);
      break;

    case '%': /* parameter contains bans */
      if (parse_flags & MODE_PARSE_SET) {
	char *banlist = parv[param] + 1, *p = 0, *ban, *ptr;
	struct Ban *newban;

	for (ban = ircd_strtok(&p, banlist, " "); ban;
	     ban = ircd_strtok(&p, 0, " ")) {
	  ban = collapse(pretty_mask(ban));

	    /*
	     * Yeah, we should probably do this elsewhere, and make it better
	     * and more general; this will hold until we get there, though.
	     * I dislike the current add_banid API... -Kev
	     *
	     * I wish there were a better algo. for this than the n^2 one
	     * shown below *sigh*
	     */
	  for (lp = chptr->banlist; lp; lp = lp->next) {
	    if (!ircd_strcmp(lp->banstr, ban)) {
	      ban = 0; /* don't add ban */
	      lp->flags &= ~BAN_BURST_WIPEOUT; /* not wiping out */
	      break; /* new ban already existed; don't even repropagate */
	    } else if (!(lp->flags & BAN_BURST_WIPEOUT) &&
		       !mmatch(lp->banstr, ban)) {
	      ban = 0; /* don't add ban unless wiping out bans */
	      break; /* new ban is encompassed by an existing one; drop */
	    } else if (!mmatch(ban, lp->banstr))
	      lp->flags |= BAN_OVERLAPPED; /* remove overlapping ban */

	    if (!lp->next)
	      break;
	  }

	  if (ban) { /* add the new ban to the end of the list */
	    /* Build ban buffer */
	    if (!banpos) {
	      banstr[banpos++] = ' ';
	      banstr[banpos++] = ':';
	      banstr[banpos++] = '%';
	    } else
	      banstr[banpos++] = ' ';
	    for (ptr = ban; *ptr; ptr++) /* add ban to buffer */
	      banstr[banpos++] = *ptr;

	    newban = make_ban(ban); /* create new ban */
            strcpy(newban->who, "*");
	    newban->when = TStime();
	    newban->flags |= BAN_BURSTED;
	    newban->next = 0;
	    if (lp)
	      lp->next = newban; /* link it in */
	    else
	      chptr->banlist = newban;
	  }
	}
      } 
      param++; /* look at next param */
      break;

    default: /* parameter contains clients */
      {
	struct Client *acptr;
	char *nicklist = parv[param], *p = 0, *nick, *ptr;
	int current_mode, last_mode, base_mode;
	int oplevel = -1;	/* Mark first field with digits: means the same as 'o' (but with level). */
	int last_oplevel = 0;
	struct Membership* member;

        base_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
        if (chptr->mode.mode & MODE_DELJOINS)
            base_mode |= CHFL_DELAYED;
        current_mode = last_mode = base_mode;

	for (nick = ircd_strtok(&p, nicklist, ","); nick;
	     nick = ircd_strtok(&p, 0, ",")) {

	  if ((ptr = strchr(nick, ':'))) { /* new flags; deal */
	    *ptr++ = '\0';

	    if (parse_flags & MODE_PARSE_SET) {
	      int current_mode_needs_reset;
	      for (current_mode_needs_reset = 1; *ptr; ptr++) {
		if (*ptr == 'o') { /* has oper status */
		  /*
		   * An 'o' is pre-oplevel protocol, so this is only for
		   * backwards compatibility.  Give them an op-level of
		   * MAXOPLEVEL so everyone can deop them.
		   */
		  oplevel = MAXOPLEVEL;
		  if (current_mode_needs_reset) {
		    current_mode = base_mode;
		    current_mode_needs_reset = 0;
		  }
		  current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
                  /*
                   * Older servers may send XXYYY:ov, in which case we
                   * do not want to use the code for 'v' below.
                   */
                  if (ptr[1] == 'v') {
                    current_mode |= CHFL_VOICE;
                    ptr++;
                  }
		}
		else if (*ptr == 'v') { /* has voice status */
		  if (current_mode_needs_reset) {
                    current_mode = base_mode;
		    current_mode_needs_reset = 0;
		  }
		  current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_VOICE;
		  oplevel = -1;	/* subsequent digits are an absolute op-level value. */
                }
		else if (IsDigit(*ptr)) {
		  int level_increment = 0;
		  if (oplevel == -1) { /* op-level is absolute value? */
		    if (current_mode_needs_reset) {
		      current_mode = base_mode;
		      current_mode_needs_reset = 0;
		    }
		    oplevel = 0;
		  }
		  current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
		  do {
		    level_increment = 10 * level_increment + *ptr++ - '0';
		  } while (IsDigit(*ptr));
		  oplevel += level_increment;
		}
		else /* I don't recognize that flag */
		  break; /* so stop processing */
	      }
	    }
	  }

	  if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr)
	    continue; /* ignore this client */

	  /* Build nick buffer */
	  nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */
	  nickpos++;

	  for (ptr = nick; *ptr; ptr++) /* store nick */
	    nickstr[nickpos++] = *ptr;

	  if (current_mode != last_mode) { /* if mode changed... */
	    last_mode = current_mode;
	    last_oplevel = oplevel;

	    nickstr[nickpos++] = ':'; /* add a specifier */
	    if (current_mode & CHFL_VOICE)
	      nickstr[nickpos++] = 'v';
	    if (current_mode & CHFL_CHANOP)
            {
              if (chptr->mode.apass[0])
	        nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel);
              else
                nickstr[nickpos++] = 'o';
            }
	  } else if (current_mode & CHFL_CHANOP && oplevel != last_oplevel) { /* if just op level changed... */
	    nickstr[nickpos++] = ':'; /* add a specifier */
	    nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel - last_oplevel);
            last_oplevel = oplevel;
	  }

	  if (!(member = find_member_link(chptr, acptr)))
	  {
	    add_user_to_channel(chptr, acptr, current_mode, oplevel);
            if (!(current_mode & CHFL_DELAYED))
              sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, 0, "%H", chptr);
	  }
	  else
	  {
	    /* The member was already joined (either by CREATE or JOIN).
	       Remember the current mode. */
	    if (member->status & CHFL_CHANOP)
	      member->status |= CHFL_BURST_ALREADY_OPPED;
	    if (member->status & CHFL_VOICE)
	      member->status |= CHFL_BURST_ALREADY_VOICED;
	    /* Synchronize with the burst. */
	    member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE));
	    SetOpLevel(member, oplevel);
	  }
	}
      }
      param++;
      break;
    } /* switch (*parv[param]) */
  } /* while (param < parc) */

  nickstr[nickpos] = '\0';
  banstr[banpos] = '\0';

  if (parse_flags & MODE_PARSE_SET) {
    modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */
    modestr[0] = modestr[1] ? ' ' : '\0';
  } else
    modestr[0] = '\0';

  sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr,
			chptr->creationtime, modestr, nickstr, banstr);

  if (parse_flags & MODE_PARSE_WIPEOUT || banpos)
    mode_ban_invalidate(chptr);

  if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */
    /* first deal with channel members */
    for (member = chptr->members; member; member = member->next_member) {
      if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
	if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED))
	  modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member));
	if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED))
	  modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member));
      } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
	if (member->status & CHFL_CHANOP)
	  modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member));
	if (member->status & CHFL_VOICE)
	  modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member));
	member->status = (member->status
                          & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE))
			 | CHFL_DEOPPED;
      }
    }

    /* Now deal with channel bans */
    lp_p = &chptr->banlist;
    while (*lp_p) {
      lp = *lp_p;

      /* remove ban from channel */
      if (lp->flags & (BAN_OVERLAPPED | BAN_BURST_WIPEOUT)) {
        char *bandup;
        DupString(bandup, lp->banstr);
	modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
			    bandup, 1);
	*lp_p = lp->next; /* clip out of list */
        free_ban(lp);
	continue;
      } else if (lp->flags & BAN_BURSTED) /* add ban to channel */
	modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN,
			    lp->banstr, 0); /* don't free banstr */

      lp->flags &= BAN_IPMASK; /* reset the flag */
      lp_p = &(*lp_p)->next;
    }
  }

  return mbuf ? modebuf_flush(mbuf) : 0;
}
예제 #9
0
/*
 * m_forcejoin
 *      parv[1] = user to force
 *      parv[2] = channel to force them into
 */
static int
mo_forcejoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
    struct Client *target_p;
    struct Channel *chptr;
    int type;
    char mode;
    char sjmode;
    char *newch;

    if(!IsOperAdmin(source_p)) {
        sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin");
        return 0;
    }

    if((hunt_server(client_p, source_p, ":%s FORCEJOIN %s %s", 1, parc, parv)) != HUNTED_ISME)
        return 0;

    /* if target_p is not existant, print message
     * to source_p and bail - scuzzy
     */
    if((target_p = find_client(parv[1])) == NULL) {
        sendto_one(source_p, form_str(ERR_NOSUCHNICK), me.name, source_p->name, parv[1]);
        return 0;
    }

    if(!IsPerson(target_p))
        return 0;

    sendto_wallops_flags(UMODE_WALLOP, &me,
                         "FORCEJOIN called for %s %s by %s!%s@%s",
                         parv[1], parv[2], source_p->name, source_p->username, source_p->host);
    ilog(L_MAIN, "FORCEJOIN called for %s %s by %s!%s@%s",
         parv[1], parv[2], source_p->name, source_p->username, source_p->host);
    sendto_server(NULL, NULL, NOCAPS, NOCAPS,
                  ":%s WALLOPS :FORCEJOIN called for %s %s by %s!%s@%s",
                  me.name, parv[1], parv[2],
                  source_p->name, source_p->username, source_p->host);

    /* select our modes from parv[2] if they exist... (chanop) */
    if(*parv[2] == '@') {
        type = CHFL_CHANOP;
        mode = 'o';
        sjmode = '@';
    } else if(*parv[2] == '+') {
        type = CHFL_VOICE;
        mode = 'v';
        sjmode = '+';
    } else {
        type = CHFL_PEON;
        mode = sjmode = '\0';
    }

    if(mode != '\0')
        parv[2]++;

    if((chptr = find_channel(parv[2])) != NULL) {
        if(IsMember(target_p, chptr)) {
            /* debugging is fun... */
            sendto_one_notice(source_p, ":*** Notice -- %s is already in %s",
                              target_p->name, chptr->chname);
            return 0;
        }

        add_user_to_channel(chptr, target_p, type);

        sendto_server(target_p, chptr, NOCAPS, NOCAPS,
                      ":%s SJOIN %ld %s + :%c%s",
                      me.name, (long) chptr->channelts,
                      chptr->chname, type ? sjmode : ' ', target_p->name);

        sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
                             target_p->name, target_p->username,
                             target_p->host, chptr->chname);

        if(type)
            sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s",
                                 me.name, chptr->chname, mode, target_p->name);

        if(chptr->topic != NULL) {
            sendto_one(target_p, form_str(RPL_TOPIC), me.name,
                       target_p->name, chptr->chname, chptr->topic);
            sendto_one(target_p, form_str(RPL_TOPICWHOTIME),
                       me.name, source_p->name, chptr->chname,
                       chptr->topic_info, chptr->topic_time);
        }

        channel_member_names(chptr, target_p, 1);
    } else {
        newch = LOCAL_COPY(parv[2]);
        if(!check_channel_name(newch)) {
            sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
                       source_p->name, (unsigned char *) newch);
            return 0;
        }

        /* channel name must begin with & or # */
        if(!IsChannelName(newch)) {
            sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
                       source_p->name, (unsigned char *) newch);
            return 0;
        }

        /* newch can't be longer than CHANNELLEN */
        if(strlen(newch) > CHANNELLEN) {
            sendto_one_notice(source_p, ":Channel name is too long");
            return 0;
        }

        chptr = get_or_create_channel(target_p, newch, NULL);
        add_user_to_channel(chptr, target_p, CHFL_CHANOP);

        /* send out a join, make target_p join chptr */
        sendto_server(target_p, chptr, NOCAPS, NOCAPS,
                      ":%s SJOIN %ld %s +nt :@%s", me.name,
                      (long) chptr->channelts, chptr->chname, target_p->name);

        sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
                             target_p->name, target_p->username,
                             target_p->host, chptr->chname);

        chptr->mode.mode |= MODE_TOPICLIMIT;
        chptr->mode.mode |= MODE_NOPRIVMSGS;

        sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +nt", me.name, chptr->chname);

        target_p->localClient->last_join_time = rb_current_time();
        channel_member_names(chptr, target_p, 1);

        /* we do this to let the oper know that a channel was created, this will be
         * seen from the server handling the command instead of the server that
         * the oper is on.
         */
        sendto_one_notice(source_p, ":*** Notice -- Creating channel %s", chptr->chname);
    }
    return 0;
}
예제 #10
0
/*
** mo_ojoin
**      parv[1] = channel
*/
static int
mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr;
	int move_me = 0;

	/* admins only */
	if(!IsOperAdmin(source_p))
	{
		sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "ojoin");
		return 0;
	}

	/* XXX - we might not have CBURSTed this channel if we are a lazylink
	 * yet. */

	if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+')
	{
		parv[1]++;
		move_me = 1;
	}

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

	if(IsMember(source_p, chptr))
	{
		sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN",
			   me.name, source_p->name, parv[1]);
		return 0;
	}

	if(move_me == 1)
		parv[1]--;

	if(*parv[1] == '@')
	{
		add_user_to_channel(chptr, source_p, CHFL_CHANOP);
		sendto_server(client_p, chptr, NOCAPS, NOCAPS,
			      ":%s SJOIN %ld %s + :@%s",
			      me.name, (long)chptr->channelts, chptr->chname, source_p->name);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name,
				     source_p->username, source_p->host, chptr->chname);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
				     me.name, chptr->chname, source_p->name);

	}
	else if(*parv[1] == '+')
	{
		add_user_to_channel(chptr, source_p, CHFL_VOICE);
		sendto_server(client_p, chptr, NOCAPS, NOCAPS,
			      ":%s SJOIN %ld %s + :+%s",
			      me.name, (long)chptr->channelts, chptr->chname, source_p->name);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name,
				     source_p->username, source_p->host, chptr->chname);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s",
				     me.name, chptr->chname, source_p->name);
	}
	else
	{
		add_user_to_channel(chptr, source_p, CHFL_PEON);
		sendto_server(client_p, chptr, NOCAPS, NOCAPS,
			      ":%s SJOIN %ld %s + :%s",
			      me.name, (long)chptr->channelts, chptr->chname, source_p->name);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name,
				     source_p->username, source_p->host, chptr->chname);
	}

	/* send the topic... */
	if(chptr->topic != NULL)
	{
		sendto_one(source_p, form_str(RPL_TOPIC), me.name,
			   source_p->name, chptr->chname, chptr->topic->topic);
		sendto_one(source_p, form_str(RPL_TOPICWHOTIME), me.name,
			   source_p->name, chptr->chname, chptr->topic->topic_info,
			   chptr->topic->topic_time);
	}

	source_p->localClient->last_join_time = rb_time();
	channel_member_names(chptr, source_p, 1);

	return 0;
}
예제 #11
0
/*
** mo_ojoin
**      parv[0] = sender prefix
**      parv[1] = channel
*/
static void mo_ojoin(struct Client *client_p, struct Client *source_p,
                        int parc, char *parv[])
{
	struct Channel *chptr;
	int move_me = 0;

	/* admins only */
	if (!IsOperAdmin(source_p))
	{
		sendto_one(source_p, ":%s NOTICE %s :You have no A flag", me.name, parv[0]);
		return;
	}

	if (*parv[1] == '@' || *parv[1] == '+')
	{
		parv[1]++;
		move_me = 1;
	}

	chptr = hash_find_channel(parv[1]);

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

	if(IsMember(source_p, chptr))
	{
		sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN",
			   me.name, source_p->name, parv[1]);
		return;
	}

	if (move_me == 1)
		parv[1]--;

	sendto_wallops_flags(UMODE_WALLOP, &me, 
			     "OJOIN called for [%s] by %s!%s@%s",
			     parv[1], source_p->name, source_p->username, source_p->host);
	ilog(L_NOTICE, "OJOIN called for [%s] by %s!%s@%s",
	     parv[1], source_p->name, source_p->username, source_p->host);

	if(*chptr->chname != '&')
		sendto_server(NULL, NULL, NOCAPS, NOCAPS, 
			      ":%s WALLOPS :OJOIN called for [%s] by %s!%s@%s",
			      me.name, parv[1], source_p->name, source_p->username,
			      source_p->host);

	if (*parv[1] == '@') 
	{
		add_user_to_channel(chptr, source_p, CHFL_CHANOP);

		if(*chptr->chname != '&')
			sendto_server(client_p, chptr, NOCAPS, NOCAPS,  
				      ":%s SJOIN %lu %s + :@%s", 
				      me.name, chptr->channelts,
				      chptr->chname, source_p->name);

		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name, source_p->username,
				     source_p->host, chptr->chname);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
				     me.name, chptr->chname, source_p->name);

	}
	else if (*parv[1] == '+')
	{
		add_user_to_channel(chptr, source_p, CHFL_VOICE);

		if(*chptr->chname != '&')
			sendto_server(client_p, chptr, NOCAPS, NOCAPS,  
				      ":%s SJOIN %lu %s + :+%s",
				      me.name, chptr->channelts,
				      chptr->chname, source_p->name);

		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name, source_p->username,
				     source_p->host, chptr->chname);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s",
				     me.name, chptr->chname, source_p->name);
	}
	else
	{
		add_user_to_channel(chptr, source_p, CHFL_PEON);

		if(*chptr->chname != '&')
			sendto_server(client_p, chptr, NOCAPS, NOCAPS,  
				      ":%s SJOIN %lu %s + :%s",
				      me.name, chptr->channelts,
				      chptr->chname, source_p->name);

		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name, source_p->username,
				     source_p->host, chptr->chname);
	}

	/* send the topic... */
	if (chptr->topic != NULL)
	{
		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);
	}

	source_p->localClient->last_join_time = CurrentTime;
	channel_member_names(chptr, source_p, 1);
}
예제 #12
0
/*
 * m_join
 *      parv[0] = sender prefix
 *      parv[1] = channel
 *      parv[2] = channel password (key)
 */
static void
m_join(struct Client *client_p,
       struct Client *source_p,
       int parc,
       char *parv[])
{
  struct Channel *chptr = NULL;
  char  *name, *key = NULL;
  int   i, flags = 0;
  char  *p = NULL, *p2 = NULL;
  int   successful_join_count = 0; /* Number of channels successfully joined */
  
  if (*parv[1] == '\0')
    {
      sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
                 me.name, parv[0], "JOIN");
      return;
    }

  if (parc > 2)
    {
      key = strtoken(&p2, parv[2], ",");
    }

  for (name = strtoken(&p, parv[1], ","); name;
         key = (key) ? strtoken(&p2, NULL, ",") : NULL,
         name = strtoken(&p, NULL, ","))
    {

      if(!check_channel_name(name))
      {
        sendto_one(source_p, form_str(ERR_BADCHANNAME),
	           me.name, source_p->name, (unsigned char*)name);
        continue;
      }

      /*
      ** JOIN 0 sends out a part for all channels a user
      ** has joined.
      **
      ** this should be either disabled or selectable in
      ** config file .. it's abused a lot more than it's
      ** used these days :/ --is
      */
      if (*name == '0' && !atoi(name))
      {
        if (source_p->user->channel.head == NULL)
          continue;
	  
        do_join_0(&me,source_p);
	continue;
      }
      
      /* check it begins with # or & */
      else if(!IsChannelName(name))
      {
        sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
	           me.name, source_p->name, name);
	continue;
      }

      if(ConfigServerHide.disable_local_channels &&
        (*name == '&'))
      {
        sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
	           me.name, source_p->name, name);
        continue;
      }

      /* check the length */
      if (strlen(name) > CHANNELLEN)
      {
        sendto_one(source_p, form_str(ERR_BADCHANNAME),
	           me.name, source_p->name, name);
	continue;
      }
      
      /* see if its resv'd */
      if(find_channel_resv(name) && 
         (!IsOper(source_p) || !ConfigChannel.no_oper_resvs))
	{
	  sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
		     me.name, source_p->name, name);
          sendto_realops_flags(UMODE_SPY, L_ALL,
                   "User %s (%s@%s) is attempting to join locally juped channel %s",
                   source_p->name, source_p->username, source_p->host, name);
	  continue;
	}

      /* look for the channel */
      if((chptr = hash_find_channel(name)) != NULL)
	{
	  if(IsMember(source_p, chptr))
            return;

	  if(splitmode && !IsOper(source_p) && (*name != '&') && 
             ConfigChannel.no_join_on_split)
	  {
	    sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
                       me.name, source_p->name, name);
	    continue;
	  }

	  if (chptr->users == 0)
	    flags = CHFL_CHANOP;
	  else
	    flags = 0;
	}
      else
	{
	  if(splitmode && !IsOper(source_p) && (*name != '&') && 
            (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split))
	  {
	    sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
	               me.name, source_p->name, name);
	    continue;
	  }
	  
	  flags = CHFL_CHANOP;
	}

      if ((source_p->user->joined >= ConfigChannel.max_chans_per_user) &&
         (!IsOper(source_p) || (source_p->user->joined >=
	                        ConfigChannel.max_chans_per_user*3)))
	{
	  sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
		     me.name, parv[0], name);
	  if(successful_join_count)
	    source_p->localClient->last_join_time = CurrentTime;
	  return;
	}

      if(flags == 0)        /* if channel doesn't exist, don't penalize */
	successful_join_count++;

      if(chptr == NULL)     /* If I already have a chptr, no point doing this */
	{
	  chptr = get_or_create_channel(source_p, name, NULL);
	}
      
      if(chptr == NULL)
	{
	  sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
		     me.name, parv[0], name);
	  if(successful_join_count > 0)
	    successful_join_count--;
	  continue;
	}

    if (!IsOper(source_p))
     check_spambot_warning(source_p, name);
      
      /* can_join checks for +i key, bans etc */
      if ( (i = can_join(source_p, chptr, key)) )
	{
	  sendto_one(source_p,
		     form_str(i), me.name, parv[0], name);
	  if(successful_join_count > 0)
	    successful_join_count--;
	  continue;
	}

      /* add the user to the channel */
      add_user_to_channel(chptr, source_p, flags);

      /* we send the user their join here, because we could have to
       * send a mode out next.
       */
      sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
			   source_p->name,
			   source_p->username,
			   source_p->host,
			   chptr->chname);

      /* if theyre joining opped (ie, new chan or joining one thats
       * persisting) then set timestamp to current, set +nt and
       * broadcast the sjoin with its old modes, or +nt.
       */
      if (flags & CHFL_CHANOP)
	{
          char mbuf[MODEBUFLEN];
          char pbuf[MODEBUFLEN];

	  chptr->channelts = CurrentTime;
          chptr->mode.mode |= MODE_TOPICLIMIT;
          chptr->mode.mode |= MODE_NOPRIVMSGS;

	  sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s +nt",
			       me.name, chptr->chname);

          if(*chptr->chname == '#')
          {
            channel_modes(chptr, source_p, mbuf, pbuf);

            strlcat(mbuf, " ", sizeof(mbuf));

            if(pbuf[0] != '\0')
              strlcat(mbuf, pbuf, sizeof(mbuf));

            /* note: mbuf here will have a trailing space.  we add one above,
             * and channel_modes() will leave a trailing space on pbuf if
             * its used --fl
             */
	    sendto_server(client_p, chptr, NOCAPS, NOCAPS,
                          ":%s SJOIN %lu %s %s:@%s",
                          me.name, (unsigned long) chptr->channelts, 
                          chptr->chname, mbuf, parv[0]);
          }

          /* drop our +beI modes */
          free_channel_list(&chptr->banlist);
          free_channel_list(&chptr->exceptlist);
          free_channel_list(&chptr->invexlist);
	}
      else 
	{
	  sendto_server(client_p, chptr, NOCAPS, NOCAPS,
                        ":%s SJOIN %lu %s + :%s",
                        me.name, (unsigned long) chptr->channelts,
                        chptr->chname, parv[0]);
        }

      del_invite(chptr, source_p);
      
      if (chptr->topic != NULL)
	{
	  sendto_one(source_p, form_str(RPL_TOPIC), me.name,
		     parv[0], chptr->chname, chptr->topic);

          sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
                     me.name, parv[0], chptr->chname,
                     chptr->topic_info,
                     chptr->topic_time);
	}

      channel_member_names(source_p, chptr, chptr->chname, 1);

      if(successful_join_count)
	source_p->localClient->last_join_time = CurrentTime;
    }
}
예제 #13
0
/* mo_ojoin()
 *      parv[0] = sender prefix
 *      parv[1] = channels separated by commas
 */
static void
mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
{
	struct Channel *chptr = NULL;
	const char *prefix = "";
	char modeletter = '\0';
	char *name = parv[1];
	char *t = NULL;
	unsigned int flags = 0;

	/* admins only */
	if(!IsAdmin(source_p))
	{
		sendto_one(source_p, form_str(ERR_NOPRIVILEGES), me.name, source_p->name);
		return;
	}

	for(name = strtoken(&t, name, ","); name; name = strtoken(&t, NULL, ","))
	{
		switch (*name)
		{
		case '@':
			prefix = "@";
			flags = CHFL_CHANOP;
			modeletter = 'o';
			++name;
			break;
#ifdef HALFOPS
		case '%':
			prefix = "%";
			flags = CHFL_HALFOP;
			modeletter = 'h';
			++name;
			break;
#endif
		case '+':
			prefix = "+";
			flags = CHFL_VOICE;
			modeletter = 'v';
			++name;
			break;
		case '#':
		case '&':
			prefix = "";
			flags = 0;
			modeletter = '\0';
			break;

		default:
			sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
				   me.name, source_p->name, name);
			continue;
		}

		/* Error checking here */
		if((chptr = hash_find_channel(name)) == NULL)
		{
			sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
				   me.name, source_p->name, name);
		}
		else if(IsMember(source_p, chptr))
		{
			sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN",
				   me.name, source_p->name, name);
		}
		else
		{
			add_user_to_channel(chptr, source_p, flags, NO);

			if(chptr->chname[0] == '#')
			{
				sendto_server(client_p, source_p, chptr, CAP_TS6, NOCAPS,
					      LL_ICLIENT, ":%s SJOIN %lu %s + :%s%s", me.id,
					      (unsigned long) chptr->channelts, chptr->chname,
					      prefix, source_p->id);
				sendto_server(client_p, source_p, chptr, NOCAPS, CAP_TS6,
					      LL_ICLIENT, ":%s SJOIN %lu %s + :%s%s", me.name,
					      (unsigned long) chptr->channelts, chptr->chname,
					      prefix, source_p->name);
			}

			sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN %s",
					     source_p->name, source_p->username,
					     source_p->host, chptr->chname);

			if(modeletter != '\0')
				sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s MODE %s +%c %s",
						     me.name, chptr->chname, modeletter,
						     source_p->name);

			/* send the topic... */
			if(chptr->topic != NULL)
			{
				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);
			}

			source_p->localClient->last_join_time = CurrentTime;
			channel_member_names(source_p, chptr, 1);
		}
	}
}
예제 #14
0
/*
** mo_ojoin
**      parv[1] = channel
*/
static int
mo_ojoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr;
	int move_me = 0;

	/* admins only */
	if(!IsOperAdmin(source_p))
	{
		sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin");
		return 0;
	}

	if(*parv[1] == '@' || *parv[1] == '%' || *parv[1] == '+' || *parv[1] == '!'
	   || *parv[1] == '~')
	{
		parv[1]++;
		move_me = 1;
	}
	else
	{
		sendto_one_notice(source_p, ":Unrecognized op prefix '%c'", *parv[1]);
		return 0;
	}

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

	if(IsMember(source_p, chptr))
	{
		sendto_one_notice(source_p, ":Please part %s before using OJOIN", parv[1]);
		return 0;
	}

	if(move_me == 1)
		parv[1]--;

	/* only sends stuff for #channels remotely */

	if(*parv[1] == '!')
	{
		if(!ConfigChannel.use_admin)
		{
			sendto_one_notice(source_p,
					  ":This server's configuration file does not support admin prefix");
			return 0;
		}

		add_user_to_channel(chptr, source_p, CHFL_ADMIN);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :!%s",
			      me.id, (long) chptr->channelts, chptr->chname, source_p->id);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name,
				     source_p->username, source_p->host, chptr->chname);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s",
				     me.name, chptr->chname, source_p->name);

	}
	else if(*parv[1] == '@')
	{
		add_user_to_channel(chptr, source_p, CHFL_CHANOP);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :@%s",
			      me.id, (long) chptr->channelts, chptr->chname, source_p->id);
		send_channel_join(chptr, source_p);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
				     me.name, chptr->chname, source_p->name);

	}
	else if(*parv[1] == '%')
	{
		if(!ConfigChannel.use_halfop)
		{
			sendto_one_notice(source_p,
					  ":This server's configuration file does not support halfop prefix");
			return 0;
		}

		add_user_to_channel(chptr, source_p, CHFL_HALFOP);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :%s%s",
			      me.id, (long) chptr->channelts, chptr->chname, "%", source_p->id);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
				     source_p->name,
				     source_p->username, source_p->host, chptr->chname);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s",
				     me.name, chptr->chname, source_p->name);
	}
	else if(*parv[1] == '+')
	{
		add_user_to_channel(chptr, source_p, CHFL_VOICE);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :+%s",
			      me.id, (long) chptr->channelts, chptr->chname, source_p->id);
		send_channel_join(chptr, source_p);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +v %s",
				     me.name, chptr->chname, source_p->name);
	}
	else if(*parv[1] == '~')
	{
		if(!ConfigChannel.use_founder)
		{
			sendto_one_notice(source_p,
					  ":This server's configuration file does not support founder prefix");
			return 0;
		}

		add_user_to_channel(chptr, source_p, CHFL_FOUNDER);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s SJOIN %ld %s + :~%s",
			      me.id, (long) chptr->channelts, chptr->chname, source_p->id);
		send_channel_join(chptr, source_p);
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +u %s",
				     me.name, chptr->chname, source_p->name);
	}
	else
	{
		add_user_to_channel(chptr, source_p, CHFL_PEON);
		sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
			      ":%s JOIN %ld %s +",
			      source_p->id, (long) chptr->channelts, chptr->chname);
		send_channel_join(chptr, source_p);
	}

	/* send the topic... */
	if(chptr->topic != NULL)
	{
		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);
	}

	source_p->localClient->last_join_time = rb_current_time();
	channel_member_names(chptr, source_p, 1);

	sendto_realops_snomask(SNO_GENERAL, L_ALL,
			       "OJOIN called for %s by %s!%s@%s",
			       parv[1], source_p->name, source_p->username, source_p->host);
	ilog(L_MAIN, "OJOIN called for %s by %s", parv[1], get_oper_name(source_p));


	return 0;
}
예제 #15
0
/* Join a channel, ignoring forwards, +ib, etc. It notifes source_p of any errors joining
 * NB: this assumes a local user.
 */
void user_join_override(struct Client * client_p, struct Client * source_p, struct Client * target_p, const char * channels)
{
	static char jbuf[BUFSIZE];
	struct ConfItem *aconf;
	struct Channel *chptr = NULL;
	char *name;
	const char *modes;
	char *p = NULL;
	int flags;
	char *chanlist;

	jbuf[0] = '\0';

	if(channels == NULL)
		return;

	/* rebuild the list of channels theyre supposed to be joining. */
	chanlist = LOCAL_COPY(channels);
	for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p))
	{
		/* check the length and name of channel is ok */
		if(!check_channel_name_loc(target_p, name) || (strlen(name) > LOC_CHANNELLEN))
		{
			sendto_one_numeric(source_p, ERR_BADCHANNAME,
					   form_str(ERR_BADCHANNAME), (unsigned char *) name);
			continue;
		}

		/* join 0 parts all channels */
		if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist)
		{
			(void) strcpy(jbuf, "0");
			continue;
		}

		/* check it begins with # or & */
		else if(!IsChannelName(name))
		{
			sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
					   form_str(ERR_NOSUCHCHANNEL), name);
			continue;
		}

		/* see if its resv'd */
		if(!IsExemptResv(target_p) && (aconf = hash_find_resv(name)))
		{
			sendto_one_numeric(source_p, ERR_BADCHANNAME,
					   form_str(ERR_BADCHANNAME), name);

			/* dont update tracking for jupe exempt users, these
			 * are likely to be spamtrap leaves
			 */
			if(IsExemptJupe(source_p))
				aconf->port--;

			continue;
		}

		if(splitmode && !IsOper(target_p) && (*name != '&') &&
		   ConfigChannel.no_join_on_split)
		{
			sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
				   me.name, source_p->name, name);
			continue;
		}

		if(*jbuf)
			(void) strcat(jbuf, ",");
		(void) rb_strlcat(jbuf, name, sizeof(jbuf));
	}

	for(name = rb_strtok_r(jbuf, ",", &p); name; name = rb_strtok_r(NULL, ",", &p))
	{
		/* JOIN 0 simply parts all channels the user is in */
		if(*name == '0' && !atoi(name))
		{
			if(target_p->user->channel.head == NULL)
				continue;

			do_join_0(&me, target_p);
			continue;
		}
		
		if((chptr = find_channel(name)) != NULL)
		{
			if(IsMember(target_p, chptr))
			{
				/* debugging is fun... */
				sendto_one_notice(source_p, ":*** Notice -- %s is already in %s",
					 target_p->name, chptr->chname);
				return;
			}

			add_user_to_channel(chptr, target_p, CHFL_PEON);
			if (chptr->mode.join_num && rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
			{
				chptr->join_count = 0;
				chptr->join_delta = rb_current_time();
			}
			chptr->join_count++;

			sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
					     target_p->name, target_p->username,
					     target_p->host, chptr->chname);

			sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
				      ":%s JOIN %ld %s +",
				      get_id(target_p, client_p), (long) chptr->channelts,
				      chptr->chname);

			del_invite(chptr, target_p);

			if(chptr->topic != NULL)
			{
				sendto_one(target_p, form_str(RPL_TOPIC), me.name,
				   target_p->name, chptr->chname, chptr->topic);
				sendto_one(target_p, form_str(RPL_TOPICWHOTIME),
					   me.name, source_p->name, chptr->chname,
					   chptr->topic_info, chptr->topic_time);
			}

			channel_member_names(chptr, target_p, 1);
		}
		else
		{
			hook_data_channel_activity hook_info;
			char statusmodes[5] = "";

			if(!check_channel_name(name))
			{
				sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
					   source_p->name, (unsigned char *) name);
				return;
			}

			/* channel name must begin with & or # */
			if(!IsChannelName(name))
			{
				sendto_one(source_p, form_str(ERR_BADCHANNAME), me.name,
					   source_p->name, (unsigned char *) name);
				return;
			}

			/* name can't be longer than CHANNELLEN */
			if(strlen(name) > CHANNELLEN)
			{
				sendto_one_notice(source_p, ":Channel name is too long");
				return;
			}

			chptr = get_or_create_channel(target_p, name, NULL);

			flags = CHFL_CHANOP;
			
			add_user_to_channel(chptr, target_p, flags);
			if (chptr->mode.join_num &&
					rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
			{
				chptr->join_count = 0;
				chptr->join_delta = rb_current_time();
			}
			chptr->join_count++;
			
			sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
					     target_p->name, target_p->username,
					     target_p->host, chptr->chname);
		
				chptr->mode.mode |= MODE_TOPICLIMIT;
				chptr->mode.mode |= MODE_NOPRIVMSGS;

			modes = channel_modes(chptr, &me);
			sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s",
					     me.name, chptr->chname, modes);

			strcat(statusmodes, "@");

			sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
				      ":%s SJOIN %ld %s %s :%s%s",
				      me.id, (long) chptr->channelts,
				      chptr->chname, modes, statusmodes,
				      get_id(target_p, client_p));

			target_p->localClient->last_join_time = rb_current_time();
			channel_member_names(chptr, target_p, 1);

			/* Call channel join hooks */
			hook_info.client = source_p;
			hook_info.chptr = chptr;
			hook_info.key = chptr->mode.key;
			call_hook(h_channel_join, &hook_info);

			/* we do this to let the oper know that a channel was created, this will be
			 * seen from the server handling the command instead of the server that
			 * the oper is on.
			 */
			sendto_one_notice(source_p, ":*** Notice -- Creating channel %s", chptr->chname);
		}
	}		


	return;
}
예제 #16
0
/*
 * m_lljoin
 *      parv[0] = sender prefix
 *      parv[1] = channel
 *      parv[2] = nick ("!nick" == cjoin)
 *      parv[3] = vchan/key (optional)
 *      parv[4] = 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;
  char *vkey = NULL;
  int  flags;
  int  i;
  struct Client *target_p;
  struct Channel *chptr, *vchan_chptr, *root_vchan;
#ifdef VCHANS
  int cjoin = 0;
  int  vc_ts;
  char *pvc = NULL;
#endif

  if(uplink && !IsCapable(uplink,CAP_LL))
    {
      sendto_realops_flags(FLAGS_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;

#ifdef VCHANS
  if (nick[0] == '!')
  {
    cjoin = 1;
    nick++;
  }
 
  if(parc > 4)
  {
    key = parv[4];
    vkey = parv[3];
  }
#endif
  else if(parc >3)
  {
    key = vkey = parv[3];
  }

  flags = 0;

  target_p = find_client(nick);

  if( !target_p || !target_p->user )
    return;

  if( !MyClient(target_p) )
    return;

  chptr = hash_find_channel(chname);

#ifdef VCHANS
  if (cjoin)
  {
    if(!chptr) /* Uhm, bad! */
    {
      sendto_realops_flags(FLAGS_ALL, L_ALL,
        "LLJOIN %s %s called by %s, but root chan doesn't exist!",
        chname, nick, client_p->name);
      return;
    }
    flags = CHFL_CHANOP;

    if(! (vchan_chptr = cjoin_channel(chptr, target_p, chname)))
      return;

    root_vchan = chptr;
    chptr = vchan_chptr;
  }
  else
#endif
  {
#ifdef VCHANS
    if (chptr)
    {
      vchan_chptr = select_vchan(chptr, target_p, vkey, chname);
    }
    else
#endif
    {
      chptr = vchan_chptr = get_or_create_channel(target_p, chname, NULL);
      flags = CHFL_CHANOP;
    }
   
#ifdef VCHANS
    if (vchan_chptr != chptr)
    {
      root_vchan = chptr;
      chptr = vchan_chptr;
    }
    else
#endif
      root_vchan = chptr;

    if(!chptr || !root_vchan)
      return;

    if (chptr->users == 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, root_vchan->chname);
      return;
    }

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

  if ((target_p->user->joined >= ConfigChannel.max_chans_per_user) &&
      (!IsOper(target_p) || (target_p->user->joined >= 
                             ConfigChannel.max_chans_per_user*3)))
    {
      sendto_one(target_p, form_str(ERR_TOOMANYCHANNELS),
		 me.name, nick, root_vchan->chname );
      return; 
    }
  
  if(flags == CHFL_CHANOP)
    {
      chptr->channelts = CurrentTime;
      /*
       * XXX - this is a rather ugly hack.
       *
       * Unfortunately, there's no way to pass
       * the fact that it is a vchan through SJOIN...
       */
      /* Prevent users creating a fake vchan */
#ifdef VCHANS
      if (chname[0] == '#' && chname[1] == '#')
        {
          if ((pvc = strrchr(chname+3, '_')))
          {
            /*
             * OK, name matches possible vchan:
             * ##channel_blah
             */
            pvc++; /*  point pvc after last _ */
            vc_ts = atol(pvc);
            /*
             * if blah is the same as the TS, up the TS
             * by one, to prevent this channel being
             * seen as a vchan
             */
            if (vc_ts == CurrentTime)
              chptr->channelts++;
          }
        }
#endif

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

  /* a user can create a channel with halfops..? */
#if 0
  else if ((flags == CHFL_HALFOP) && (IsCapable(uplink, CAP_HOPS)))
    {
      sendto_one(uplink,
		 ":%s SJOIN %lu %s + :%%%s",
		 me.name,
		 (unsigned long) chptr->channelts,
		 chptr->chname,
		 nick);
    }
#endif
  else
    {
      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);

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

  channel_member_names(target_p, chptr, chname, 1);
}
예제 #17
0
/*
** mo_clearchan
**      parv[0] = sender prefix
**      parv[1] = channel
*/
static void mo_clearchan(struct Client *client_p, struct Client *source_p,
                        int parc, char *parv[])
{
  struct Channel *chptr, *root_chptr;
  int on_vchan = 0;

  /* admins only */
  if (!IsOperAdmin(source_p))
    {
      sendto_one(source_p, ":%s NOTICE %s :You have no A flag", me.name, parv[0]);
      return;
    }

  /* XXX - we might not have CBURSTed this channel if we are a lazylink
   * yet. */
  chptr= hash_find_channel(parv[1]);
  root_chptr = chptr;

#ifdef VCHANS
  if (chptr && parc > 2 && parv[2][0] == '!')
    {
      chptr = find_vchan(chptr, parv[2]);
      if (root_chptr != chptr)
        on_vchan++;
    }
#endif

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

  if(IsMember(source_p, chptr))
    {
      sendto_one(source_p, ":%s NOTICE %s :*** Please part %s before using CLEARCHAN",
                 me.name, source_p->name, parv[1]);
      return;
    }

  if (!on_vchan)
    {
     sendto_wallops_flags(FLAGS_WALLOP, &me, 
              "CLEARCHAN called for [%s] by %s!%s@%s",
              parv[1], source_p->name, source_p->username, source_p->host);
     sendto_server(NULL, source_p, NULL, NOCAPS, NOCAPS, LL_ICLIENT,
                   ":%s WALLOPS :CLEARCHAN called for [%s] by %s!%s@%s",
                   me.name, parv[1], source_p->name, source_p->username,
                   source_p->host);
     ilog(L_NOTICE, "CLEARCHAN called for [%s] by %s!%s@%s",
         parv[1], source_p->name, source_p->username, source_p->host);
    }
  else
    {
     sendto_wallops_flags(FLAGS_WALLOP, &me,
              "CLEARCHAN called for [%s %s] by %s!%s@%s",
              parv[1], parv[2], source_p->name, source_p->username,
              source_p->host);
     sendto_server(NULL, source_p, NULL, NOCAPS, NOCAPS, LL_ICLIENT,
                   ":%s WALLOPS :CLEARCHAN called for [%s %s] by %s!%s@%s",
                   me.name, parv[1], parv[2], source_p->name,
                   source_p->username, source_p->host);
     ilog(L_NOTICE, "CLEARCHAN called for [%s %s] by %s!%s@%s",
         parv[1], parv[2], source_p->name, source_p->username, source_p->host);
    }

  /* Kill all the modes we have about the channel.. making everyone a peon */  
  remove_our_modes(0, chptr, root_chptr, source_p);
  
  /* SJOIN the user to give them ops, and lock the channel */

  sendto_server(client_p, source_p, chptr, NOCAPS, NOCAPS,
                LL_ICLIENT, ":%s SJOIN %lu %s +ntsi :@%s",
                me.name, (unsigned long) (chptr->channelts - 1),
                chptr->chname, source_p->name);
  sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
                       source_p->name,
                       source_p->username,
                       source_p->host,
                       root_chptr->chname);
  sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
                       me.name, chptr->chname, source_p->name);

  add_user_to_channel(chptr, source_p, CHFL_CHANOP);

  /* Take the TS down by 1, so we don't see the channel taken over
   * again. */
  if (chptr->channelts)
    chptr->channelts--;
  
#ifdef VCHANS
  if (on_vchan)
    add_vchan_to_client_cache(source_p,root_chptr,chptr);
#endif

  chptr->mode.mode =
    MODE_SECRET | MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS;
  free_topic(chptr);
  chptr->mode.key[0] = 0;

  /* Kick the users out and join the oper */
  kick_list(client_p, source_p, chptr, &chptr->peons, chptr->chname);

}
예제 #18
0
/* mo_ojoin()
 *      parv[0] = sender prefix
 *      parv[1] = channels separated by commas (#ifdef OJOIN_MULTIJOIN)
 */
static void
mo_ojoin(struct Client *client_p, struct Client *source_p,
         int parc, char *parv[])
{
    struct Channel *chptr;
    char *name = parv[1], modeletter;
#ifdef OJOIN_MULTIJOIN
    char *t;
#endif
    short move_me = 1;
    unsigned int tmp_flags;

    /* admins only */
    if (!IsAdmin(source_p))
    {
        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
                   me.name, source_p->name);
        return;
    }

#ifdef OJOIN_MULTIJOIN
    for (name = strtoken (&t, name, ","); name;
            name = strtoken (&t, NULL, ","))
    {
#endif

        move_me = 1;

        switch (*name)
        {
#ifndef DISABLE_CHAN_OWNER
        case '!':
            tmp_flags = CHFL_CHANOWNER;
            modeletter = 'u';
            name++;
            break;
#endif
        case '@':
            tmp_flags = CHFL_CHANOP;
            modeletter = 'o';
            name++;
            break;
        case '+':
            tmp_flags = CHFL_VOICE;
            modeletter = 'v';
            name++;
            break;
        case '%':
            tmp_flags = CHFL_HALFOP;
            modeletter = 'h';
            name++;
            break;
        case '#':
        case '&':
            tmp_flags = 0;
            modeletter = '\0';
            break;

        /* We're not joining a channel, or we don't know the mode,
        * what ARE we joining? */
        default:
            sendto_one (source_p, form_str(ERR_NOSUCHCHANNEL),
                        me.name, source_p->name, name);

#ifdef OJOIN_MULTIJOIN
            continue;
#else
            return;
#endif
        }

        /* Error checking here */

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

        else if (IsMember(source_p, chptr))
        {
            sendto_one(source_p, ":%s NOTICE %s :Please part %s before using OJOIN",
                       me.name, source_p->name, name);
        }

        else
        {
            if (move_me == 1)
                name--;

            add_user_to_channel(chptr, source_p, tmp_flags);

            if (chptr->chname[0] == '#')
            {
                sendto_server(client_p, CAP_TS6, NOCAPS,
                              ":%s SJOIN %lu %s + :%c%s",
                              me.id, (unsigned long)chptr->channelts, chptr->chname,
                              (modeletter != '\0') ? *name : ' ',
                              source_p->id);
                sendto_server(client_p, NOCAPS, CAP_TS6,
                              ":%s SJOIN %lu %s + :%c%s", me.name,
                              (unsigned long)chptr->channelts,
                              chptr->chname, (modeletter != '\0') ? *name : ' ',
                              source_p->name);
            }

            sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN %s",
                                 source_p->name,
                                 source_p->username,
                                 GET_CLIENT_HOST(source_p),
                                 chptr->chname);

            if (modeletter != '\0')
            {
                sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +%c %s",
                                     me.name, chptr->chname, modeletter, source_p->name);
            }

            /* send the topic... */
            if (chptr->topic != NULL)
            {
                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);
            }

            source_p->localClient->last_join_time = CurrentTime;
            channel_member_names(source_p, chptr, 1);
        }
#ifdef OJOIN_MULTIJOIN
    }
#endif
}
예제 #19
0
/*
 * ms_burst - server message handler
 *
 * --  by Run [email protected]  december 1995 till march 1997
 *
 * parv[0] = sender prefix
 * parv[1] = channel name
 * parv[2] = channel timestamp
 * The meaning of the following parv[]'s depend on their first character:
 * If parv[n] starts with a '+':
 * Net burst, additive modes
 *   parv[n] = <mode>
 *   parv[n+1] = <param> (optional)
 *   parv[n+2] = <param> (optional)
 * If parv[n] starts with a '%', then n will be parc-1:
 *   parv[n] = %<ban> <ban> <ban> ...
 * If parv[n] starts with another character:
 *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
 *   where <mode> is the channel mode (ov) of nick and all following nicks.
 *
 * Example:
 * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
 *
 * Anti net.ride code.
 *
 * When the channel already exist, and its TS is larger then
 * the TS in the BURST message, then we cancel all existing modes.
 * If its is smaller then the received BURST message is ignored.
 * If it's equal, then the received modes are just added.
 */
int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
{
  struct ModeBuf modebuf, *mbuf = 0;
  struct Channel *chptr;
  time_t timestamp;
  struct Membership *member, *nmember;
  struct SLink *lp, **lp_p;
  unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST);
  int param, nickpos = 0, banpos = 0;
  char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE];

  if (parc < 3)
    return protocol_violation(sptr,"Too few parameters for BURST");

  if (!IsBurst(sptr)) /* don't allow BURST outside of burst */
    return exit_client_msg(cptr, cptr, &me, "HACK: BURST message outside "
			   "net.burst from %s", cli_name(sptr));

  if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
    return 0; /* can't create the channel? */

  timestamp = atoi(parv[2]);

  if (!chptr->creationtime || chptr->creationtime > timestamp) {
    /*
     * Kick local members if channel is +i or +k and our TS was larger
     * than the burst TS (anti net.ride). The modes hack is here because
     * we have to do this before mode_parse, as chptr may go away.
     */
    for (param = 3; param < parc; param++) {
      if (parv[param][0] != '+')
        continue;
      if (strchr(parv[param], 'i') || strchr(parv[param], 'k')) {
        /* Clear any outstanding rogue invites */
        mode_invite_clear(chptr);
        for (member = chptr->members; member; member = nmember) {
          nmember=member->next_member;
          if (!MyUser(member->user) || IsZombie(member))
            continue;
          sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user);
          sendcmdto_channel_butserv_butone(&me, CMD_KICK, chptr, NULL, "%H %C :Net Rider", chptr, member->user);
          make_zombie(member, member->user, &me, &me, chptr);
        }
      }
      break;
    }

    /* If the channel had only locals, it went away by now. */
    if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
      return 0; /* can't create the channel? */
  }

  /* turn off burst joined flag */
  for (member = chptr->members; member; member = member->next_member)
    member->status &= ~CHFL_BURST_JOINED;

  if (!chptr->creationtime) /* mark channel as created during BURST */
    chptr->mode.mode |= MODE_BURSTADDED;

  /* new channel or an older one */
  if (!chptr->creationtime || chptr->creationtime > timestamp) {
    chptr->creationtime = timestamp;

    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
		 MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
    modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
    chptr->mode.mode &= ~(MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET |
			  MODE_MODERATED | MODE_TOPICLIMIT | MODE_INVITEONLY |
			  MODE_NOPRIVMSGS);

    parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */

    /* mark bans for wipeout */
    for (lp = chptr->banlist; lp; lp = lp->next)
      lp->flags |= CHFL_BURST_BAN_WIPEOUT;
  
    /* clear topic set by netrider (if set) */
    if (*chptr->topic) {
      *chptr->topic = '\0';
      *chptr->topic_nick = '\0';
      chptr->topic_time = 0;
      sendcmdto_channel_butserv_butone(&me, CMD_TOPIC, chptr, NULL, 
                                       "%H :%s", chptr, chptr->topic);
    }
  } else if (chptr->creationtime == timestamp) {
    modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
		 MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);

    parse_flags |= MODE_PARSE_SET; /* set new modes */
  }

  param = 3; /* parse parameters */
  while (param < parc) {
    switch (*parv[param]) {
    case '+': /* parameter introduces a mode string */
      param += mode_parse(mbuf, cptr, sptr, chptr, parc - param,
			  parv + param, parse_flags);
      break;

    case '%': /* parameter contains bans */
      if (parse_flags & MODE_PARSE_SET) {
	char *banlist = parv[param] + 1, *p = 0, *ban, *ptr;
	struct SLink *newban;

	for (ban = ircd_strtok(&p, banlist, " "); ban;
	     ban = ircd_strtok(&p, 0, " ")) {
	  ban = collapse(pretty_mask(ban));

	    /*
	     * Yeah, we should probably do this elsewhere, and make it better
	     * and more general; this will hold until we get there, though.
	     * I dislike the current add_banid API... -Kev
	     *
	     * I wish there were a better algo. for this than the n^2 one
	     * shown below *sigh*
	     */
	  for (lp = chptr->banlist; lp; lp = lp->next) {
	    if (!ircd_strcmp(lp->value.ban.banstr, ban)) {
	      ban = 0; /* don't add ban */
	      lp->flags &= ~CHFL_BURST_BAN_WIPEOUT; /* not wiping out */
	      break; /* new ban already existed; don't even repropagate */
	    } else if (!(lp->flags & CHFL_BURST_BAN_WIPEOUT) &&
		       !mmatch(lp->value.ban.banstr, ban)) {
	      ban = 0; /* don't add ban unless wiping out bans */
	      break; /* new ban is encompassed by an existing one; drop */
	    } else if (!mmatch(ban, lp->value.ban.banstr))
	      lp->flags |= CHFL_BAN_OVERLAPPED; /* remove overlapping ban */

	    if (!lp->next)
	      break;
	  }

	  if (ban) { /* add the new ban to the end of the list */
	    /* Build ban buffer */
	    if (!banpos) {
	      banstr[banpos++] = ' ';
	      banstr[banpos++] = ':';
	      banstr[banpos++] = '%';
	    } else
	      banstr[banpos++] = ' ';
	    for (ptr = ban; *ptr; ptr++) /* add ban to buffer */
	      banstr[banpos++] = *ptr;

	    newban = make_link(); /* create new ban */

	    DupString(newban->value.ban.banstr, ban);

	    DupString(newban->value.ban.who, 
		      cli_name(feature_bool(FEAT_HIS_BANWHO) ? &me : sptr));

	    newban->value.ban.when = TStime();

	    newban->flags = CHFL_BAN | CHFL_BURST_BAN; /* set flags */
	    if ((ptr = strrchr(ban, '@')) && check_if_ipmask(ptr + 1))
	      newban->flags |= CHFL_BAN_IPMASK;

	    newban->next = 0;
	    if (lp)
	      lp->next = newban; /* link it in */
	    else
	      chptr->banlist = newban;
	  }
	}
      } 
      param++; /* look at next param */
      break;

    default: /* parameter contains clients */
      {
	struct Client *acptr;
	char *nicklist = parv[param], *p = 0, *nick, *ptr;
	int default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
	int last_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;

	for (nick = ircd_strtok(&p, nicklist, ","); nick;
	     nick = ircd_strtok(&p, 0, ",")) {

	  if ((ptr = strchr(nick, ':'))) { /* new flags; deal */
	    *ptr++ = '\0';

	    if (parse_flags & MODE_PARSE_SET) {
	      for (default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; *ptr;
		   ptr++) {
		if (*ptr == 'o') /* has oper status */
		  default_mode = (default_mode & ~CHFL_DEOPPED) | CHFL_CHANOP;
		else if (*ptr == 'v') /* has voice status */
		  default_mode |= CHFL_VOICE;
		else /* I don't recognize that flag */
		  break; /* so stop processing */
	      }
	    }
	  }

	  if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr)
	    continue; /* ignore this client */

	  /* Build nick buffer */
	  nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */
	  nickpos++;

	  for (ptr = nick; *ptr; ptr++) /* store nick */
	    nickstr[nickpos++] = *ptr;

	  if (default_mode != last_mode) { /* if mode changed... */
	    last_mode = default_mode;

	    nickstr[nickpos++] = ':'; /* add a specifier */
	    if (default_mode & CHFL_CHANOP)
	      nickstr[nickpos++] = 'o';
	    if (default_mode & CHFL_VOICE)
	      nickstr[nickpos++] = 'v';
	  }

	  add_user_to_channel(chptr, acptr, default_mode);
	  sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, "%H", chptr);
	}
      }
      param++;
      break;
    } /* switch (*parv[param]) { */
  } /* while (param < parc) { */

  nickstr[nickpos] = '\0';
  banstr[banpos] = '\0';

  if (parse_flags & MODE_PARSE_SET) {
    modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */
    modestr[0] = modestr[1] ? ' ' : '\0';
  } else
    modestr[0] = '\0';

  sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr,
			chptr->creationtime, modestr, nickstr, banstr);

  if (parse_flags & MODE_PARSE_WIPEOUT || banpos)
    mode_ban_invalidate(chptr);

  if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */
    /* first deal with channel members */
    for (member = chptr->members; member; member = member->next_member) {
      if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
	if (member->status & CHFL_CHANOP)
	  modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user);
	if (member->status & CHFL_VOICE)
	  modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user);
      } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
	if (member->status & CHFL_CHANOP)
	  modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user);
	if (member->status & CHFL_VOICE)
	  modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user);
	member->status = ((member->status & ~(CHFL_CHANOP | CHFL_VOICE)) |
			  CHFL_DEOPPED);
      }
    }

    /* Now deal with channel bans */
    lp_p = &chptr->banlist;
    while (*lp_p) {
      lp = *lp_p;

      /* remove ban from channel */
      if (lp->flags & (CHFL_BAN_OVERLAPPED | CHFL_BURST_BAN_WIPEOUT)) {
	modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
			    lp->value.ban.banstr, 1); /* let it free banstr */

	*lp_p = lp->next; /* clip out of list */
	MyFree(lp->value.ban.who); /* free who */
	free_link(lp); /* free ban */
	continue;
      } else if (lp->flags & CHFL_BURST_BAN) /* add ban to channel */
	modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN,
			    lp->value.ban.banstr, 0); /* don't free banstr */

      lp->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* reset the flag */
      lp_p = &(*lp_p)->next;
    }
  }

  return mbuf ? modebuf_flush(mbuf) : 0;
}
예제 #20
0
/*
 * mo_omode - MODE command handler
 * parv[1] - channel
 */
static int
mo_omode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
	struct Channel *chptr = NULL;
	struct membership *msptr;
	char params[512];
	int i;
	int wasonchannel;
	/* admins only */
	if (!IsOperAdmin(source_p)) {
		sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "admin");
		return 0;
	}
	/* Now, try to find the channel in question */
	if (!IsChanPrefix(parv[1][0]) || !check_channel_name(parv[1])) {
		sendto_one_numeric(source_p, ERR_BADCHANNAME,
		                   form_str(ERR_BADCHANNAME), parv[1]);
		return 0;
	}
	chptr = find_channel(parv[1]);
	if (chptr == NULL) {
		sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
		                   form_str(ERR_NOSUCHCHANNEL), parv[1]);
		return 0;
	}
	/* Now know the channel exists */
	msptr = find_channel_membership(chptr, source_p);
	wasonchannel = msptr != NULL;
	if (is_any_op(msptr)) {
		sendto_one_notice(source_p, ":Use a normal MODE you idiot");
		return 0;
	}
	params[0] = '\0';
	for (i = 2; i < parc; i++) {
		if (i != 2)
			rb_strlcat(params, " ", sizeof params);
		rb_strlcat(params, parv[i], sizeof params);
	}
	sendto_wallops_flags(UMODE_WALLOP, &me,
	                     "OMODE called for [%s] [%s] by %s!%s@%s",
	                     parv[1], params, source_p->name, source_p->username, source_p->host);
	ilog(L_MAIN, "OMODE called for [%s] [%s] by %s",
	     parv[1], params, get_oper_name(source_p));
	if (*chptr->chname != '&')
		sendto_server(NULL, NULL, NOCAPS, NOCAPS,
		              ":%s WALLOPS :OMODE called for [%s] [%s] by %s!%s@%s",
		              me.name, parv[1], params, source_p->name, source_p->username,
		              source_p->host);
#if 0
	set_channel_mode(client_p, source_p->servptr, chptr, msptr,
	                 parc - 2, parv + 2);
#else
	if (parc == 4 && !strcmp(parv[2], "+y") && !irccmp(parv[3], source_p->name)) {
		/* Ownering themselves */
		if (!wasonchannel) {
			sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
			                   form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname);
			return 0;
		}
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +y %s",
		                     me.name, parv[1], source_p->name);
		sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
		              ":%s TMODE %ld %s +y %s",
		              me.id, (long) chptr->channelts, parv[1],
		              source_p->id);
		msptr->flags |= CHFL_OWNER;
	} else if (parc == 4 && !strcmp(parv[2], "+a") && !irccmp(parv[3], source_p->name)) {
		/* Admining themselves */
		if (!wasonchannel) {
			sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
			                   form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname);
			return 0;
		}
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +a %s",
		                     me.name, parv[1], source_p->name);
		sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
		              ":%s TMODE %ld %s +a %s",
		              me.id, (long) chptr->channelts, parv[1],
		              source_p->id);
		msptr->flags |= CHFL_ADMIN;
	} else if (parc == 4 && !strcmp(parv[2], "+o") && !irccmp(parv[3], source_p->name)) {
		/* Opping themselves */
		if (!wasonchannel) {
			sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
			                   form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname);
			return 0;
		}
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
		                     me.name, parv[1], source_p->name);
		sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
		              ":%s TMODE %ld %s +o %s",
		              me.id, (long) chptr->channelts, parv[1],
		              source_p->id);
		msptr->flags |= CHFL_CHANOP;
	} else if (parc == 4 && !strcmp(parv[2], "+h") && !irccmp(parv[3], source_p->name)) {
		/* Halfopping themselves */
		if (!wasonchannel) {
			sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
			                   form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->chname);
			return 0;
		}
		sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s +h %s",
		                     me.name, parv[1], source_p->name);
		sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
		              ":%s TMODE %ld %s +h %s",
		              me.id, (long) chptr->channelts, parv[1],
		              source_p->id);
		msptr->flags |= CHFL_HALFOP;
	} else if (ConfigChannel.use_owner) {
		/* I hope this is correct.
		 * -- Kabaka */
		/* Hack it so set_channel_mode() will accept */
		if (wasonchannel)
			msptr->flags |= CHFL_OWNER;
		else {
			add_user_to_channel(chptr, source_p, CHFL_CHANOP);
			msptr = find_channel_membership(chptr, source_p);
		}
		set_channel_mode(client_p, source_p, chptr, msptr,
		                 parc - 2, parv + 2);
		if (wasonchannel)
			msptr->flags &= ~CHFL_OWNER;
		else
			remove_user_from_channel(msptr);
	} else if (ConfigChannel.use_admin) {
		/* Hack it so set_channel_mode() will accept */
		if (wasonchannel)
			msptr->flags |= CHFL_ADMIN;
		else {
			add_user_to_channel(chptr, source_p, CHFL_CHANOP);
			msptr = find_channel_membership(chptr, source_p);
		}
		set_channel_mode(client_p, source_p, chptr, msptr,
		                 parc - 2, parv + 2);
		/* We know they were not opped before and they can't have opped
		 * themselves as set_channel_mode() does not allow that
		 * -- jilles */
		if (wasonchannel)
			msptr->flags &= ~CHFL_ADMIN;
		else
			remove_user_from_channel(msptr);
	} else {
		/* CHFL_ADMIN is only useful if admin is enabled
		 * so hack it with op if it is not. */
		if (wasonchannel)
			msptr->flags |= CHFL_CHANOP;
		else {
			add_user_to_channel(chptr, source_p, CHFL_CHANOP);
			msptr = find_channel_membership(chptr, source_p);
		}
		set_channel_mode(client_p, source_p, chptr, msptr,
		                 parc - 2, parv + 2);
		/* We know they were not opped before and they can't have opped
		 * themselves as set_channel_mode() does not allow that
		 * -- jilles */
		if (wasonchannel)
			msptr->flags &= ~CHFL_CHANOP;
		else
			remove_user_from_channel(msptr);
	}
#endif
	return 0;
}
예제 #21
0
/*
** m_cjoin
**      parv[0] = sender prefix
**      parv[1] = channel
**      parv[2] = channel password (key)
*/
static void m_cjoin(struct Client *client_p,
                   struct Client *source_p,
                   int parc,
                   char *parv[])
{
  static char   jbuf[BUFSIZE];
  struct Channel *chptr = NULL;
  struct Channel *vchan_chptr = NULL;
  struct Channel *root_vchan = NULL;
  char  *name;
  char  *p = NULL;

  if (!(source_p->user))
    {
      /* something is *f****d* - bail */
      return;
    }

  if(ConfigChannel.use_vchans == 0)
  {
    sendto_one(source_p, form_str(source_p,ERR_VCHANDISABLED),
               me.name, parv[0]);
    return;
  }
  
  if (ConfigChannel.vchans_oper_only && !IsOper(source_p))
  {
    sendto_one(source_p, form_str(source_p,ERR_NOPRIVILEGES),
               me.name, parv[0]);
    return;
  }

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


  /* Ok, only allowed to CJOIN already existing channels
   * so first part simply verifies the "root" channel exists first
   */

  *jbuf = '\0';

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

  if (!check_channel_name(name))
    {
      sendto_one(source_p, form_str(source_p,ERR_BADCHANNAME),
		 me.name, parv[0], (unsigned char*) name);
      return;
    }

  if (*name == '&')
    {
      sendto_one(source_p, form_str(source_p,ERR_BADCHANNAME),
		 me.name, parv[0], (unsigned char*) name);
      return;
    }

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

  strlcpy(jbuf, name, sizeof(jbuf));

  if ((chptr = hash_find_channel(name)) == NULL)
    {
      /* if chptr isn't found locally, it =could= exist
       * on the uplink. So ask.
       */
      if ( !ServerInfo.hub && uplink &&
           IsCapable(uplink, CAP_LL))
        {
          /* cache the channel if it exists on uplink
           * If the channel as seen by the uplink, has vchans,
           * the uplink will have to SJOIN all of those.
           */
          sendto_one(uplink, ":%s CBURST %s !%s",
                     me.name, parv[1], source_p->name);

          return;
        }
      else
        {
          sendto_one(source_p, form_str(source_p,ERR_NOSUCHCHANNEL),
                     me.name, source_p->name, name);
        }
      return;
    }

  if (! (vchan_chptr = cjoin_channel(chptr, source_p, name)) )
    return;

  root_vchan = chptr;
  chptr = vchan_chptr;
  
  /*
  **  Complete user entry to the new channel
  */
  add_user_to_channel(chptr, source_p, CHFL_CHANOP);

  sendto_channel_local(ALL_MEMBERS, chptr,
			":%s!%s@%s JOIN :%s",
			source_p->name,
			source_p->username,
			source_p->host,
			root_vchan->chname);

  sendto_server(client_p, NULL, chptr, NOCAPS, NOCAPS, NOFLAGS,
                ":%s SJOIN %lu %s + :@%s",
                me.name,
                (unsigned long) chptr->channelts,
                chptr->chname,
                source_p->name);

  vchan_chptr->mode.mode |= MODE_TOPICLIMIT;
  vchan_chptr->mode.mode |= MODE_NOPRIVMSGS;

  sendto_channel_local(ALL_MEMBERS,chptr,
			":%s MODE %s +nt",
			me.name,
			root_vchan->chname);

  sendto_server(source_p, NULL, vchan_chptr, NOCAPS, NOCAPS, NOFLAGS,
                ":%s MODE %s +nt",
                me.name,
                vchan_chptr->chname);

  del_invite(vchan_chptr, source_p);
  channel_member_names(source_p, vchan_chptr, root_vchan->chname, 1);
}