1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
25 #include "configreader.h"
38 #include "inspstring.h"
39 #include "helperfuncs.h"
42 extern InspIRCd* ServerInstance;
45 extern std::vector<Module*> modules;
46 extern std::vector<ircd_module*> factory;
51 *name = *topic = *setby = *key = 0;
52 created = topicset = limit = 0;
53 internal_userlist.clear();
57 void chanrec::SetMode(char mode,bool mode_on)
59 modes[mode-65] = mode_on;
61 this->SetModeParam(mode,"",false);
65 void chanrec::SetModeParam(char mode,const char* parameter,bool mode_on)
67 log(DEBUG,"SetModeParam called");
69 CustomModeList::iterator n = custom_mode_params.find(mode);
73 if (n == custom_mode_params.end())
75 custom_mode_params[mode] = strdup(parameter);
76 log(DEBUG,"Custom mode parameter %c %s added",mode,parameter);
80 log(DEBUG, "Tried to set custom mode parameter for %c '%s' when it was already '%s'", mode, parameter, n->second);
85 if (n != custom_mode_params.end())
88 custom_mode_params.erase(n);
93 bool chanrec::IsModeSet(char mode)
95 return modes[mode-65];
98 std::string chanrec::GetModeParameter(char mode)
104 else if (mode == 'l')
106 return ConvToStr(this->limit);
110 CustomModeList::iterator n = custom_mode_params.find(mode);
111 if (n != custom_mode_params.end())
119 long chanrec::GetUserCounter()
121 return (this->internal_userlist.size());
124 void chanrec::AddUser(userrec* user)
126 internal_userlist[user] = user;
129 unsigned long chanrec::DelUser(userrec* user)
131 CUListIter a = internal_userlist.find(user);
133 if (a != internal_userlist.end())
135 internal_userlist.erase(a);
136 /* And tidy any others... */
138 DelHalfoppedUser(user);
142 return internal_userlist.size();
145 bool chanrec::HasUser(userrec* user)
147 return (internal_userlist.find(user) != internal_userlist.end());
150 void chanrec::AddOppedUser(userrec* user)
152 internal_op_userlist[user] = user;
155 void chanrec::DelOppedUser(userrec* user)
157 CUListIter a = internal_op_userlist.find(user);
158 if (a != internal_op_userlist.end())
160 internal_op_userlist.erase(a);
165 void chanrec::AddHalfoppedUser(userrec* user)
167 internal_halfop_userlist[user] = user;
170 void chanrec::DelHalfoppedUser(userrec* user)
172 CUListIter a = internal_halfop_userlist.find(user);
174 if (a != internal_halfop_userlist.end())
176 internal_halfop_userlist.erase(a);
180 void chanrec::AddVoicedUser(userrec* user)
182 internal_voice_userlist[user] = user;
185 void chanrec::DelVoicedUser(userrec* user)
187 CUListIter a = internal_voice_userlist.find(user);
189 if (a != internal_voice_userlist.end())
191 internal_voice_userlist.erase(a);
195 CUList* chanrec::GetUsers()
197 return &internal_userlist;
200 CUList* chanrec::GetOppedUsers()
202 return &internal_op_userlist;
205 CUList* chanrec::GetHalfoppedUsers()
207 return &internal_halfop_userlist;
210 CUList* chanrec::GetVoicedUsers()
212 return &internal_voice_userlist;
216 * add a channel to a user, creating the record for it if needed and linking
217 * it to the user record
219 chanrec* chanrec::JoinUser(userrec *user, const char* cn, bool override, const char* key)
227 strlcpy(cname,cn,CHANMAX);
229 chanrec* Ptr = FindChan(cname);
236 FOREACH_RESULT(I_OnUserPreJoin,OnUserPreJoin(user,NULL,cname));
241 /* create a new one */
243 ServerInstance->chanlist[cname] = Ptr;
245 strlcpy(Ptr->name, cname,CHANMAX);
246 Ptr->modes[CM_TOPICLOCK] = Ptr->modes[CM_NOEXTERNAL] = 1;
249 strlcpy(Ptr->setby, user->nick,NICKMAX-1);
251 log(DEBUG,"chanrec::JoinUser(): created: %s",cname);
253 * set created to 2 to indicate user
254 * is the first in the channel
255 * and should be given ops
261 /* Already on the channel */
262 if (Ptr->HasUser(user))
266 * remote users are allowed us to bypass channel modes
267 * and bans (used by servers)
269 if (IS_LOCAL(user)) /* was a check on fd > -1 */
272 FOREACH_RESULT(I_OnUserPreJoin,OnUserPreJoin(user,Ptr,cname));
277 else if (MOD_RESULT == 0)
282 FOREACH_RESULT(I_OnCheckKey,OnCheckKey(user, Ptr, key ? key : ""));
287 log(DEBUG,"chanrec::JoinUser(): no key given in JOIN");
288 user->WriteServ("475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
293 if (strcmp(key,Ptr->key))
295 log(DEBUG,"chanrec::JoinUser(): bad key given in JOIN");
296 user->WriteServ("475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
302 if (Ptr->modes[CM_INVITEONLY])
305 irc::string xname(Ptr->name);
306 FOREACH_RESULT(I_OnCheckInvite,OnCheckInvite(user, Ptr));
309 if (user->IsInvited(xname))
311 /* user was invited to channel */
312 /* there may be an optional channel NOTICE here */
316 user->WriteServ("473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
320 user->RemoveInvite(xname);
325 FOREACH_RESULT(I_OnCheckLimit,OnCheckLimit(user, Ptr));
328 if (Ptr->GetUserCounter() >= Ptr->limit)
330 user->WriteServ("471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
335 if (Ptr->bans.size())
338 FOREACH_RESULT(I_OnCheckBan,OnCheckBan(user, Ptr));
340 sprintf(mask,"%s!%s@%s",user->nick, user->ident, user->GetIPString());
343 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
345 /* This allows CIDR ban matching
347 * Full masked host Full unmasked host IP with/without CIDR
349 if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match(mask, i->data, true)))
351 user->WriteServ("474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
361 log(DEBUG,"chanrec::JoinUser(): Overridden checks");
366 for (UserChanList::const_iterator index = user->chans.begin(); index != user->chans.end(); index++)
368 if ((*index)->channel == NULL)
370 return chanrec::ForceChan(Ptr, *index, user, created);
375 * XXX: If the user is an oper here, we can just extend their user->chans vector by one
376 * and put the channel in here. Same for remote users which are not bound by
377 * the channel limits. Otherwise, nope, youre boned.
379 if (!IS_LOCAL(user)) /* was a check on fd < 0 */
381 ucrec* a = new ucrec();
382 chanrec* c = chanrec::ForceChan(Ptr,a,user,created);
383 user->chans.push_back(a);
386 else if (*user->oper)
388 /* Oper allows extension up to the OPERMAXCHANS value */
389 if (user->chans.size() < OPERMAXCHANS)
391 ucrec* a = new ucrec();
392 chanrec* c = chanrec::ForceChan(Ptr,a,user,created);
393 user->chans.push_back(a);
398 user->WriteServ("405 %s %s :You are on too many channels",user->nick, cname);
402 log(DEBUG,"BLAMMO, Whacking channel.");
403 /* Things went seriously pear shaped, so take this away. bwahaha. */
404 chan_hash::iterator n = ServerInstance->chanlist.find(cname);
405 if (n != ServerInstance->chanlist.end())
409 ServerInstance->chanlist.erase(n);
410 for (unsigned int index =0; index < user->chans.size(); index++)
412 if (user->chans[index]->channel == Ptr)
414 user->chans[index]->channel = NULL;
415 user->chans[index]->uc_modes = 0;
422 for (unsigned int index =0; index < user->chans.size(); index++)
424 if (user->chans[index]->channel == Ptr)
426 user->chans[index]->channel = NULL;
427 user->chans[index]->uc_modes = 0;
434 chanrec* chanrec::ForceChan(chanrec* Ptr,ucrec *a,userrec* user, int created)
438 /* first user in is given ops */
439 a->uc_modes = UCMODE_OP;
440 Ptr->AddOppedUser(user);
449 Ptr->WriteChannel(user,"JOIN :%s",Ptr->name);
451 /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */
454 log(DEBUG,"Sent JOIN to client");
457 user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
458 user->WriteServ("333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
461 user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
463 FOREACH_MOD(I_OnUserJoin,OnUserJoin(user,Ptr));
468 * remove a channel from a users record, and remove the record from the hash
469 * if the channel has become empty
471 long chanrec::PartUser(userrec *user, const char* reason)
474 return this->GetUserCounter();
476 for (unsigned int i =0; i < user->chans.size(); i++)
478 /* zap it from the channel list of the user */
479 if (user->chans[i]->channel == this)
483 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason));
484 this->WriteChannel(user, "PART %s :%s", this->name, reason);
488 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, ""));
489 this->WriteChannel(user, "PART :%s", this->name);
491 user->chans[i]->uc_modes = 0;
492 user->chans[i]->channel = NULL;
497 if (!this->DelUser(user)) /* if there are no users left on the channel... */
499 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
500 /* kill the record */
501 if (iter != ServerInstance->chanlist.end())
503 log(DEBUG,"del_channel: destroyed: %s", this->name);
504 FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
505 ServerInstance->chanlist.erase(iter);
510 return this->GetUserCounter();
513 long chanrec::ServerKickUser(userrec* user, const char* reason, bool triggerevents)
515 if (!user || !reason)
516 return this->GetUserCounter();
520 if (!this->HasUser(user))
523 return this->GetUserCounter();
529 FOREACH_MOD(I_OnUserKick,OnUserKick(NULL,user,this,reason));
532 for (unsigned int i =0; i < user->chans.size(); i++)
534 if (user->chans[i]->channel == this)
536 this->WriteChannelWithServ(ServerInstance->Config->ServerName, "KICK %s %s :%s", this->name, user->nick, reason);
537 user->chans[i]->uc_modes = 0;
538 user->chans[i]->channel = NULL;
543 if (!this->DelUser(user))
545 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
546 /* kill the record */
547 if (iter != ServerInstance->chanlist.end())
549 FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
550 ServerInstance->chanlist.erase(iter);
555 return this->GetUserCounter();
558 long chanrec::KickUser(userrec *src, userrec *user, const char* reason)
560 if (!src || !user || !reason)
561 return this->GetUserCounter();
565 if (!this->HasUser(user))
567 src->WriteServ("441 %s %s %s :They are not on that channel",src->nick, user->nick, this->name);
568 return this->GetUserCounter();
570 if ((is_uline(user->server)) && (!is_uline(src->server)))
572 src->WriteServ("482 %s %s :Only a u-line may kick a u-line from a channel.",src->nick, this->name);
573 return this->GetUserCounter();
577 if (!is_uline(src->server))
580 FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));
582 return this->GetUserCounter();
584 /* Set to -1 by OnUserPreKick if explicit allow was set */
585 if (MOD_RESULT != -1)
587 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));
588 if ((MOD_RESULT == ACR_DENY) && (!is_uline(src->server)))
589 return this->GetUserCounter();
591 if ((MOD_RESULT == ACR_DEFAULT) || (!is_uline(src->server)))
593 int them = cstatus(src, this);
594 int us = cstatus(user, this);
595 if ((them < STATUS_HOP) || (them < us))
597 if (them == STATUS_HOP)
599 src->WriteServ("482 %s %s :You must be a channel operator",src->nick, this->name);
603 src->WriteServ("482 %s %s :You must be at least a half-operator",src->nick, this->name);
605 return this->GetUserCounter();
611 FOREACH_MOD(I_OnUserKick,OnUserKick(src,user,this,reason));
613 for (UserChanList::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
615 /* zap it from the channel list of the user */
616 if ((*i)->channel == this)
618 this->WriteChannel(src, "KICK %s %s :%s", this->name, user->nick, reason);
620 (*i)->channel = NULL;
625 if (!this->DelUser(user))
626 /* if there are no users left on the channel */
628 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
630 /* kill the record */
631 if (iter != ServerInstance->chanlist.end())
633 FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
634 ServerInstance->chanlist.erase(iter);
639 return this->GetUserCounter();
642 void chanrec::WriteChannel(userrec* user, char* text, ...)
644 char textbuffer[MAXBUF];
650 va_start(argsPtr, text);
651 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
654 this->WriteChannel(user, std::string(textbuffer));
657 void chanrec::WriteChannel(userrec* user, const std::string &text)
659 CUList *ulist = this->GetUsers();
664 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
666 if (i->second->fd != FD_MAGIC_NUMBER)
667 user->WriteTo(i->second,text);
671 void chanrec::WriteChannelWithServ(const char* ServName, const char* text, ...)
673 char textbuffer[MAXBUF];
679 va_start(argsPtr, text);
680 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
683 this->WriteChannelWithServ(ServName, std::string(textbuffer));
686 void chanrec::WriteChannelWithServ(const char* ServName, const std::string &text)
688 CUList *ulist = this->GetUsers();
690 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
692 if (IS_LOCAL(i->second))
693 i->second->WriteServ(text);
697 /* write formatted text from a source user to all users on a channel except
698 * for the sender (for privmsg etc) */
699 void chanrec::WriteAllExceptSender(userrec* user, char status, char* text, ...)
701 char textbuffer[MAXBUF];
707 va_start(argsPtr, text);
708 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
711 this->WriteAllExceptSender(user, status, std::string(textbuffer));
714 void chanrec::WriteAllExceptSender(userrec* user, char status, const std::string& text)
724 ulist = this->GetOppedUsers();
727 ulist = this->GetHalfoppedUsers();
730 ulist = this->GetVoicedUsers();
733 ulist = this->GetUsers();
737 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
739 if ((IS_LOCAL(i->second)) && (user != i->second))
740 i->second->WriteFrom(user,text);