unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

channel.c (36177B)

      1 /* Unreal Internet Relay Chat Daemon, src/channel.c
      2  * (C) Copyright 1990 Jarkko Oikarinen and
      3  *                    University of Oulu, Co Center
      4  * (C) Copyright 1999-present The UnrealIRCd team
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation; either version 1, or (at your option)
      9  * any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License
     17  * along with this program; if not, write to the Free Software
     18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  */
     20 
     21 /** @file
     22  * @brief Various important (common) channel functions.
     23  */
     24 
     25 #include "unrealircd.h"
     26 
     27 /** Lazy way to signal an OperOverride MODE */
     28 long opermode = 0;
     29 /** Lazy way to signal an SAJOIN MODE */
     30 long sajoinmode = 0;
     31 /** List of all channels on the server.
     32  * @ingroup ListFunctions
     33  * @section channels_example Example
     34  * This code will list all channels on the network.
     35  * @code
     36  * sendnotice(client, "List of all channels:");
     37  * for (channel = channels; channel; channel=channel->nextch)
     38  *     sendnotice(client, "Channel %s", channel->name);
     39  * @endcode
     40  */
     41 Channel *channels = NULL;
     42 
     43 static mp_pool_t *channel_pool = NULL;
     44 
     45 /** This describes the letters, modes and options for core channel modes.
     46  * These are +ntmispklr and also the list modes +vhoaq and +beI.
     47  */
     48 CoreChannelModeTable corechannelmodetable[] = {
     49 	{MODE_BAN, 'b', 1, 1},
     50 	{MODE_EXCEPT, 'e', 1, 1},	/* exception ban */
     51 	{MODE_INVEX, 'I', 1, 1},	/* invite-only exception */
     52 	{0x0, 0x0, 0x0, 0x0}
     53 };
     54 
     55 /** The advertised supported channel modes in the 004 numeric */
     56 char cmodestring[512];
     57 
     58 /** Returns 1 if the IRCOp can override or is a remote connection */
     59 inline int op_can_override(const char *acl, Client *client, Channel *channel, void* extra)
     60 {
     61 #ifndef NO_OPEROVERRIDE
     62 	if (MyUser(client) && !(ValidatePermissionsForPath(acl,client,NULL,channel,extra)))
     63 		return 0;
     64 	return 1;
     65 #else
     66 	return 0;
     67 #endif
     68 }
     69 
     70 /** Returns 1 if a half-op can set this channel mode */
     71 int Halfop_mode(long mode)
     72 {
     73 	CoreChannelModeTable *tab = &corechannelmodetable[0];
     74 
     75 	while (tab->mode != 0x0)
     76 	{
     77 		if (tab->mode == mode)
     78 			return (tab->halfop == 1 ? TRUE : FALSE);
     79 		tab++;
     80 	}
     81 	return TRUE;
     82 }
     83 
     84 /** Find client in a Member linked list (eg: channel->members) */
     85 Member *find_member_link(Member *lp, Client *ptr)
     86 {
     87 	if (ptr)
     88 	{
     89 		while (lp)
     90 		{
     91 			if (lp->client == ptr)
     92 				return (lp);
     93 			lp = lp->next;
     94 		}
     95 	}
     96 	return NULL;
     97 }
     98 
     99 /** Find channel in a Membership linked list (eg: client->user->channel) */
    100 Membership *find_membership_link(Membership *lp, Channel *ptr)
    101 {
    102 	if (ptr)
    103 		while (lp)
    104 		{
    105 			if (lp->channel == ptr)
    106 				return (lp);
    107 			lp = lp->next;
    108 		}
    109 	return NULL;
    110 }
    111 
    112 /** Allocate and return an empty Member struct */
    113 static Member *make_member(void)
    114 {
    115 	Member *lp;
    116 	unsigned int	i;
    117 
    118 	if (freemember == NULL)
    119 	{
    120 		for (i = 1; i <= (4072/sizeof(Member)); ++i)
    121 		{
    122 			lp = safe_alloc(sizeof(Member));
    123 			lp->next = freemember;
    124 			freemember = lp;
    125 		}
    126 	}
    127 	lp = freemember;
    128 	freemember = freemember->next;
    129 	lp->next = NULL;
    130 	return lp;
    131 }
    132 
    133 /** Free a Member struct */
    134 static void free_member(Member *lp)
    135 {
    136 	if (!lp)
    137 		return;
    138 	moddata_free_member(lp);
    139 	memset(lp, 0, sizeof(Member));
    140 	lp->next = freemember;
    141 	freemember = lp;
    142 }
    143 
    144 /** Allocate and return an empty Membership struct */
    145 static Membership *make_membership(void)
    146 {
    147 	Membership *m = NULL;
    148 	unsigned int	i;
    149 
    150 	if (freemembership == NULL)
    151 	{
    152 		for (i = 1; i <= (4072/sizeof(Membership)); i++)
    153 		{
    154 			m = safe_alloc(sizeof(Membership));
    155 			m->next = freemembership;
    156 			freemembership = m;
    157 		}
    158 		m = freemembership;
    159 		freemembership = m->next;
    160 	}
    161 	else
    162 	{
    163 		m = freemembership;
    164 		freemembership = freemembership->next;
    165 	}
    166 	memset(m, 0, sizeof(Membership));
    167 	return m;
    168 }
    169 
    170 /** Free a Membership struct */
    171 static void free_membership(Membership *m)
    172 {
    173 	if (m)
    174 	{
    175 		moddata_free_membership(m);
    176 		memset(m, 0, sizeof(Membership));
    177 		m->next = freemembership;
    178 		freemembership = m;
    179 	}
    180 }
    181 
    182 /** Find a client by nickname, hunt for older nick names if not found.
    183  * This can be handy, for example for /KILL nick, if 'nick' keeps
    184  * nick-changing and you are slow with typing.
    185  * @param client	The requestor
    186  * @param user		The nick name (or server name)
    187  * @param chasing	This will be set to 1 if the client was found
    188  *			only after searching through the nick history.
    189  * @returns The client (if found) or NULL (if not found).
    190  */
    191 Client *find_chasing(Client *client, const char *user, int *chasing)
    192 {
    193 	Client *who = find_client(user, NULL);
    194 
    195 	if (chasing)
    196 		*chasing = 0;
    197 	if (who)
    198 	{
    199 		if (!IsServer(who))
    200 			return who;
    201 		else
    202 			return NULL;
    203 	}
    204 	if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
    205 	{
    206 		sendnumeric(client, ERR_NOSUCHNICK, user);
    207 		return NULL;
    208 	}
    209 	if (chasing)
    210 		*chasing = 1;
    211 	if (!IsServer(who))
    212 		return who;
    213 	else return NULL;
    214 }
    215 
    216 /** Return 1 if the bans are identical, taking into account special handling for extbans */
    217 int identical_ban(const char *one, const char *two)
    218 {
    219 #if 0
    220 	if (is_extended_ban(one) && is_extended_ban(two))
    221 	{
    222 		/* compare the first 3 characters case-sensitive and if identical then compare
    223 		 * the remainder of the string case-insensitive.
    224 		 */
    225 		if (!strncmp(one, two, 3) && !strcasecmp(one+3, two+3))
    226 			return 1;
    227 	} else {
    228 		if (!mycmp(one, two))
    229 			return 1;
    230 	}
    231 #else
    232 	/* Actually I think we can live with this nowadays.
    233 	 * We are pushing towards named extbans, and all the
    234 	 * letter extbans that could clash no longer exist.
    235 	 */
    236 	if (!mycmp(one, two))
    237 		return 1;
    238 #endif
    239 	return 0;
    240 }
    241 
    242 /** Add a listmode (+beI) with the specified banid to
    243  *  the specified channel. (Extended version with
    244  *  set by nick and set on timestamp)
    245  */
    246 int add_listmode_ex(Ban **list, Client *client, Channel *channel, const char *banid, const char *setby, time_t seton)
    247 {
    248 	Ban *ban;
    249 	int cnt = 0, len;
    250 	int do_not_add = 0;
    251 
    252 	//if (MyUser(client))
    253 	//	collapse(banid);
    254 
    255 	len = strlen(banid);
    256 	if (!*list && ((len > MAXBANLENGTH) || (MAXBANS < 1)))
    257 	{
    258 		if (MyUser(client))
    259 		{
    260 			/* Only send the error to local clients */
    261 			sendnumeric(client, ERR_BANLISTFULL, channel->name, banid);
    262 		}
    263 		do_not_add = 1;
    264 	}
    265 	for (ban = *list; ban; ban = ban->next)
    266 	{
    267 		len += strlen(ban->banstr);
    268 		/* Check MAXBANLENGTH / MAXBANS only for local clients
    269 		 * and 'me' (for +b's set during +f).
    270 		 */
    271 		if ((MyUser(client) || IsMe(client)) && ((len > MAXBANLENGTH) || (++cnt >= MAXBANS)))
    272 		{
    273 			do_not_add = 1;
    274 		}
    275 		if (identical_ban(ban->banstr, banid))
    276 			break; /* update existing ban (potentially) */
    277 	}
    278 
    279 	/* Create a new ban if needed */
    280 	if (!ban)
    281 	{
    282 		if (do_not_add)
    283 		{
    284 			/* The banlist is full and trying to add a new ban.
    285 			 * This is not permitted.
    286 			 */
    287 			if (MyUser(client))
    288 			{
    289 				/* Only send the error to local clients */
    290 				sendnumeric(client, ERR_BANLISTFULL, channel->name, banid);
    291 			}
    292 			return -1;
    293 		}
    294 		ban = make_ban();
    295 		ban->next = *list;
    296 		*list = ban;
    297 	}
    298 
    299 	if ((ban->when > 0) && (seton >= ban->when))
    300 	{
    301 		/* Trying to add the same ban while an older version
    302 		 * or identical version of the ban already exists.
    303 		 */
    304 		return -1;
    305 	}
    306 
    307 	/* Update/set if this ban is new or older than existing one */
    308 	safe_strdup(ban->banstr, banid); /* cAsE may differ, use oldest version of it */
    309 	safe_strdup(ban->who, setby);
    310 	ban->when = seton;
    311 	return 0;
    312 }
    313 
    314 /** Add a listmode (+beI) with the specified banid to
    315  *  the specified channel. (Simplified version)
    316  */
    317 int add_listmode(Ban **list, Client *client, Channel *channel, const char *banid)
    318 {
    319 	char *setby = client->name;
    320 	char nuhbuf[NICKLEN+USERLEN+HOSTLEN+4];
    321 
    322 	if (IsUser(client) && (iConf.ban_setter == SETTER_NICK_USER_HOST))
    323 		setby = make_nick_user_host_r(nuhbuf, sizeof(nuhbuf), client->name, client->user->username, GetHost(client));
    324 
    325 	return add_listmode_ex(list, client, channel, banid, setby, TStime());
    326 }
    327 
    328 /** Delete a listmode (+beI) from a channel that matches the specified banid.
    329  */
    330 int del_listmode(Ban **list, Channel *channel, const char *banid)
    331 {
    332 	Ban **ban;
    333 	Ban *tmp;
    334 
    335 	if (!banid)
    336 		return -1;
    337 	for (ban = list; *ban; ban = &((*ban)->next))
    338 	{
    339 		if (identical_ban(banid, (*ban)->banstr))
    340 		{
    341 			tmp = *ban;
    342 			*ban = tmp->next;
    343 			safe_free(tmp->banstr);
    344 			safe_free(tmp->who);
    345 			free_ban(tmp);
    346 			return 0;
    347 		}
    348 	}
    349 	return -1;
    350 }
    351 
    352 /** is_banned - Check if a user is banned on a channel.
    353  * @param client   Client to check (can be remote client)
    354  * @param channel  Channel to check
    355  * @param type   Type of ban to check for (BANCHK_*)
    356  * @param msg    Message, only for some BANCHK_* types, otherwise NULL
    357  * @param errmsg Error message returned, could be NULL (which does not
    358  *               indicate absence of an error).
    359  * @returns      A pointer to the ban struct if banned, otherwise NULL.
    360  * @comments     Simple wrapper for is_banned_with_nick()
    361  */
    362 inline Ban *is_banned(Client *client, Channel *channel, int type, const char **msg, const char **errmsg)
    363 {
    364 	return is_banned_with_nick(client, channel, type, NULL, msg, errmsg);
    365 }
    366 
    367 /** ban_check_mask - Checks if the user matches the specified n!u@h mask -or- run an extended ban.
    368  * This is basically extracting the mask and extban check from is_banned_with_nick,
    369  * but with being a bit more strict in what an extban is.
    370  * Strange things could happen if this is called outside standard ban checking.
    371  * @param b	Ban context, see BanContext
    372  * @returns	Nonzero if the mask/extban succeeds. Zero if it doesn't.
    373  */
    374 inline int ban_check_mask(BanContext *b)
    375 {
    376 	if (!b->no_extbans && is_extended_ban(b->banstr))
    377 	{
    378 		/* Is an extended ban. */
    379 		const char *nextbanstr;
    380 		Extban *extban = findmod_by_bantype(b->banstr, &nextbanstr);
    381 		if (!extban || !(extban->is_banned_events & b->ban_check_types))
    382 		{
    383 			return 0;
    384 		} else {
    385 			b->banstr = nextbanstr;
    386 			return extban->is_banned(b);
    387 		}
    388 	}
    389 	else
    390 	{
    391 		/* Is a n!u@h mask. */
    392 		return match_user(b->banstr, b->client, MATCH_CHECK_ALL);
    393 	}
    394 }
    395 
    396 /** is_banned_with_nick - Check if a user is banned on a channel.
    397  * @param client   Client to check (can be remote client)
    398  * @param channel  Channel to check
    399  * @param type   Type of ban to check for (BANCHK_*)
    400  * @param nick   Nick of the user (or NULL, to default to client->name)
    401  * @param msg    Message, only for some BANCHK_* types, otherwise NULL
    402  * @returns      A pointer to the ban struct if banned, otherwise NULL.
    403  */
    404 Ban *is_banned_with_nick(Client *client, Channel *channel, int type, const char *nick, const char **msg, const char **errmsg)
    405 {
    406 	Ban *ban, *ex;
    407 	char savednick[NICKLEN+1];
    408 	BanContext *b = safe_alloc(sizeof(BanContext));
    409 
    410 	/* It's not really doable to pass 'nick' to all the ban layers,
    411 	 * including extbans (with stacking) and so on. Or at least not
    412 	 * without breaking several module API's.
    413 	 * So, instead, we temporarily set 'client->name' to 'nick' and
    414 	 * restore it to the orginal value at the end of this function.
    415 	 * This is possible because all these layers never send a message
    416 	 * to 'client' and only indicate success/failure.
    417 	 * Note that all this ONLY happens if is_banned_with_nick() is called
    418 	 * with a non-NULL nick. That doesn't happen much. In UnrealIRCd
    419 	 * only in case of '/NICK newnick'. This fixes #5165.
    420 	 */
    421 	if (nick)
    422 	{
    423 		strlcpy(savednick, client->name, sizeof(savednick));
    424 		strlcpy(client->name, nick, sizeof(client->name));
    425 	}
    426 
    427 	b->client = client;
    428 	b->channel = channel;
    429 	b->ban_check_types = type;
    430 	if (msg)
    431 		b->msg = *msg;
    432 
    433 	/* We check +b first, if a +b is found we then see if there is a +e.
    434 	 * If a +e was found we return NULL, if not, we return the ban.
    435 	 */
    436 
    437 	for (ban = channel->banlist; ban; ban = ban->next)
    438 	{
    439 		b->banstr = ban->banstr;
    440 		if (ban_check_mask(b))
    441 			break;
    442 	}
    443 
    444 	if (ban)
    445 	{
    446 		/* Ban found, now check for +e */
    447 		for (ex = channel->exlist; ex; ex = ex->next)
    448 		{
    449 			b->banstr = ex->banstr;
    450 			if (ban_check_mask(b))
    451 			{
    452 				/* except matched */
    453 				ban = NULL;
    454 				break;
    455 			}
    456 		}
    457 		/* user is not on except, 'ban' stays non-NULL. */
    458 	}
    459 
    460 	if (nick)
    461 	{
    462 		/* Restore the nick */
    463 		strlcpy(client->name, savednick, sizeof(client->name));
    464 	}
    465 
    466 	/* OUT: */
    467 	if (msg)
    468 		*msg = b->msg;
    469 	if (errmsg)
    470 		*errmsg = b->error_msg;
    471 
    472 	safe_free(b);
    473 	return ban;
    474 }
    475 
    476 /** Checks if a ban already exists */
    477 int ban_exists(Ban *lst, const char *str)
    478 {
    479 	for (; lst; lst = lst->next)
    480 		if (!mycmp(lst->banstr, str))
    481 			return 1;
    482 	return 0;
    483 }
    484 
    485 /** Checks if a ban already exists - special version.
    486  * This ignores the "~time:xx:" suffixes in the banlist.
    487  * So it will return 1 if a ban is there for ~time:5:blah!*@*
    488  * and you call ban_exists_ignore_time(channel->banlist, "blah!*@*")
    489  */
    490 int ban_exists_ignore_time(Ban *lst, const char *str)
    491 {
    492 	const char *p;
    493 
    494 	for (; lst; lst = lst->next)
    495 	{
    496 		if (!strncmp(lst->banstr, "~time:", 6))
    497 		{
    498 			/* Special treatment for ~time:xx: */
    499 			p = strchr(lst->banstr+6, ':');
    500 			if (p)
    501 			{
    502 				p++;
    503 				if (!mycmp(p, str))
    504 					return 1;
    505 			}
    506 		} else
    507 		{
    508 			/* The simple version */
    509 			if (!mycmp(lst->banstr, str))
    510 				return 1;
    511 		}
    512 	}
    513 	return 0;
    514 }
    515 
    516 /** Add user to the channel.
    517  * This adds both the Member struct to the channel->members linked list
    518  * and also the Membership struct to the client->user->channel linked list.
    519  * @note This does NOT send the JOIN, it only does the linked list stuff.
    520  */
    521 void add_user_to_channel(Channel *channel, Client *client, const char *modes)
    522 {
    523 	Member *m;
    524 	Membership *mb;
    525 	const char *p;
    526 
    527 	if (!client->user)
    528 		return;
    529 
    530 	m = make_member();
    531 	m->client = client;
    532 	m->next = channel->members;
    533 	channel->members = m;
    534 	channel->users++;
    535 
    536 	mb = make_membership();
    537 	mb->channel = channel;
    538 	mb->next = client->user->channel;
    539 	client->user->channel = mb;
    540 	client->user->joined++;
    541 
    542 	for (p = modes; *p; p++)
    543 		add_member_mode_fast(m, mb, *p);
    544 
    545 	RunHook(HOOKTYPE_JOIN_DATA, client, channel);
    546 }
    547 
    548 /** Remove the user from the channel.
    549  * This frees the memberships, decreases the user counts,
    550  * destroys the channel if needed, etc.
    551  * This does not send any PART/KICK/..!
    552  * @param client	The client that is removed from the channel
    553  * @param channel	The channel
    554  * @param dont_log	Set to 1 if it should not be logged as a part,
    555  *                      for example if you are already logging it as a kick.
    556  */
    557 int remove_user_from_channel(Client *client, Channel *channel, int dont_log)
    558 {
    559 	Member **m;
    560 	Member *m2;
    561 	Membership **mb;
    562 	Membership *mb2;
    563 
    564 	/* Update channel->members list */
    565 	for (m = &channel->members; (m2 = *m); m = &m2->next)
    566 	{
    567 		if (m2->client == client)
    568 		{
    569 			*m = m2->next;
    570 			free_member(m2);
    571 			break;
    572 		}
    573 	}
    574 
    575 	/* Update client->user->channel list */
    576 	for (mb = &client->user->channel; (mb2 = *mb); mb = &mb2->next)
    577 	{
    578 		if (mb2->channel == channel)
    579 		{
    580 			*mb = mb2->next;
    581 			free_membership(mb2);
    582 			break;
    583 		}
    584 	}
    585 
    586 	/* Update user record to reflect 1 less joined */
    587 	client->user->joined--;
    588 
    589 	if (!dont_log)
    590 	{
    591 		if (MyUser(client))
    592 		{
    593 			unreal_log(ULOG_INFO, "part", "LOCAL_CLIENT_PART", client,
    594 				   "User $client left $channel",
    595 				   log_data_channel("channel", channel));
    596 		} else {
    597 			unreal_log(ULOG_INFO, "part", "REMOTE_CLIENT_PART", client,
    598 				   "User $client left $channel",
    599 				   log_data_channel("channel", channel));
    600 		}
    601 	}
    602 
    603 	/* Now sub1_from_channel() will deal with the channel record
    604 	 * and destroy the channel if needed.
    605 	 */
    606 	return sub1_from_channel(channel);
    607 }
    608 
    609 /** Returns 1 if channel has this channel mode set and 0 if not */
    610 int has_channel_mode(Channel *channel, char mode)
    611 {
    612 	Cmode *cm;
    613 
    614 	for (cm=channelmodes; cm; cm = cm->next)
    615 		if ((cm->letter == mode) && (channel->mode.mode & cm->mode))
    616 			return 1;
    617 
    618 	return 0; /* Not found */
    619 }
    620 
    621 /** Returns 1 if channel has this mode is set and 0 if not */
    622 int has_channel_mode_raw(Cmode_t m, char mode)
    623 {
    624 	Cmode *cm;
    625 
    626 	for (cm=channelmodes; cm; cm = cm->next)
    627 		if ((cm->letter == mode) && (m & cm->mode))
    628 			return 1;
    629 
    630 	return 0; /* Not found */
    631 }
    632 
    633 /** Get the extended channel mode 'bit' value (eg: 0x20) by character (eg: 'Z') */
    634 Cmode_t get_extmode_bitbychar(char m)
    635 {
    636 	Cmode *cm;
    637 
    638 	for (cm=channelmodes; cm; cm = cm->next)
    639                 if (cm->letter == m)
    640                         return cm->mode;
    641 
    642         return 0;
    643 }
    644 
    645 /** Write the "simple" list of channel modes for channel channel onto buffer mbuf with the parameters in pbuf.
    646  * @param client		The client requesting the mode list (can be NULL)
    647  * @param mbuf			Modes will be stored here
    648  * @param pbuf			Mode parameters will be stored here
    649  * @param mbuf_size		Length of the mbuf buffer
    650  * @param pbuf_size		Length of the pbuf buffer
    651  * @param channel		The channel to fetch modes from
    652  * @param hide_local_modes	If set to 1 then we will hide local channel modes like Z and d
    653  *				(eg: if you intend to send the buffer to a remote server)
    654  */
    655 void channel_modes(Client *client, char *mbuf, char *pbuf, size_t mbuf_size, size_t pbuf_size, Channel *channel, int hide_local_modes)
    656 {
    657 	int show_mode_parameters = 0;
    658 	Cmode *cm;
    659 
    660 	if (!mbuf_size || !pbuf_size)
    661 		return;
    662 
    663 	if (!client || IsMember(client, channel) || IsServer(client) || IsMe(client) || IsULine(client) ||
    664 	    ValidatePermissionsForPath("channel:see:mode:remote",client,NULL,channel,NULL))
    665 	{
    666 		show_mode_parameters = 1;
    667 	}
    668 
    669 	*pbuf = '\0';
    670 	strlcpy(mbuf, "+", mbuf_size);
    671 
    672 	for (cm=channelmodes; cm; cm = cm->next)
    673 	{
    674 		if (cm->letter &&
    675 		    !(hide_local_modes && cm->local) &&
    676 		    (channel->mode.mode & cm->mode))
    677 		{
    678 			char flag = cm->letter;
    679 
    680 			if (mbuf_size)
    681 				strlcat_letter(mbuf, flag, mbuf_size);
    682 
    683 			if (cm->paracount && show_mode_parameters)
    684 			{
    685 				strlcat(pbuf, cm_getparameter(channel, flag), pbuf_size);
    686 				strlcat(pbuf, " ", pbuf_size);
    687 			}
    688 		}
    689 	}
    690 
    691 	/* Remove the trailing space from the parameters -- codemastr */
    692 	if (*pbuf)
    693 		pbuf[strlen(pbuf)-1]='\0';
    694 }
    695 
    696 /** Make a pretty mask from the input string - only used by SILENCE
    697  */
    698 char *pretty_mask(const char *mask_in)
    699 {
    700 	char mask[512];
    701 	char *cp, *user, *host;
    702 
    703 	strlcpy(mask, mask_in, sizeof(mask));
    704 
    705 	if ((user = strchr((cp = mask), '!')))
    706 		*user++ = '\0';
    707 
    708 	if ((host = strrchr(user ? user : cp, '@')))
    709 	{
    710 		*host++ = '\0';
    711 		if (!user)
    712 			return make_nick_user_host(NULL, cp, host);
    713 	}
    714 	else if (!user && strchr(cp, '.'))
    715 	{
    716 		return make_nick_user_host(NULL, NULL, cp);
    717 	}
    718 	return make_nick_user_host(cp, user, host);
    719 }
    720 
    721 /** Trim a string - rather than cutting it off sharply, this adds a * at the end.
    722  * So "toolong" becomes "toolon*"
    723  */
    724 char *trim_str(char *str, int len)
    725 {
    726 	int l;
    727 	if (!str)
    728 		return NULL;
    729 	if ((l = strlen(str)) > len)
    730 	{
    731 		str += l - len;
    732 		*str = '*';
    733 	}
    734 	return str;
    735 }
    736 
    737 /* Convert regular ban (non-extban) if needed.
    738  * This does things like:
    739  * nick!user@host -> nick!user@host (usually no change)
    740  * nickkkkkkkkkkkkkkkkkkkkkkkkkk!user@host -> nickkkkkkk*!user@host (dealing with NICKLEN restrictions and such).
    741  * user@host -> *!user@host
    742  * 1.2.3.4 -> *!*@1.2.3.4 (converting IP to a proper mask)
    743  * @param mask		Incoming mask (this will be touched/fragged!)
    744  * @param buf		Output buffer
    745  * @param buflen	Length of the output buffer, eg sizeof(buf)
    746  * @retval The sanitized mask, or NULL if it should be rejected fully.
    747  * @note Since 'mask' will be fragged, you most likely wish to pass a copy of it rather than the original.
    748  */
    749 const char *convert_regular_ban(char *mask, char *buf, size_t buflen)
    750 {
    751 	static char namebuf[USERLEN + HOSTLEN + 6];
    752 	char *user, *host;
    753 
    754 	if (!*mask)
    755 		return NULL; /* empty extban */
    756 
    757 	if (!buf)
    758 	{
    759 		buf = namebuf;
    760 		buflen = sizeof(namebuf);
    761 	}
    762 
    763 	if ((*mask == '~') && !strchr(mask, '@'))
    764 	{
    765 		/* has a '~', which makes it look like an extban,
    766 		 * but is not a user@host ban, too confusing.
    767 		 */
    768 		return NULL;
    769 	}
    770 
    771 	if ((user = strchr(mask, '!')))
    772 		*user++ = '\0';
    773 
    774 	if ((host = strrchr(user ? user : mask, '@')))
    775 	{
    776 		*host++ = '\0';
    777 		if (!user)
    778 			return make_nick_user_host_r(buf, buflen, NULL, trim_str(mask,USERLEN), trim_str(host,HOSTLEN));
    779 	}
    780 	else if (!user && (strchr(mask, '.') || strchr(mask, ':')))
    781 	{
    782 		/* 1.2.3.4 -> *!*@1.2.3.4 (and the same for IPv6) */
    783 		return make_nick_user_host_r(buf, buflen, NULL, NULL, trim_str(mask,HOSTLEN));
    784 	}
    785 
    786 	/* regular nick!user@host with the auto-trimming feature */
    787 	return make_nick_user_host_r(buf, buflen, trim_str(mask,NICKLEN), trim_str(user,USERLEN), trim_str(host,HOSTLEN));
    788 }
    789 
    790 /** Make a proper ban mask.
    791  * This takes user input (eg: "nick") and converts it to a mask suitable
    792  * in the +beI lists (eg: "nick!*@*"). It also deals with extended bans,
    793  * in which case it will call the extban->conv_param() function.
    794  * @param mask		The ban mask
    795  * @param what		MODE_DEL or MODE_ADD
    796  * @param client	The client adding/removing this ban mask
    797  * @param conv_options	Options for BanContext.conv_options (eg BCTX_CONV_OPTION_WRITE_LETTER_BANS)
    798  * @returns pointer to correct banmask or NULL in case of error
    799  * @note A pointer is returned to a static buffer, which is overwritten
    800  *       on next clean_ban_mask or make_nick_user_host call.
    801  */
    802 const char *clean_ban_mask(const char *mask_in, int what, Client *client, int conv_options)
    803 {
    804 	char *cp, *x;
    805 	static char mask[512];
    806 
    807 	/* Strip any ':' at beginning since that would cause a desync */
    808 	for (; (*mask_in && (*mask_in == ':')); mask_in++);
    809 	if (!*mask_in)
    810 		return NULL;
    811 
    812 	/* Work on a copy */
    813 	strlcpy(mask, mask_in, sizeof(mask));
    814 
    815 	cp = strchr(mask, ' ');
    816 	if (cp)
    817 		*cp = '\0';
    818 
    819 	/* Forbid ASCII <= 32 in all bans */
    820 	for (x = mask; *x; x++)
    821 		if (*x <= ' ')
    822 			return NULL;
    823 
    824 	/* Extended ban? */
    825 	if (is_extended_ban(mask))
    826 	{
    827 		const char *nextbanstr;
    828 		Extban *extban;
    829 
    830 		if (RESTRICT_EXTENDEDBANS && MyUser(client) && !ValidatePermissionsForPath("immune:restrict-extendedbans",client,NULL,NULL,NULL))
    831 		{
    832 			if (!strcmp(RESTRICT_EXTENDEDBANS, "*"))
    833 			{
    834 				sendnotice(client, "Setting/removing of extended bans has been disabled");
    835 				return NULL;
    836 			}
    837 			if (strchr(RESTRICT_EXTENDEDBANS, mask[1]))
    838 			{
    839 				sendnotice(client, "Setting/removing of extended bantypes '%s' has been disabled",
    840 					RESTRICT_EXTENDEDBANS);
    841 				return NULL;
    842 			}
    843 		}
    844 
    845 		extban = findmod_by_bantype(mask, &nextbanstr);
    846 		if (!extban)
    847 		{
    848 			/* extended bantype not supported, what to do?
    849 			 * Here are the rules:
    850 			 * - if from a remote client/server: allow it (easy upgrading,
    851 			 *   no desync)
    852 			 * - if from a local client trying to REMOVE the extban,
    853 			 *   allow it too (so you don't get "unremovable" extbans).
    854 			 */
    855 			if (!MyUser(client) || (what == MODE_DEL))
    856 				return mask; /* allow it */
    857 			return NULL; /* reject */
    858 		}
    859 
    860 		if (extban->conv_param)
    861 		{
    862 			const char *ret;
    863 			static char retbuf[512];
    864 			BanContext *b = safe_alloc(sizeof(BanContext));
    865 			b->client = client;
    866 			b->what = what;
    867 			b->banstr = nextbanstr;
    868 			b->conv_options = conv_options;
    869 			ret = extban->conv_param(b, extban);
    870 			ret = prefix_with_extban(ret, b, extban, retbuf, sizeof(retbuf));
    871 			safe_free(b);
    872 			return ret;
    873 		}
    874 		/* else, do some basic sanity checks and cut it off at 80 bytes */
    875 		if ((mask[1] != ':') || (mask[2] == '\0'))
    876 		    return NULL; /* require a ":<char>" after extban type */
    877 		if (strlen(mask) > 80)
    878 			mask[80] = '\0';
    879 		return mask;
    880 	}
    881 
    882 	return convert_regular_ban(mask, NULL, 0);
    883 }
    884 
    885 /** Check if 'client' matches an invite exception (+I) on 'channel' */
    886 int find_invex(Channel *channel, Client *client)
    887 {
    888 	Ban *inv;
    889 	BanContext *b = safe_alloc(sizeof(BanContext));
    890 
    891 	b->client = client;
    892 	b->channel = channel;
    893 	b->ban_check_types = BANCHK_JOIN;
    894 
    895 	for (inv = channel->invexlist; inv; inv = inv->next)
    896 	{
    897 		b->banstr = inv->banstr;
    898 		if (ban_check_mask(b))
    899 		{
    900 			safe_free(b);
    901 			return 1;
    902 		}
    903 	}
    904 
    905 	safe_free(b);
    906 	return 0;
    907 }
    908 
    909 /** Remove unwanted characters from channel name.
    910  * You must call this before creating a new channel,
    911  * eg in case of /JOIN.
    912  */
    913 int valid_channelname(const char *cname)
    914 {
    915 	const char *p;
    916 
    917 	/* Channel name must start with a dash */
    918 	if (*cname != '#')
    919 		return 0;
    920 
    921 	if (strlen(cname) > CHANNELLEN)
    922 		return 0;
    923 
    924 	if ((iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_ANY) || !iConf.allowed_channelchars)
    925 	{
    926 		/* The default up to and including UnrealIRCd 4 */
    927 		for (p = cname; *p; p++)
    928 		{
    929 			if (*p < 33 || *p == ',' || *p == ':')
    930 				return 0;
    931 		}
    932 	} else
    933 	if (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_ASCII)
    934 	{
    935 		/* The strict setting: only allow ASCII 32-128, except some chars */
    936 		for (p = cname; *p; p++)
    937 		{
    938 			if (*p < 33 || *p == ',' || *p == ':' || *p > 127)
    939 				return 0;
    940 		}
    941 	} else
    942 	if (iConf.allowed_channelchars == ALLOWED_CHANNELCHARS_UTF8)
    943 	{
    944 		/* Only allow UTF8, and also disallow some chars */
    945 		for (p = cname; *p; p++)
    946 		{
    947 			if (*p < 33 || *p == ',' || *p == ':')
    948 				return 0;
    949 		}
    950 		/* And run it through the UTF8 validator */
    951 		if (!unrl_utf8_validate(cname, (const char **)&p))
    952 			return 0;
    953 	} else
    954 	{
    955 		/* Impossible */
    956 		abort();
    957 	}
    958 	return 1; /* Valid */
    959 }
    960 
    961 void initlist_channels(void)
    962 {
    963 	channel_pool = mp_pool_new(sizeof(Channel), 512 * 1024);
    964 }
    965 
    966 /** Create channel 'name' (or if it exists, return the existing one)
    967  * @param name		Channel name
    968  * @param flag		If set to 'CREATE' then the channel is
    969  *			created if it does not exist.
    970  * @returns Pointer to channel (new or existing).
    971  * @note Be sure to call valid_channelname() first before
    972  *       you blindly call this function!
    973  */
    974 Channel *make_channel(const char *name)
    975 {
    976 	Channel *channel;
    977 	int len;
    978 	char *p;
    979 	char namebuf[CHANNELLEN+1];
    980 
    981 	if (BadPtr(name))
    982 		return NULL;
    983 
    984 	/* Copy and silently truncate */
    985 	strlcpy(namebuf, name, sizeof(namebuf));
    986 
    987 	/* Copied from valid_channelname(), the minimal requirements */
    988 	for (p = namebuf; *p; p++)
    989 	{
    990 		if (*p < 33 || *p == ',' || *p == ':')
    991 		{
    992 			*p = '\0';
    993 			break;
    994 		}
    995 	}
    996 
    997 	/* Exists? Return it. */
    998 	if ((channel = find_channel(name)))
    999 		return channel;
   1000 
   1001 	channel = mp_pool_get(channel_pool);
   1002 	memset(channel, 0, sizeof(Channel));
   1003 
   1004 	strlcpy(channel->name, name, sizeof(channel->name));
   1005 
   1006 	if (channels)
   1007 		channels->prevch = channel;
   1008 
   1009 	channel->topic = NULL;
   1010 	channel->topic_nick = NULL;
   1011 	channel->prevch = NULL;
   1012 	channel->nextch = channels;
   1013 	channel->creationtime = TStime();
   1014 	channels = channel;
   1015 	add_to_channel_hash_table(channel->name, channel);
   1016 	irccounts.channels++;
   1017 
   1018 	RunHook(HOOKTYPE_CHANNEL_CREATE, channel);
   1019 
   1020 	return channel;
   1021 }
   1022 
   1023 /** Is the user 'client' invited to channel 'channel' by a chanop?
   1024  * @param client	The client who was invited
   1025  * @param channel	The channel to which the person was invited
   1026  */
   1027 int is_invited(Client *client, Channel *channel)
   1028 {
   1029 	int invited = 0;
   1030 	RunHook(HOOKTYPE_IS_INVITED, client, channel, &invited);
   1031 	return invited;
   1032 }
   1033 
   1034 /** Subtract one user from channel i. Free the channel if it became empty.
   1035  * @param channel The channel
   1036  * @returns 1 if the channel was freed, 0 if the channel still exists.
   1037  */
   1038 int sub1_from_channel(Channel *channel)
   1039 {
   1040 	Ban *ban;
   1041 	Link *lp;
   1042 	int should_destroy = 1;
   1043 
   1044 	--channel->users;
   1045 	if (channel->users > 0)
   1046 		return 0;
   1047 
   1048 	/* No users in the channel anymore */
   1049 	channel->users = 0; /* to be sure */
   1050 
   1051 	/* If the channel is +P then this hook will actually stop destruction. */
   1052 	RunHook(HOOKTYPE_CHANNEL_DESTROY, channel, &should_destroy);
   1053 	if (!should_destroy)
   1054 		return 0;
   1055 
   1056 	/* We are now going to destroy the channel.
   1057 	 * But first we will destroy all kinds of references and lists...
   1058 	 */
   1059 
   1060 	moddata_free_channel(channel);
   1061 
   1062 	while (channel->banlist)
   1063 	{
   1064 		ban = channel->banlist;
   1065 		channel->banlist = ban->next;
   1066 		safe_free(ban->banstr);
   1067 		safe_free(ban->who);
   1068 		free_ban(ban);
   1069 	}
   1070 	while (channel->exlist)
   1071 	{
   1072 		ban = channel->exlist;
   1073 		channel->exlist = ban->next;
   1074 		safe_free(ban->banstr);
   1075 		safe_free(ban->who);
   1076 		free_ban(ban);
   1077 	}
   1078 	while (channel->invexlist)
   1079 	{
   1080 		ban = channel->invexlist;
   1081 		channel->invexlist = ban->next;
   1082 		safe_free(ban->banstr);
   1083 		safe_free(ban->who);
   1084 		free_ban(ban);
   1085 	}
   1086 
   1087 	/* free extcmode params */
   1088 	extcmode_free_paramlist(channel->mode.mode_params);
   1089 
   1090 	safe_free(channel->mode_lock);
   1091 	safe_free(channel->topic);
   1092 	safe_free(channel->topic_nick);
   1093 
   1094 	if (channel->prevch)
   1095 		channel->prevch->nextch = channel->nextch;
   1096 	else
   1097 		channels = channel->nextch;
   1098 
   1099 	if (channel->nextch)
   1100 		channel->nextch->prevch = channel->prevch;
   1101 	del_from_channel_hash_table(channel->name, channel);
   1102 
   1103 	irccounts.channels--;
   1104 	mp_pool_release(channel);
   1105 	return 1;
   1106 }
   1107 
   1108 /** Set channel mode lock on the channel, these are modes that users cannot change.
   1109  * @param client	The client or server issueing the MLOCK
   1110  * @param channel	The channel that will be MLOCK'ed
   1111  * @param newmlock	The MLOCK string: list of mode characters that are locked
   1112  */
   1113 void set_channel_mlock(Client *client, Channel *channel, const char *newmlock, int propagate)
   1114 {
   1115 	safe_strdup(channel->mode_lock, newmlock);
   1116 
   1117 	if (propagate)
   1118 	{
   1119 		sendto_server(client, 0, 0, NULL, ":%s MLOCK %lld %s :%s",
   1120 			      client->id, (long long)channel->creationtime, channel->name,
   1121 			      BadPtr(channel->mode_lock) ? "" : channel->mode_lock);
   1122 	}
   1123 }
   1124 
   1125 /** Parse a channelmode line.
   1126  * @in pm A ParseMode struct, used to return values and to maintain internal state.
   1127  * @in modebuf_in Buffer pointing to mode characters (eg: +snk-l)
   1128  * @in parabuf_in Buffer pointing to all parameters (eg: key 123)
   1129  * @retval Returns 1 if we have valid data to return, 0 if at end of mode line.
   1130  * @section parse_chanmode_example Example:
   1131  * @code
   1132  * ParseMode pm;
   1133  * int ret;
   1134  * for (ret = parse_chanmode(&pm, modebuf, parabuf); ret; ret = parse_chanmode(&pm, NULL, NULL))
   1135  * {
   1136  *         unreal_log(ULOG_INFO, "test", "TEST", "Got %c%c %s",
   1137  *                    pm.what == MODE_ADD ? '+' : '-',
   1138  *                    pm.modechar,
   1139  *                    pm.param ? pm.param : "");
   1140  * }
   1141  * @endcode
   1142  */
   1143 int parse_chanmode(ParseMode *pm, const char *modebuf_in, const char *parabuf_in)
   1144 {
   1145 	if (modebuf_in)
   1146 	{
   1147 		/* Initialize */
   1148 		memset(pm, 0, sizeof(ParseMode));
   1149 		pm->modebuf = modebuf_in;
   1150 		pm->parabuf = parabuf_in;
   1151 		pm->what = MODE_ADD;
   1152 	}
   1153 
   1154 	while(1)
   1155 	{
   1156 		if (*pm->modebuf == '\0')
   1157 			return 0;
   1158 		else if (*pm->modebuf == '+')
   1159 		{
   1160 			pm->what = MODE_ADD;
   1161 			pm->modebuf++;
   1162 			continue;
   1163 		}
   1164 		else if (*pm->modebuf == '-')
   1165 		{
   1166 			pm->what = MODE_DEL;
   1167 			pm->modebuf++;
   1168 			continue;
   1169 		}
   1170 		else
   1171 		{
   1172 			CoreChannelModeTable *tab = &corechannelmodetable[0];
   1173 			Cmode *cm;
   1174 			int eatparam = 0;
   1175 
   1176 			/* Set some defaults */
   1177 			pm->extm = NULL;
   1178 			pm->modechar = *pm->modebuf;
   1179 			pm->param = NULL;
   1180 
   1181 			while (tab->mode != 0x0)
   1182 			{
   1183 				if (tab->flag == *pm->modebuf)
   1184 					break;
   1185 				tab++;
   1186 			}
   1187 
   1188 			if (tab->mode)
   1189 			{
   1190 				/* INTERNAL MODE */
   1191 				if (tab->parameters)
   1192 				{
   1193 					eatparam = 1;
   1194 				}
   1195 			} else {
   1196 				/* EXTENDED CHANNEL MODE */
   1197 				int found = 0;
   1198 				for (cm=channelmodes; cm; cm = cm->next)
   1199 				{
   1200 					if (cm->letter == *pm->modebuf)
   1201 					{
   1202 						found = 1;
   1203 						break;
   1204 					}
   1205 				}
   1206 				if (!found)
   1207 				{
   1208 					/* Not found. Will be ignored, just move on.. */
   1209 					pm->modebuf++;
   1210 					continue;
   1211 				}
   1212 				pm->extm = cm;
   1213 				if (cm->paracount == 1)
   1214 				{
   1215 					if (pm->what == MODE_ADD)
   1216 						eatparam = 1;
   1217 					else if (cm->unset_with_param)
   1218 						eatparam = 1;
   1219 					/* else 0 (if MODE_DEL && !unset_with_param) */
   1220 				}
   1221 			}
   1222 
   1223 			if (eatparam)
   1224 			{
   1225 				/* Hungry.. */
   1226 				if (pm->parabuf && *pm->parabuf)
   1227 				{
   1228 					const char *start, *end;
   1229 					for (; *pm->parabuf == ' '; pm->parabuf++); /* skip whitespace */
   1230 					start = pm->parabuf;
   1231 					if (*pm->parabuf == '\0')
   1232 					{
   1233 						pm->modebuf++;
   1234 						continue; /* invalid, got mode but no parameter available */
   1235 					}
   1236 					end = strchr(start, ' ');
   1237 					/* copy start .. end (where end may be null, then just copy all) */
   1238 					if (end)
   1239 					{
   1240 						pm->parabuf = end + 1; /* point to next param, or \0 */
   1241 						if (end - start + 1 > sizeof(pm->buf))
   1242 							end = start + sizeof(pm->buf); /* 'never' reached */
   1243 						strlcpy(pm->buf, start, end - start + 1);
   1244 					}
   1245 					else
   1246 					{
   1247 						strlcpy(pm->buf, start, sizeof(pm->buf));
   1248 						pm->parabuf = pm->parabuf + strlen(pm->parabuf); /* point to \0 at end */
   1249 					}
   1250 					stripcrlf(pm->buf); /* needed for unreal_server_compat.c */
   1251 					pm->param = pm->buf;
   1252 				} else {
   1253 					pm->modebuf++;
   1254 					continue; /* invalid, got mode but no parameter available */
   1255 				}
   1256 			}
   1257 		}
   1258 		pm->modebuf++; /* advance pointer */
   1259 		return 1;
   1260 	}
   1261 }
   1262 
   1263 /** Returns 1 if both clients are at least in 1 same channel */
   1264 int has_common_channels(Client *c1, Client *c2)
   1265 {
   1266 	Membership *lp;
   1267 
   1268 	for (lp = c1->user->channel; lp; lp = lp->next)
   1269 	{
   1270 		if (IsMember(c2, lp->channel) && user_can_see_member(c1, c2, lp->channel))
   1271 			return 1;
   1272 	}
   1273 	return 0;
   1274 }
   1275 
   1276 /** Returns 1 if user 'user' can see channel member 'target'.
   1277  * This may return 0 if the user is 'invisible' due to mode +D rules.
   1278  * NOTE: Membership is unchecked, assumed membership of both.
   1279  */
   1280 int user_can_see_member(Client *user, Client *target, Channel *channel)
   1281 {
   1282 	Hook *h;
   1283 	int j = 0;
   1284 
   1285 	if (user == target)
   1286 		return 1;
   1287 
   1288 	for (h = Hooks[HOOKTYPE_VISIBLE_IN_CHANNEL]; h; h = h->next)
   1289 	{
   1290 		j = (*(h->func.intfunc))(target,channel);
   1291 		if (j != 0)
   1292 			break;
   1293 	}
   1294 
   1295 	/* We must ensure that user is allowed to "see" target */
   1296 	if (j != 0 && !(check_channel_access(target, channel, "hoaq") || check_channel_access(target,channel, "v")) && !check_channel_access(user, channel, "hoaq"))
   1297 		return 0;
   1298 
   1299 	return 1;
   1300 }
   1301 
   1302 /** Returns 1 if user 'target' is invisible in channel 'channel'.
   1303  * This may return 0 if the user is 'invisible' due to mode +D rules.
   1304  */
   1305 int invisible_user_in_channel(Client *target, Channel *channel)
   1306 {
   1307 	Hook *h;
   1308 	int j = 0;
   1309 
   1310 	for (h = Hooks[HOOKTYPE_VISIBLE_IN_CHANNEL]; h; h = h->next)
   1311 	{
   1312 		j = (*(h->func.intfunc))(target,channel);
   1313 		if (j != 0)
   1314 			break;
   1315 	}
   1316 
   1317 	/* We must ensure that user is allowed to "see" target */
   1318 	if (j != 0 && !(check_channel_access(target, channel, "hoaq") || check_channel_access(target,channel, "v")))
   1319 		return 1;
   1320 
   1321 	return 0;
   1322 }
   1323 
   1324 /** Send a message to the user that (s)he is using an invalid channel name.
   1325  * This is usually called after an if (MyUser(client) && !valid_channelname(name)).
   1326  * @param client      The client to send the message to.
   1327  * @param channelname The (invalid) channel that the user tried to join.
   1328  */
   1329 void send_invalid_channelname(Client *client, const char *channelname)
   1330 {
   1331 	const char *reason;
   1332 
   1333 	if (*channelname != '#')
   1334 	{
   1335 		reason = "Channel name must start with a hash mark (#)";
   1336 	} else
   1337 	if (strlen(channelname) > CHANNELLEN)
   1338 	{
   1339 		reason = "Channel name is too long";
   1340 	} else {
   1341 		switch(iConf.allowed_channelchars)
   1342 		{
   1343 			case ALLOWED_CHANNELCHARS_ASCII:
   1344 				reason = "Channel name contains illegal characters (must be ASCII)";
   1345 				break;
   1346 			case ALLOWED_CHANNELCHARS_UTF8:
   1347 				reason = "Channel name contains illegal characters (must be valid UTF8)";
   1348 				break;
   1349 			case ALLOWED_CHANNELCHARS_ANY:
   1350 			default:
   1351 				reason = "Channel name contains illegal characters";
   1352 		}
   1353 	}
   1354 
   1355 	sendnumeric(client, ERR_FORBIDDENCHANNEL, channelname, reason);
   1356 }
   1357 
   1358 /** Is the provided string possibly an extended ban?
   1359  * Note that it still may not exist, it just tests the first part.
   1360  * @param str	The string to check (eg "~account:xyz")
   1361  */
   1362 int is_extended_ban(const char *str)
   1363 {
   1364 	const char *p;
   1365 
   1366 	if (*str != '~')
   1367 		return 0;
   1368 	for (p = str+1; *p; p++)
   1369 	{
   1370 		if (!isalnum(*p))
   1371 		{
   1372 			if (*p == ':')
   1373 				return 1;
   1374 		}
   1375 	}
   1376 	return 0;
   1377 }
   1378 
   1379 /** Is the provided string possibly an extended server ban?
   1380  * Actually this is only a very light check.
   1381  * It may still not exist, it just tests the first part.
   1382  * @param str	The string to check (eg "~account:xyz")
   1383  * The only difference between this and is_extended_ban()
   1384  * is that we allow a % at the beginning for soft-bans.
   1385  * @see is_extended_ban()
   1386  */
   1387 int is_extended_server_ban(const char *str)
   1388 {
   1389 	if (*str == '%')
   1390 		str++;
   1391 	return is_extended_ban(str);
   1392 }
   1393 
   1394 /** Check if it is an empty (useless) mode, namely "", "+" or "-".
   1395  * Typically called as: empty_mode(modebuf)
   1396  */
   1397 int empty_mode(const char *m)
   1398 {
   1399 	if (!*m || (((m[0] == '+') || (m[0] == '-')) && m[1] == '\0'))
   1400 		return 1;
   1401 	return 0;
   1402 }
   1403 
   1404 /** Free everything of/in a MultiLineMode */
   1405 void free_multilinemode(MultiLineMode *m)
   1406 {
   1407 	int i;
   1408 	if (m == NULL)
   1409 		return;
   1410 	for (i=0; i < m->numlines; i++)
   1411 	{
   1412 		safe_free(m->modeline[i]);
   1413 		safe_free(m->paramline[i]);
   1414 	}
   1415 	safe_free(m);
   1416 }