unrealircd

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

invite.c (14199B)

      1 /*
      2  *   IRC - Internet Relay Chat, src/modules/invite.c
      3  *   (C) 2004 The UnrealIRCd Team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers.
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #include "unrealircd.h"
     24 
     25 #define MSG_INVITE 	"INVITE"
     26 
     27 #define CLIENT_INVITES(client)		(moddata_local_client(client, userInvitesMD).ptr)
     28 #define CHANNEL_INVITES(channel)	(moddata_channel(channel, channelInvitesMD).ptr)
     29 
     30 ModDataInfo *userInvitesMD;
     31 ModDataInfo *channelInvitesMD;
     32 long CAP_INVITE_NOTIFY = 0L;
     33 int invite_always_notify = 0;
     34 
     35 CMD_FUNC(cmd_invite);
     36 
     37 void invite_free(ModData *md);
     38 int invite_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
     39 int invite_config_run(ConfigFile *cf, ConfigEntry *ce, int type);
     40 void add_invite(Client *from, Client *to, Channel *channel, MessageTag *mtags);
     41 void del_invite(Client *client, Channel *channel);
     42 static int invite_channel_destroy(Channel *channel, int *should_destroy);
     43 int invite_user_quit(Client *client, MessageTag *mtags, const char *comment);
     44 int invite_user_join(Client *client, Channel *channel, MessageTag *mtags);
     45 int invite_is_invited(Client *client, Channel *channel, int *invited);
     46 
     47 ModuleHeader MOD_HEADER
     48   = {
     49 	"invite",
     50 	"5.0",
     51 	"command /invite", 
     52 	"UnrealIRCd Team",
     53 	"unrealircd-6",
     54     };
     55 
     56 MOD_TEST()
     57 {
     58 	HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, invite_config_test);
     59 	return MOD_SUCCESS;
     60 }
     61 
     62 MOD_INIT()
     63 {
     64 	ClientCapabilityInfo cap;
     65 	ClientCapability *c;
     66 	ModDataInfo mreq;
     67 
     68 	MARK_AS_OFFICIAL_MODULE(modinfo);
     69 
     70 	CommandAdd(modinfo->handle, MSG_INVITE, cmd_invite, MAXPARA, CMD_USER|CMD_SERVER);	
     71 
     72 	memset(&cap, 0, sizeof(cap));
     73 	cap.name = "invite-notify";
     74 	c = ClientCapabilityAdd(modinfo->handle, &cap, &CAP_INVITE_NOTIFY);
     75 	if (!c)
     76 	{
     77 		config_error("[%s] Failed to request invite-notify cap: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
     78 		return MOD_FAILED;
     79 	}
     80 
     81 	memset(&mreq, 0 , sizeof(mreq));
     82 	mreq.type = MODDATATYPE_LOCAL_CLIENT;
     83 	mreq.name = "invite",
     84 	mreq.free = invite_free;
     85 	userInvitesMD = ModDataAdd(modinfo->handle, mreq);
     86 	if (!userInvitesMD)
     87 	{
     88 		config_error("[%s] Failed to request user invite moddata: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
     89 		return MOD_FAILED;
     90 	}
     91 	
     92 	memset(&mreq, 0 , sizeof(mreq));
     93 	mreq.type = MODDATATYPE_CHANNEL;
     94 	mreq.name = "invite",
     95 	mreq.free = invite_free;
     96 	channelInvitesMD = ModDataAdd(modinfo->handle, mreq);
     97 	if (!channelInvitesMD)
     98 	{
     99 		config_error("[%s] Failed to request channel invite moddata: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
    100 		return MOD_FAILED;
    101 	}
    102 
    103 	invite_always_notify = 0; /* the default */
    104 	HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, invite_config_run);
    105 	HookAdd(modinfo->handle, HOOKTYPE_CHANNEL_DESTROY, 1000000, invite_channel_destroy);
    106 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_QUIT, 0, invite_user_quit);
    107 	HookAdd(modinfo->handle, HOOKTYPE_LOCAL_JOIN, 0, invite_user_join);
    108 	HookAdd(modinfo->handle, HOOKTYPE_IS_INVITED, 0, invite_is_invited);
    109 	
    110 	return MOD_SUCCESS;
    111 }
    112 
    113 MOD_LOAD()
    114 {
    115 	return MOD_SUCCESS;
    116 }
    117 
    118 MOD_UNLOAD()
    119 {
    120 	return MOD_SUCCESS;
    121 }
    122 
    123 void invite_free(ModData *md)
    124 {
    125 	Link **inv, *tmp;
    126 
    127 	if (!md->ptr)
    128 		return; // was not set
    129 
    130 	for (inv = (Link **)md->ptr; (tmp = *inv); inv = &tmp->next)
    131 	{
    132 		*inv = tmp->next;
    133 		free_link(tmp);
    134 	}
    135 }
    136 
    137 int invite_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
    138 {
    139 	int errors = 0;
    140 
    141 	if (type != CONFIG_SET)
    142 		return 0;
    143 
    144 	if (!ce || !ce->name || strcmp(ce->name, "normal-user-invite-notification"))
    145 		return 0;
    146 
    147 	if (!ce->value)
    148 	{
    149 		config_error_empty(ce->file->filename, ce->line_number, "set", ce->name);
    150 		errors++;
    151 	}
    152 
    153 	*errs = errors;
    154 	return errors ? -1 : 1;
    155 }
    156 
    157 int invite_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
    158 {
    159 	ConfigEntry *cep;
    160 
    161 	if (type != CONFIG_SET)
    162 		return 0;
    163 
    164 	if (!ce || !ce->name || strcmp(ce->name, "normal-user-invite-notification"))
    165 		return 0;
    166 
    167 	invite_always_notify = config_checkval(ce->value, CFG_YESNO);
    168 
    169 	return 1;
    170 }
    171 
    172 static int invite_channel_destroy(Channel *channel, int *should_destroy)
    173 {
    174 	Link *lp;
    175 	while ((lp = CHANNEL_INVITES(channel)))
    176 		del_invite(lp->value.client, channel);
    177 	return 0;
    178 }
    179 
    180 int invite_user_quit(Client *client, MessageTag *mtags, const char *comment)
    181 {
    182 	Link *lp;
    183 	/* Clean up invitefield */
    184 	while ((lp = CLIENT_INVITES(client)))
    185 		del_invite(client, lp->value.channel);
    186 	return 0;
    187 }
    188 
    189 int invite_user_join(Client *client, Channel *channel, MessageTag *mtags)
    190 {
    191 	del_invite(client, channel);
    192 	return 0;
    193 }
    194 
    195 /* Send the user their list of active invites */
    196 void send_invite_list(Client *client)
    197 {
    198 	Link *inv;
    199 
    200 	for (inv = CLIENT_INVITES(client); inv; inv = inv->next)
    201 	{
    202 		sendnumeric(client, RPL_INVITELIST,
    203 			   inv->value.channel->name);	
    204 	}
    205 	sendnumeric(client, RPL_ENDOFINVITELIST);
    206 }
    207 
    208 int invite_is_invited(Client *client, Channel *channel, int *invited)
    209 {
    210 	Link *lp;
    211 	
    212 	if (!MyConnect(client))
    213 		return 0; // not handling invite lists for remote clients
    214 
    215 	for (lp = CLIENT_INVITES(client); lp; lp = lp->next)
    216 		if (lp->value.channel == channel)
    217 		{
    218 			*invited = 1;
    219 			return 0;
    220 		}
    221 	return 0;
    222 }
    223 
    224 void invite_process(Client *client, Client *target, Channel *channel, MessageTag *recv_mtags, int override)
    225 {
    226 	MessageTag *mtags = NULL;
    227 
    228 	new_message(client, recv_mtags, &mtags);
    229 
    230 	/* broadcast to other servers */
    231 	sendto_server(client, 0, 0, mtags, ":%s INVITE %s %s %d", client->id, target->id, channel->name, override);
    232 
    233 	/* send chanops notifications */
    234 	if (IsUser(client) && (check_channel_access(client, channel, "oaq")
    235 	    || IsULine(client)
    236 	    || ValidatePermissionsForPath("channel:override:invite:self",client,NULL,channel,NULL)
    237 	    || invite_always_notify
    238 	    ))
    239 	{
    240 		if (override == 1)
    241 		{
    242 			sendto_channel(channel, &me, NULL, "o",
    243 				0, SEND_LOCAL, mtags,
    244 				":%s NOTICE @%s :OperOverride -- %s invited him/herself into the channel.",
    245 				me.name, channel->name, client->name);
    246 		}
    247 		if (override == 0)
    248 		{
    249 			sendto_channel(channel, &me, NULL, "o",
    250 				CAP_INVITE_NOTIFY | CAP_INVERT, SEND_LOCAL, mtags,
    251 				":%s NOTICE @%s :%s invited %s into the channel.",
    252 				me.name, channel->name, client->name, target->name);
    253 		}
    254 		/* always send IRCv3 invite-notify if possible */
    255 		sendto_channel(channel, client, NULL, "o",
    256 			CAP_INVITE_NOTIFY, SEND_LOCAL, mtags,
    257 			":%s INVITE %s %s",
    258 			client->name, target->name, channel->name);
    259 	}
    260 
    261 	/* add to list and notify the person who got invited */
    262 	if (MyConnect(target))
    263 	{
    264 		if (IsUser(client) && (check_channel_access(client, channel, "oaq")
    265 			|| IsULine(client)
    266 			|| ValidatePermissionsForPath("channel:override:invite:self",client,NULL,channel,NULL)
    267 			))
    268 		{
    269 			add_invite(client, target, channel, mtags);
    270 		}
    271 
    272 		if (!is_silenced(client, target))
    273 		{
    274 			sendto_prefix_one(target, client, mtags, ":%s INVITE %s :%s", client->name,
    275 				target->name, channel->name);
    276 		}
    277 	}
    278 	free_message_tags(mtags);
    279 }
    280 
    281 void invite_operoverride_msg(Client *client, Channel *channel, char *override_mode, char *override_mode_text)
    282 {
    283 	unreal_log(ULOG_INFO, "operoverride", "OPEROVERRIDE_INVITE", client,
    284 		   "OperOverride: $client.details invited him/herself into $channel (Overriding $override_mode_text)",
    285 		   log_data_string("override_type", "join"),
    286 		   log_data_string("override_mode", override_mode),
    287 		   log_data_string("override_mode_text", override_mode_text),
    288 		   log_data_channel("channel", channel));
    289 }
    290 
    291 /*
    292 ** cmd_invite
    293 **	parv[1] - user to invite
    294 **	parv[2] - channel name
    295 **  parv[3] - override (S2S only)
    296 */
    297 CMD_FUNC(cmd_invite)
    298 {
    299 	Client *target = NULL;
    300 	Channel *channel = NULL;
    301 	int override = 0;
    302 	int i = 0;
    303 	int params_ok = 0;
    304 	Hook *h;
    305 
    306 	if (parc >= 3 && *parv[1] != '\0')
    307 	{
    308 		params_ok = 1;
    309 		target = find_user(parv[1], NULL);
    310 		channel = find_channel(parv[2]);
    311 	}
    312 	
    313 	if (!MyConnect(client))
    314 	/*** remote invite ***/
    315 	{
    316 		if (!params_ok)
    317 			return;
    318 		/* the client or channel may be already gone */
    319 		if (!target)
    320 		{
    321 			sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
    322 			return;
    323 		}
    324 		if (!channel)
    325 		{
    326 			sendnumeric(client, ERR_NOSUCHCHANNEL, parv[2]);
    327 			return;
    328 		}
    329 		if (parc >= 4 && !BadPtr(parv[3]))
    330 		{
    331 			override = atoi(parv[3]);
    332 		}
    333 
    334 		/* no further checks */
    335 
    336 		invite_process(client, target, channel, recv_mtags, override);
    337 		return;
    338 	}
    339 
    340 	/*** local invite ***/
    341 
    342 	/* the client requested own invite list */
    343 	if (parc == 1)
    344 	{
    345 		send_invite_list(client);
    346 		return;
    347 	}
    348 
    349 	/* notify user about bad parameters */
    350 	if (!params_ok)
    351 	{
    352 		sendnumeric(client, ERR_NEEDMOREPARAMS, "INVITE");
    353 		return;
    354 	}
    355 
    356 	if (!target)
    357 	{
    358 		sendnumeric(client, ERR_NOSUCHNICK, parv[1]);
    359 		return;
    360 	}
    361 
    362 	if (!channel)
    363 	{
    364 		sendnumeric(client, ERR_NOSUCHCHANNEL, parv[2]);
    365 		return;
    366 	}
    367 
    368 	/* proceed with the command */
    369 	for (h = Hooks[HOOKTYPE_PRE_INVITE]; h; h = h->next)
    370 	{
    371 		i = (*(h->func.intfunc))(client,target,channel,&override);
    372 		if (i == HOOK_DENY)
    373 			return;
    374 		if (i == HOOK_ALLOW)
    375 			break;
    376 	}
    377 
    378 	if (!IsMember(client, channel) && !IsULine(client))
    379 	{
    380 		if (ValidatePermissionsForPath("channel:override:invite:notinchannel",client,NULL,channel,NULL) && client == target)
    381 		{
    382 			override = 1;
    383 		} else {
    384 			sendnumeric(client, ERR_NOTONCHANNEL, parv[2]);
    385 			return;
    386 		}
    387 	}
    388 
    389 	if (IsMember(target, channel))
    390 	{
    391 		sendnumeric(client, ERR_USERONCHANNEL, parv[1], parv[2]);
    392 		return;
    393 	}
    394 
    395 	if (has_channel_mode(channel, 'i'))
    396 	{
    397 		if (!check_channel_access(client, channel, "oaq") && !IsULine(client))
    398 		{
    399 			if (ValidatePermissionsForPath("channel:override:invite:invite-only",client,NULL,channel,NULL) && client == target)
    400 			{
    401 				override = 1;
    402 			} else {
    403 				sendnumeric(client, ERR_CHANOPRIVSNEEDED, channel->name);
    404 				return;
    405 			}
    406 		}
    407 		else if (!IsMember(client, channel) && !IsULine(client))
    408 		{
    409 			if (ValidatePermissionsForPath("channel:override:invite:invite-only",client,NULL,channel,NULL) && client == target)
    410 			{
    411 				override = 1;
    412 			} else {
    413 				sendnumeric(client, ERR_CHANOPRIVSNEEDED, channel->name);
    414 				return;
    415 			}
    416 		}
    417 	}
    418 
    419 	if (SPAMFILTER_VIRUSCHANDENY && SPAMFILTER_VIRUSCHAN &&
    420 	    !strcasecmp(channel->name, SPAMFILTER_VIRUSCHAN) &&
    421 	    !check_channel_access(client, channel, "oaq") && !ValidatePermissionsForPath("immune:server-ban:viruschan",client,NULL,NULL,NULL))
    422 	{
    423 		sendnumeric(client, ERR_CHANOPRIVSNEEDED, channel->name);
    424 		return;
    425 	}
    426 
    427 	if (target_limit_exceeded(client, target, target->name))
    428 		return;
    429 
    430 	if (!ValidatePermissionsForPath("immune:invite-flood",client,NULL,NULL,NULL) &&
    431 	    flood_limit_exceeded(client, FLD_INVITE))
    432 	{
    433 		sendnumeric(client, RPL_TRYAGAIN, "INVITE");
    434 		return;
    435 	}
    436 
    437 	if (!override)
    438 	{
    439 		sendnumeric(client, RPL_INVITING, target->name, channel->name);
    440 		if (target->user->away)
    441 		{
    442 			sendnumeric(client, RPL_AWAY, target->name, target->user->away);
    443 		}
    444 	}
    445 	else
    446 	{
    447 		/* Send OperOverride messages */
    448 		char override_what = '\0';
    449 		if (is_banned(client, channel, BANCHK_JOIN, NULL, NULL))
    450 			invite_operoverride_msg(client, channel, "b", "ban");
    451 		else if (has_channel_mode(channel, 'i'))
    452 			invite_operoverride_msg(client, channel, "i", "invite only");
    453 		else if (has_channel_mode(channel, 'l'))
    454 			invite_operoverride_msg(client, channel, "l", "user limit");
    455 		else if (has_channel_mode(channel, 'k'))
    456 			invite_operoverride_msg(client, channel, "k", "key");
    457 		else if (has_channel_mode(channel, 'z'))
    458 			invite_operoverride_msg(client, channel, "z", "secure only");
    459 #ifdef OPEROVERRIDE_VERIFY
    460 		else if (channel->mode.mode & MODE_SECRET || channel->mode.mode & MODE_PRIVATE)
    461 		       override = -1;
    462 #endif
    463 		else
    464 			return;
    465 	}
    466 
    467 	/* allowed to proceed */
    468 	invite_process(client, target, channel, recv_mtags, override);
    469 }
    470 
    471 /** Register an invite from someone to a channel - so they can bypass +i etc.
    472  * @param from		The person sending the invite
    473  * @param to		The person who is invited to join
    474  * @param channel	The channel
    475  * @param mtags		Message tags associated with this INVITE command
    476  */
    477 void add_invite(Client *from, Client *to, Channel *channel, MessageTag *mtags)
    478 {
    479 	Link *inv, *tmp;
    480 
    481 	del_invite(to, channel);
    482 	/* If too many invite entries then delete the oldest one */
    483 	if (link_list_length(CLIENT_INVITES(to)) >= MAXCHANNELSPERUSER)
    484 	{
    485 		for (tmp = CLIENT_INVITES(to); tmp->next; tmp = tmp->next)
    486 			;
    487 		del_invite(to, tmp->value.channel);
    488 
    489 	}
    490 	/* We get pissy over too many invites per channel as well now,
    491 	 * since otherwise mass-inviters could take up some major
    492 	 * resources -Donwulff
    493 	 */
    494 	if (link_list_length(CHANNEL_INVITES(channel)) >= MAXCHANNELSPERUSER)
    495 	{
    496 		for (tmp = CHANNEL_INVITES(channel); tmp->next; tmp = tmp->next)
    497 			;
    498 		del_invite(tmp->value.client, channel);
    499 	}
    500 	/*
    501 	 * add client to the beginning of the channel invite list
    502 	 */
    503 	inv = make_link();
    504 	inv->value.client = to;
    505 	inv->next = CHANNEL_INVITES(channel);
    506 	CHANNEL_INVITES(channel) = inv;
    507 	/*
    508 	 * add channel to the beginning of the client invite list
    509 	 */
    510 	inv = make_link();
    511 	inv->value.channel = channel;
    512 	inv->next = CLIENT_INVITES(to);
    513 	CLIENT_INVITES(to) = inv;
    514 
    515 	RunHook(HOOKTYPE_INVITE, from, to, channel, mtags);
    516 }
    517 
    518 /** Delete a previous invite of someone to a channel.
    519  * @param client	The client who was invited
    520  * @param channel	The channel to which the person was invited
    521  */
    522 void del_invite(Client *client, Channel *channel)
    523 {
    524 	Link **inv, *tmp;
    525 
    526 	for (inv = (Link **)&CHANNEL_INVITES(channel); (tmp = *inv); inv = &tmp->next)
    527 		if (tmp->value.client == client)
    528 		{
    529 			*inv = tmp->next;
    530 			free_link(tmp);
    531 			break;
    532 		}
    533 
    534 	for (inv = (Link **)&CLIENT_INVITES(client); (tmp = *inv); inv = &tmp->next)
    535 		if (tmp->value.channel == channel)
    536 		{
    537 			*inv = tmp->next;
    538 			free_link(tmp);
    539 			break;
    540 		}
    541 }
    542