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