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"
37 #include "inspstring.h"
38 #include "helperfuncs.h"
43 chanrec::chanrec(InspIRCd* Instance) : ServerInstance(Instance)
45 *name = *topic = *setby = *key = 0;
46 created = topicset = limit = 0;
47 internal_userlist.clear();
51 void chanrec::SetMode(char mode,bool mode_on)
53 modes[mode-65] = mode_on;
55 this->SetModeParam(mode,"",false);
59 void chanrec::SetModeParam(char mode,const char* parameter,bool mode_on)
61 log(DEBUG,"SetModeParam called");
63 CustomModeList::iterator n = custom_mode_params.find(mode);
67 if (n == custom_mode_params.end())
69 custom_mode_params[mode] = strdup(parameter);
70 log(DEBUG,"Custom mode parameter %c %s added",mode,parameter);
74 log(DEBUG, "Tried to set custom mode parameter for %c '%s' when it was already '%s'", mode, parameter, n->second);
79 if (n != custom_mode_params.end())
82 custom_mode_params.erase(n);
87 bool chanrec::IsModeSet(char mode)
89 return modes[mode-65];
92 std::string chanrec::GetModeParameter(char mode)
100 return ConvToStr(this->limit);
104 CustomModeList::iterator n = custom_mode_params.find(mode);
105 if (n != custom_mode_params.end())
113 long chanrec::GetUserCounter()
115 return (this->internal_userlist.size());
118 void chanrec::AddUser(userrec* user)
120 internal_userlist[user] = user;
123 unsigned long chanrec::DelUser(userrec* user)
125 CUListIter a = internal_userlist.find(user);
127 if (a != internal_userlist.end())
129 internal_userlist.erase(a);
130 /* And tidy any others... */
132 DelHalfoppedUser(user);
136 return internal_userlist.size();
139 bool chanrec::HasUser(userrec* user)
141 return (internal_userlist.find(user) != internal_userlist.end());
144 void chanrec::AddOppedUser(userrec* user)
146 internal_op_userlist[user] = user;
149 void chanrec::DelOppedUser(userrec* user)
151 CUListIter a = internal_op_userlist.find(user);
152 if (a != internal_op_userlist.end())
154 internal_op_userlist.erase(a);
159 void chanrec::AddHalfoppedUser(userrec* user)
161 internal_halfop_userlist[user] = user;
164 void chanrec::DelHalfoppedUser(userrec* user)
166 CUListIter a = internal_halfop_userlist.find(user);
168 if (a != internal_halfop_userlist.end())
170 internal_halfop_userlist.erase(a);
174 void chanrec::AddVoicedUser(userrec* user)
176 internal_voice_userlist[user] = user;
179 void chanrec::DelVoicedUser(userrec* user)
181 CUListIter a = internal_voice_userlist.find(user);
183 if (a != internal_voice_userlist.end())
185 internal_voice_userlist.erase(a);
189 CUList* chanrec::GetUsers()
191 return &internal_userlist;
194 CUList* chanrec::GetOppedUsers()
196 return &internal_op_userlist;
199 CUList* chanrec::GetHalfoppedUsers()
201 return &internal_halfop_userlist;
204 CUList* chanrec::GetVoicedUsers()
206 return &internal_voice_userlist;
210 * add a channel to a user, creating the record for it if needed and linking
211 * it to the user record
213 chanrec* chanrec::JoinUser(InspIRCd* Instance, userrec *user, const char* cn, bool override, const char* key)
221 strlcpy(cname,cn,CHANMAX);
223 chanrec* Ptr = Instance->FindChan(cname);
230 FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,NULL,cname));
235 /* create a new one */
236 Ptr = new chanrec(Instance);
237 Instance->chanlist[cname] = Ptr;
239 strlcpy(Ptr->name, cname,CHANMAX);
240 Ptr->modes[CM_TOPICLOCK] = Ptr->modes[CM_NOEXTERNAL] = 1;
243 strlcpy(Ptr->setby, user->nick,NICKMAX-1);
245 log(DEBUG,"chanrec::JoinUser(): created: %s",cname);
247 * set created to 2 to indicate user
248 * is the first in the channel
249 * and should be given ops
255 /* Already on the channel */
256 if (Ptr->HasUser(user))
260 * remote users are allowed us to bypass channel modes
261 * and bans (used by servers)
263 if (IS_LOCAL(user)) /* was a check on fd > -1 */
266 FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,Ptr,cname));
271 else if (MOD_RESULT == 0)
276 FOREACH_RESULT_I(Instance,I_OnCheckKey,OnCheckKey(user, Ptr, key ? key : ""));
281 log(DEBUG,"chanrec::JoinUser(): no key given in JOIN");
282 user->WriteServ("475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
287 if (strcmp(key,Ptr->key))
289 log(DEBUG,"chanrec::JoinUser(): bad key given in JOIN");
290 user->WriteServ("475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
296 if (Ptr->modes[CM_INVITEONLY])
299 irc::string xname(Ptr->name);
300 FOREACH_RESULT_I(Instance,I_OnCheckInvite,OnCheckInvite(user, Ptr));
303 if (user->IsInvited(xname))
305 /* user was invited to channel */
306 /* there may be an optional channel NOTICE here */
310 user->WriteServ("473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
314 user->RemoveInvite(xname);
319 FOREACH_RESULT_I(Instance,I_OnCheckLimit,OnCheckLimit(user, Ptr));
322 if (Ptr->GetUserCounter() >= Ptr->limit)
324 user->WriteServ("471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
329 if (Ptr->bans.size())
332 FOREACH_RESULT_I(Instance,I_OnCheckBan,OnCheckBan(user, Ptr));
334 sprintf(mask,"%s!%s@%s",user->nick, user->ident, user->GetIPString());
337 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
339 /* This allows CIDR ban matching
341 * Full masked host Full unmasked host IP with/without CIDR
343 if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match(mask, i->data, true)))
345 user->WriteServ("474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
355 log(DEBUG,"chanrec::JoinUser(): Overridden checks");
360 for (UserChanList::const_iterator index = user->chans.begin(); index != user->chans.end(); index++)
362 if ((*index)->channel == NULL)
364 return chanrec::ForceChan(Instance, Ptr, *index, user, created);
369 * XXX: If the user is an oper here, we can just extend their user->chans vector by one
370 * and put the channel in here. Same for remote users which are not bound by
371 * the channel limits. Otherwise, nope, youre boned.
373 if (!IS_LOCAL(user)) /* was a check on fd < 0 */
375 ucrec* a = new ucrec();
376 chanrec* c = chanrec::ForceChan(Instance, Ptr,a,user,created);
377 user->chans.push_back(a);
380 else if (*user->oper)
382 /* Oper allows extension up to the OPERMAXCHANS value */
383 if (user->chans.size() < OPERMAXCHANS)
385 ucrec* a = new ucrec();
386 chanrec* c = chanrec::ForceChan(Instance, Ptr,a,user,created);
387 user->chans.push_back(a);
392 user->WriteServ("405 %s %s :You are on too many channels",user->nick, cname);
396 log(DEBUG,"BLAMMO, Whacking channel.");
397 /* Things went seriously pear shaped, so take this away. bwahaha. */
398 chan_hash::iterator n = Instance->chanlist.find(cname);
399 if (n != Instance->chanlist.end())
403 Instance->chanlist.erase(n);
404 for (unsigned int index =0; index < user->chans.size(); index++)
406 if (user->chans[index]->channel == Ptr)
408 user->chans[index]->channel = NULL;
409 user->chans[index]->uc_modes = 0;
416 for (unsigned int index =0; index < user->chans.size(); index++)
418 if (user->chans[index]->channel == Ptr)
420 user->chans[index]->channel = NULL;
421 user->chans[index]->uc_modes = 0;
428 chanrec* chanrec::ForceChan(InspIRCd* Instance, chanrec* Ptr,ucrec *a,userrec* user, int created)
432 /* first user in is given ops */
433 a->uc_modes = UCMODE_OP;
434 Ptr->AddOppedUser(user);
443 Ptr->WriteChannel(user,"JOIN :%s",Ptr->name);
445 /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */
448 log(DEBUG,"Sent JOIN to client");
451 user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
452 user->WriteServ("333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
455 user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
457 FOREACH_MOD_I(Instance,I_OnUserJoin,OnUserJoin(user,Ptr));
462 * remove a channel from a users record, and remove the record from the hash
463 * if the channel has become empty
465 long chanrec::PartUser(userrec *user, const char* reason)
468 return this->GetUserCounter();
470 for (unsigned int i =0; i < user->chans.size(); i++)
472 /* zap it from the channel list of the user */
473 if (user->chans[i]->channel == this)
477 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason));
478 this->WriteChannel(user, "PART %s :%s", this->name, reason);
482 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, ""));
483 this->WriteChannel(user, "PART :%s", this->name);
485 user->chans[i]->uc_modes = 0;
486 user->chans[i]->channel = NULL;
491 if (!this->DelUser(user)) /* if there are no users left on the channel... */
493 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
494 /* kill the record */
495 if (iter != ServerInstance->chanlist.end())
497 log(DEBUG,"del_channel: destroyed: %s", this->name);
498 FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
499 ServerInstance->chanlist.erase(iter);
504 return this->GetUserCounter();
507 long chanrec::ServerKickUser(userrec* user, const char* reason, bool triggerevents)
509 if (!user || !reason)
510 return this->GetUserCounter();
514 if (!this->HasUser(user))
517 return this->GetUserCounter();
523 FOREACH_MOD(I_OnUserKick,OnUserKick(NULL,user,this,reason));
526 for (unsigned int i =0; i < user->chans.size(); i++)
528 if (user->chans[i]->channel == this)
530 this->WriteChannelWithServ(ServerInstance->Config->ServerName, "KICK %s %s :%s", this->name, user->nick, reason);
531 user->chans[i]->uc_modes = 0;
532 user->chans[i]->channel = NULL;
537 if (!this->DelUser(user))
539 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
540 /* kill the record */
541 if (iter != ServerInstance->chanlist.end())
543 FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
544 ServerInstance->chanlist.erase(iter);
549 return this->GetUserCounter();
552 long chanrec::KickUser(userrec *src, userrec *user, const char* reason)
554 if (!src || !user || !reason)
555 return this->GetUserCounter();
559 if (!this->HasUser(user))
561 src->WriteServ("441 %s %s %s :They are not on that channel",src->nick, user->nick, this->name);
562 return this->GetUserCounter();
564 if ((is_uline(user->server)) && (!is_uline(src->server)))
566 src->WriteServ("482 %s %s :Only a u-line may kick a u-line from a channel.",src->nick, this->name);
567 return this->GetUserCounter();
571 if (!is_uline(src->server))
574 FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));
576 return this->GetUserCounter();
578 /* Set to -1 by OnUserPreKick if explicit allow was set */
579 if (MOD_RESULT != -1)
581 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));
582 if ((MOD_RESULT == ACR_DENY) && (!is_uline(src->server)))
583 return this->GetUserCounter();
585 if ((MOD_RESULT == ACR_DEFAULT) || (!is_uline(src->server)))
587 int them = this->GetStatus(src);
588 int us = this->GetStatus(user);
589 if ((them < STATUS_HOP) || (them < us))
591 if (them == STATUS_HOP)
593 src->WriteServ("482 %s %s :You must be a channel operator",src->nick, this->name);
597 src->WriteServ("482 %s %s :You must be at least a half-operator",src->nick, this->name);
599 return this->GetUserCounter();
605 FOREACH_MOD(I_OnUserKick,OnUserKick(src,user,this,reason));
607 for (UserChanList::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
609 /* zap it from the channel list of the user */
610 if ((*i)->channel == this)
612 this->WriteChannel(src, "KICK %s %s :%s", this->name, user->nick, reason);
614 (*i)->channel = NULL;
619 if (!this->DelUser(user))
620 /* if there are no users left on the channel */
622 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
624 /* kill the record */
625 if (iter != ServerInstance->chanlist.end())
627 FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
628 ServerInstance->chanlist.erase(iter);
633 return this->GetUserCounter();
636 void chanrec::WriteChannel(userrec* user, char* text, ...)
638 char textbuffer[MAXBUF];
644 va_start(argsPtr, text);
645 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
648 this->WriteChannel(user, std::string(textbuffer));
651 void chanrec::WriteChannel(userrec* user, const std::string &text)
653 CUList *ulist = this->GetUsers();
658 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
660 if (i->second->fd != FD_MAGIC_NUMBER)
661 user->WriteTo(i->second,text);
665 void chanrec::WriteChannelWithServ(const char* ServName, const char* text, ...)
667 char textbuffer[MAXBUF];
673 va_start(argsPtr, text);
674 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
677 this->WriteChannelWithServ(ServName, std::string(textbuffer));
680 void chanrec::WriteChannelWithServ(const char* ServName, const std::string &text)
682 CUList *ulist = this->GetUsers();
684 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
686 if (IS_LOCAL(i->second))
687 i->second->WriteServ(text);
691 /* write formatted text from a source user to all users on a channel except
692 * for the sender (for privmsg etc) */
693 void chanrec::WriteAllExceptSender(userrec* user, char status, char* text, ...)
695 char textbuffer[MAXBUF];
701 va_start(argsPtr, text);
702 vsnprintf(textbuffer, MAXBUF, text, argsPtr);
705 this->WriteAllExceptSender(user, status, std::string(textbuffer));
708 void chanrec::WriteAllExceptSender(userrec* user, char status, const std::string& text)
718 ulist = this->GetOppedUsers();
721 ulist = this->GetHalfoppedUsers();
724 ulist = this->GetVoicedUsers();
727 ulist = this->GetUsers();
731 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
733 if ((IS_LOCAL(i->second)) && (user != i->second))
734 i->second->WriteFrom(user,text);
739 * return a count of the users on a specific channel accounting for
740 * invisible users who won't increase the count. e.g. for /LIST
742 int chanrec::CountInvisible()
745 CUList *ulist= this->GetUsers();
746 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
748 if (!(i->second->modes[UM_INVISIBLE]))
755 char* chanrec::ChanModes(bool showkey)
757 static char scratch[MAXBUF];
758 static char sparam[MAXBUF];
759 char* offset = scratch;
760 std::string extparam = "";
765 /* This was still iterating up to 190, chanrec::custom_modes is only 64 elements -- Om */
766 for(int n = 0; n < 64; n++)
775 extparam = (showkey ? this->key : "<key>");
778 extparam = ConvToStr(this->limit);
786 /* We know these have no parameters */
789 extparam = this->GetModeParameter(n + 65);
794 charlcat(sparam,' ',MAXBUF);
795 strlcat(sparam,extparam.c_str(),MAXBUF);
800 /* Null terminate scratch */
802 strlcat(scratch,sparam,MAXBUF);
806 /* compile a userlist of a channel into a string, each nick seperated by
807 * spaces and op, voice etc status shown as @ and +, and send it to 'user'
809 void chanrec::UserList(userrec *user)
814 dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);
817 char* ptr = list + dlen;
819 CUList *ulist= this->GetUsers();
821 /* Improvement by Brain - this doesnt change in value, so why was it inside
824 bool has_user = this->HasUser(user);
826 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
828 if ((!has_user) && (i->second->modes[UM_INVISIBLE]))
831 * user is +i, and source not on the channel, does not show
837 size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", this->GetStatusChar(i->second), i->second->nick);
844 if (curlen > (480-NICKMAX))
846 /* list overflowed into multiple numerics */
847 user->WriteServ(list);
849 /* reset our lengths */
850 dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);
858 /* if whats left in the list isnt empty, send it */
861 user->WriteServ(list);
865 long chanrec::GetMaxBans()
868 for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
871 if (match(this->name,x.c_str()))
880 /* returns the status character for a given user on a channel, e.g. @ for op,
881 * % for halfop etc. If the user has several modes set, the highest mode
882 * the user has must be returned. */
884 const char* chanrec::GetStatusChar(userrec *user)
886 for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
888 if ((*i)->channel == this)
890 if (((*i)->uc_modes & UCMODE_OP) > 0)
894 if (((*i)->uc_modes & UCMODE_HOP) > 0)
898 if (((*i)->uc_modes & UCMODE_VOICE) > 0)
909 int chanrec::GetStatusFlags(userrec *user)
911 for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
913 if ((*i)->channel == this)
915 return (*i)->uc_modes;
923 int chanrec::GetStatus(userrec *user)
925 if (is_uline(user->server))
928 for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
930 if ((*i)->channel == this)
932 if (((*i)->uc_modes & UCMODE_OP) > 0)
936 if (((*i)->uc_modes & UCMODE_HOP) > 0)
940 if (((*i)->uc_modes & UCMODE_VOICE) > 0)
944 return STATUS_NORMAL;
947 return STATUS_NORMAL;