]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/channels.cpp
Implement <options:invitebypassmodes>, optionally circumvent +blk if invited on join...
[user/henk/code/inspircd.git] / src / channels.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core */
15
16 #include "inspircd.h"
17 #include <cstdarg>
18 #include "wildcard.h"
19 #include "mode.h"
20
21 Channel::Channel(InspIRCd* Instance, const std::string &cname, time_t ts) : ServerInstance(Instance)
22 {
23         chan_hash::iterator findchan = ServerInstance->chanlist->find(cname);
24         if (findchan != Instance->chanlist->end())
25                 throw CoreException("Cannot create duplicate channel " + cname);
26
27         (*(ServerInstance->chanlist))[cname.c_str()] = this;
28         this->name.assign(cname, 0, ServerInstance->Config->Limits.ChanMax);
29         this->created = ts ? ts : ServerInstance->Time();
30         this->age = this->created;
31
32         maxbans = topicset = 0;
33         modes.reset();
34 }
35
36 void Channel::SetMode(char mode,bool mode_on)
37 {
38         modes[mode-65] = mode_on;
39         if (!mode_on)
40                 this->SetModeParam(mode,"",false);
41 }
42
43
44 void Channel::SetModeParam(char mode,const char* parameter,bool mode_on)
45 {
46         CustomModeList::iterator n = custom_mode_params.find(mode);
47
48         if (mode_on)
49         {
50                 if (n == custom_mode_params.end())
51                         custom_mode_params[mode] = strdup(parameter);
52         }
53         else
54         {
55                 if (n != custom_mode_params.end())
56                 {
57                         free(n->second);
58                         custom_mode_params.erase(n);
59                 }
60         }
61 }
62
63 bool Channel::IsModeSet(char mode)
64 {
65         return modes[mode-65];
66 }
67
68 std::string Channel::GetModeParameter(char mode)
69 {
70         CustomModeList::iterator n = custom_mode_params.find(mode);
71         if (n != custom_mode_params.end())
72                 return n->second;
73         return "";
74 }
75
76 int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
77 {
78         if (IS_LOCAL(u))
79         {
80                 if(!forceset)
81                 {
82                         int MOD_RESULT = 0;
83                         /* 0: check status, 1: don't, -1: disallow change silently */
84
85                         FOREACH_RESULT(I_OnLocalTopicChange,OnLocalTopicChange(u,this,ntopic));
86                 
87                         if (MOD_RESULT == 1)
88                                 return CMD_FAILURE;
89                         else if (MOD_RESULT == 0)
90                         {
91                                 if (!this->HasUser(u))
92                                 {
93                                         u->WriteNumeric(442, "%s %s :You're not on that channel!",u->nick.c_str(), this->name.c_str());
94                                         return CMD_FAILURE;
95                                 }
96                                 if ((this->IsModeSet('t')) && (this->GetStatus(u) < STATUS_HOP))
97                                 {
98                                         u->WriteNumeric(482, "%s %s :You must be at least a half-operator to change the topic on this channel", u->nick.c_str(), this->name.c_str());
99                                         return CMD_FAILURE;
100                                 }
101                         }
102                 }
103         }
104
105         this->topic.assign(ntopic, 0, ServerInstance->Config->Limits.MaxTopic);
106         this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128);
107         this->topicset = ServerInstance->Time();
108         this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
109
110         if (IS_LOCAL(u))
111         {
112                 FOREACH_MOD(I_OnPostLocalTopicChange,OnPostLocalTopicChange(u, this, this->topic));
113         }
114
115         return CMD_SUCCESS;
116 }
117
118 long Channel::GetUserCounter()
119 {
120         return (this->internal_userlist.size());
121 }
122
123 void Channel::AddUser(User* user)
124 {
125         internal_userlist[user] = user->nick;
126 }
127
128 unsigned long Channel::DelUser(User* user)
129 {
130         CUListIter a = internal_userlist.find(user);
131
132         if (a != internal_userlist.end())
133         {
134                 internal_userlist.erase(a);
135                 /* And tidy any others... */
136                 DelOppedUser(user);
137                 DelHalfoppedUser(user);
138                 DelVoicedUser(user);
139         }
140
141         return internal_userlist.size();
142 }
143
144 bool Channel::HasUser(User* user)
145 {
146         return (internal_userlist.find(user) != internal_userlist.end());
147 }
148
149 void Channel::AddOppedUser(User* user)
150 {
151         internal_op_userlist[user] = user->nick;
152 }
153
154 void Channel::DelOppedUser(User* user)
155 {
156         CUListIter a = internal_op_userlist.find(user);
157         if (a != internal_op_userlist.end())
158         {
159                 internal_op_userlist.erase(a);
160                 return;
161         }
162 }
163
164 void Channel::AddHalfoppedUser(User* user)
165 {
166         internal_halfop_userlist[user] = user->nick;
167 }
168
169 void Channel::DelHalfoppedUser(User* user)
170 {
171         CUListIter a = internal_halfop_userlist.find(user);
172
173         if (a != internal_halfop_userlist.end())
174         {
175                 internal_halfop_userlist.erase(a);
176         }
177 }
178
179 void Channel::AddVoicedUser(User* user)
180 {
181         internal_voice_userlist[user] = user->nick;
182 }
183
184 void Channel::DelVoicedUser(User* user)
185 {
186         CUListIter a = internal_voice_userlist.find(user);
187
188         if (a != internal_voice_userlist.end())
189         {
190                 internal_voice_userlist.erase(a);
191         }
192 }
193
194 CUList* Channel::GetUsers()
195 {
196         return &internal_userlist;
197 }
198
199 CUList* Channel::GetOppedUsers()
200 {
201         return &internal_op_userlist;
202 }
203
204 CUList* Channel::GetHalfoppedUsers()
205 {
206         return &internal_halfop_userlist;
207 }
208
209 CUList* Channel::GetVoicedUsers()
210 {
211         return &internal_voice_userlist;
212 }
213
214 void Channel::SetDefaultModes()
215 {
216         ServerInstance->Logs->Log("CHANNELS", DEBUG, "SetDefaultModes %s", ServerInstance->Config->DefaultModes);
217         irc::spacesepstream list(ServerInstance->Config->DefaultModes);
218         std::string modeseq;
219         std::string parameter;
220
221         list.GetToken(modeseq);
222
223         for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n)
224         {
225                 ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
226                 if (mode)
227                 {
228                         if (mode->GetNumParams(true))
229                                 list.GetToken(parameter);
230                         else
231                                 parameter.clear();
232
233                         mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, parameter, true);
234                 }
235         }
236 }
237
238 /*
239  * add a channel to a user, creating the record for it if needed and linking
240  * it to the user record
241  */
242 Channel* Channel::JoinUser(InspIRCd* Instance, User *user, const char* cn, bool override, const char* key, bool bursting, time_t TS)
243 {
244         if (!user || !cn)
245                 return NULL;
246
247         char cname[MAXBUF];
248         int MOD_RESULT = 0;
249         std::string privs;
250         Channel *Ptr;
251
252         /*
253          * We don't restrict the number of channels that remote users or users that are override-joining may be in.
254          * We restrict local users to MaxChans channels.
255          * We restrict local operators to OperMaxChans channels.
256          * This is a lot more logical than how it was formerly. -- w00t
257          */
258         if (IS_LOCAL(user) && !override)
259         {
260                 // Checking MyClass exists because we *may* get here with NULL, not 100% sure.
261                 if (user->MyClass && user->MyClass->GetMaxChans())
262                 {
263                         if (user->chans.size() >= user->MyClass->GetMaxChans())
264                         {
265                                 user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
266                                 return NULL;
267                         }
268                 }
269                 else
270                 {
271                         if (IS_OPER(user))
272                         {
273                                 if (user->chans.size() >= Instance->Config->OperMaxChans)
274                                 {
275                                         user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
276                                         return NULL;
277                                 }
278                         }
279                         else
280                         {
281                                 if (user->chans.size() >= Instance->Config->MaxChans)
282                                 {
283                                         user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
284                                         return NULL;
285                                 }
286                         }
287                 }
288         }
289
290         strlcpy(cname, cn, Instance->Config->Limits.ChanMax);
291         Ptr = Instance->FindChan(cname);
292
293         if (!Ptr)
294         {
295                 /*
296                  * Fix: desync bug was here, don't set @ on remote users - spanningtree handles their permissions. bug #358. -- w00t
297                  */
298                 if (!IS_LOCAL(user))
299                 {
300                         if (!TS)
301                                 Instance->Logs->Log("CHANNEL",DEBUG,"*** BUG *** Channel::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick.c_str(), cn);
302                 }
303                 else
304                 {
305                         privs = "@";
306                 }
307
308                 if (IS_LOCAL(user) && override == false)
309                 {
310                         MOD_RESULT = 0;
311                         FOREACH_RESULT_I(Instance,I_OnUserPreJoin, OnUserPreJoin(user, NULL, cname, privs, key ? key : ""));
312                         if (MOD_RESULT == 1)
313                                 return NULL;
314                 }
315
316                 Ptr = new Channel(Instance, cname, TS);
317         }
318         else
319         {
320                 /* Already on the channel */
321                 if (Ptr->HasUser(user))
322                         return NULL;
323
324                 /*
325                  * remote users are allowed us to bypass channel modes
326                  * and bans (used by servers)
327                  */
328                 if (IS_LOCAL(user) && override == false)
329                 {
330                         MOD_RESULT = 0;
331                         FOREACH_RESULT_I(Instance,I_OnUserPreJoin, OnUserPreJoin(user, Ptr, cname, privs, key ? key : ""));
332                         if (MOD_RESULT == 1)
333                         {
334                                 return NULL;
335                         }
336                         else if (MOD_RESULT == 0)
337                         {
338                                 std::string ckey = Ptr->GetModeParameter('k');
339                                 bool invited = user->IsInvited(Ptr->name.c_str());
340                                 bool can_bypass = Instance->Config->InvBypassModes && invited;
341
342                                 if (!ckey.empty())
343                                 {
344                                         MOD_RESULT = 0;
345                                         FOREACH_RESULT_I(Instance, I_OnCheckKey, OnCheckKey(user, Ptr, key ? key : ""));
346                                         if (!MOD_RESULT)
347                                         {
348                                                 // If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled)
349                                                 if ((!key || ckey != key) && !can_bypass)
350                                                 {
351                                                         user->WriteNumeric(ERR_BADCHANNELKEY, "%s %s :Cannot join channel (Incorrect channel key)",user->nick.c_str(), Ptr->name.c_str());
352                                                         return NULL;
353                                                 }
354                                         }
355                                 }
356
357                                 if (Ptr->IsModeSet('i'))
358                                 {
359                                         MOD_RESULT = 0;
360                                         FOREACH_RESULT_I(Instance,I_OnCheckInvite,OnCheckInvite(user, Ptr));
361                                         if (!MOD_RESULT)
362                                         {
363                                                 if (!invited)
364                                                 {
365                                                         user->WriteNumeric(ERR_INVITEONLYCHAN, "%s %s :Cannot join channel (Invite only)",user->nick.c_str(), Ptr->name.c_str());
366                                                         return NULL;
367                                                 }
368                                         }
369                                 }
370
371                                 std::string limit = Ptr->GetModeParameter('l');
372                                 if (!limit.empty())
373                                 {
374                                         MOD_RESULT = 0;
375                                         FOREACH_RESULT_I(Instance, I_OnCheckLimit, OnCheckLimit(user, Ptr));
376                                         if (!MOD_RESULT)
377                                         {
378                                                 long llimit = atol(limit.c_str());
379                                                 if (Ptr->GetUserCounter() >= llimit && !can_bypass)
380                                                 {
381                                                         user->WriteNumeric(ERR_CHANNELISFULL, "%s %s :Cannot join channel (Channel is full)",user->nick.c_str(), Ptr->name.c_str());
382                                                         return NULL;
383                                                 }
384                                         }
385                                 }
386
387                                 if (Ptr->bans.size())
388                                 {
389                                         if (Ptr->IsBanned(user) && !can_bypass)
390                                         {
391                                                 user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)",user->nick.c_str(), Ptr->name.c_str());
392                                                 return NULL;
393                                         }
394                                 }
395
396                                 /*
397                                  * If the user has invites for this channel, remove them now
398                                  * after a successful join so they don't build up.
399                                  */
400                                 if (invited)
401                                 {
402                                         user->RemoveInvite(Ptr->name.c_str());
403                                 }
404                         }
405                 }
406         }
407
408         /* As spotted by jilles, dont bother to set this on remote users */
409         if (IS_LOCAL(user) && Ptr->GetUserCounter() == 0)
410                 Ptr->SetDefaultModes();
411
412         return Channel::ForceChan(Instance, Ptr, user, privs, bursting);
413 }
414
415 Channel* Channel::ForceChan(InspIRCd* Instance, Channel* Ptr, User* user, const std::string &privs, bool bursting)
416 {       
417         std::string nick = user->nick;
418         bool silent = false;
419
420         Ptr->AddUser(user);
421
422         /* Just in case they have no permissions */
423         user->chans[Ptr] = 0;
424
425         for (std::string::const_iterator x = privs.begin(); x != privs.end(); x++)
426         {
427                 const char status = *x;
428                 ModeHandler* mh = Instance->Modes->FindPrefix(status);
429                 if (mh)
430                 {
431                         /* Set, and make sure that the mode handler knows this mode was now set */
432                         Ptr->SetPrefix(user, status, mh->GetPrefixRank(), true);
433                         mh->OnModeChange(Instance->FakeClient, Instance->FakeClient, Ptr, nick, true);
434
435                         switch (mh->GetPrefix())
436                         {
437                                 /* These logic ops are SAFE IN THIS CASE because if the entry doesnt exist,
438                                  * addressing operator[] creates it. If they do exist, it points to it.
439                                  * At all other times where we dont want to create an item if it doesnt exist, we
440                                  * must stick to ::find().
441                                  */
442                                 case '@':
443                                         user->chans[Ptr] |= UCMODE_OP;
444                                 break;
445                                 case '%':
446                                         user->chans[Ptr] |= UCMODE_HOP;
447                                 break;
448                                 case '+':
449                                         user->chans[Ptr] |= UCMODE_VOICE;
450                                 break;
451                         }
452                 }
453         }
454
455         FOREACH_MOD_I(Instance,I_OnUserJoin,OnUserJoin(user, Ptr, bursting, silent));
456
457         if (!silent)
458                 Ptr->WriteChannel(user,"JOIN :%s",Ptr->name.c_str());
459
460         /* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */
461         std::string ms = Instance->Modes->ModeString(user, Ptr);
462         if ((Ptr->GetUserCounter() > 1) && (ms.length()))
463                 Ptr->WriteAllExceptSender(user, true, 0, "MODE %s +%s", Ptr->name.c_str(), ms.c_str());
464
465         /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */
466         if (IS_LOCAL(user))
467         {
468                 if (Ptr->topicset)
469                 {
470                         user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), Ptr->name.c_str(), Ptr->topic.c_str());
471                         user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), Ptr->name.c_str(), Ptr->setby.c_str(), (unsigned long)Ptr->topicset);
472                 }
473                 Ptr->UserList(user);
474         }
475         FOREACH_MOD_I(Instance,I_OnPostJoin,OnPostJoin(user, Ptr));
476         return Ptr;
477 }
478
479 bool Channel::IsBanned(User* user)
480 {
481         char mask[MAXBUF];
482         int MOD_RESULT = 0;
483         FOREACH_RESULT(I_OnCheckBan,OnCheckBan(user, this));
484
485         if (MOD_RESULT == -1)
486                 return true;
487         else if (MOD_RESULT == 0)
488         {
489                 snprintf(mask, MAXBUF, "%s!%s@%s", user->nick.c_str(), user->ident.c_str(), user->GetIPString());
490                 for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
491                 {
492                         /* This allows CIDR ban matching
493                          *
494                          *        Full masked host                      Full unmasked host                   IP with/without CIDR
495                          */
496                         if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match(mask, i->data, true)))
497                         {
498                                 return true;
499                         }
500                 }
501         }
502         return false;
503 }
504
505 bool Channel::IsExtBanned(const std::string &str, char type)
506 {
507         int MOD_RESULT = 0;
508         FOREACH_RESULT(I_OnCheckStringExtBan, OnCheckStringExtBan(str, this, type));
509
510         if (MOD_RESULT == -1)
511                 return true;
512         else if (MOD_RESULT == 0)
513         {
514                 for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
515                 {
516                         if (i->data[0] != type || i->data[1] != ':')
517                                 continue;
518
519                         // Iterate past char and : to get to the mask without doing a data copy(!)
520                         std::string maskptr = i->data.substr(2);
521                         ServerInstance->Logs->Log("EXTBANS", DEBUG, "Checking %s against %s, type is %c", str.c_str(), maskptr.c_str(), type);
522
523                         if (match(str, maskptr))
524                                 return true;
525                 }
526         }
527
528         return false;
529 }
530
531 bool Channel::IsExtBanned(User *user, char type)
532 {
533         int MOD_RESULT = 0;
534         FOREACH_RESULT(I_OnCheckExtBan, OnCheckExtBan(user, this, type));
535
536         if (MOD_RESULT == -1)
537                 return true;
538         else if (MOD_RESULT == 0)
539         {
540                 char mask[MAXBUF];
541                 snprintf(mask, MAXBUF, "%s!%s@%s", user->nick.c_str(), user->ident.c_str(), user->GetIPString());
542
543                 // XXX: we should probably hook cloaked hosts in here somehow too..
544                 if (this->IsExtBanned(mask, type))
545                         return true;
546
547                 if (this->IsExtBanned(user->GetFullHost(), type))
548                         return true;
549
550                 if (this->IsExtBanned(user->GetFullRealHost(), type))
551                         return true;
552         }
553
554         return false;
555 }
556
557 /* Channel::PartUser
558  * remove a channel from a users record, and return the number of users left.
559  * Therefore, if this function returns 0 the caller should delete the Channel.
560  *
561  * XXX: bleh, string copy of reason, fixme! -- w00t
562  */
563 long Channel::PartUser(User *user, std::string &reason)
564 {
565         bool silent = false;
566
567         if (!user)
568                 return this->GetUserCounter();
569
570         UCListIter i = user->chans.find(this);
571         if (i != user->chans.end())
572         {
573                 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason, silent));
574
575                 if (!silent)
576                         this->WriteChannel(user, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str());
577
578                 user->chans.erase(i);
579                 this->RemoveAllPrefixes(user);
580         }
581
582         if (!this->DelUser(user)) /* if there are no users left on the channel... */
583         {
584                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
585                 /* kill the record */
586                 if (iter != ServerInstance->chanlist->end())
587                 {
588                         int MOD_RESULT = 0;
589                         FOREACH_RESULT_I(ServerInstance,I_OnChannelPreDelete, OnChannelPreDelete(this));
590                         if (MOD_RESULT == 1)
591                                 return 1; // delete halted by module
592                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
593                         ServerInstance->chanlist->erase(iter);
594                 }
595                 return 0;
596         }
597
598         return this->GetUserCounter();
599 }
600
601 long Channel::ServerKickUser(User* user, const char* reason, bool triggerevents, const char* servername)
602 {
603         bool silent = false;
604
605         if (!user || !reason)
606                 return this->GetUserCounter();
607
608         if (IS_LOCAL(user))
609         {
610                 if (!this->HasUser(user))
611                 {
612                         /* Not on channel */
613                         return this->GetUserCounter();
614                 }
615         }
616
617         if (servername == NULL || *ServerInstance->Config->HideWhoisServer)
618                 servername = ServerInstance->Config->ServerName;
619
620         if (triggerevents)
621         {
622                 FOREACH_MOD(I_OnUserKick,OnUserKick(NULL, user, this, reason, silent));
623         }
624
625         UCListIter i = user->chans.find(this);
626         if (i != user->chans.end())
627         {
628                 if (!silent)
629                         this->WriteChannelWithServ(servername, "KICK %s %s :%s", this->name.c_str(), user->nick.c_str(), reason);
630
631                 user->chans.erase(i);
632                 this->RemoveAllPrefixes(user);
633         }
634
635         if (!this->DelUser(user))
636         {
637                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
638                 /* kill the record */
639                 if (iter != ServerInstance->chanlist->end())
640                 {
641                         int MOD_RESULT = 0;
642                         FOREACH_RESULT_I(ServerInstance,I_OnChannelPreDelete, OnChannelPreDelete(this));
643                         if (MOD_RESULT == 1)
644                                 return 1; // delete halted by module
645                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
646                         ServerInstance->chanlist->erase(iter);
647                 }
648                 return 0;
649         }
650
651         return this->GetUserCounter();
652 }
653
654 long Channel::KickUser(User *src, User *user, const char* reason)
655 {
656         bool silent = false;
657
658         if (!src || !user || !reason)
659                 return this->GetUserCounter();
660
661         if (IS_LOCAL(src))
662         {
663                 if (!this->HasUser(user))
664                 {
665                         src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), user->nick.c_str(), this->name.c_str());
666                         return this->GetUserCounter();
667                 }
668                 if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))
669                 {
670                         src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only a u-line may kick a u-line from a channel.",src->nick.c_str(), this->name.c_str());
671                         return this->GetUserCounter();
672                 }
673                 int MOD_RESULT = 0;
674
675                 if (!ServerInstance->ULine(src->server))
676                 {
677                         MOD_RESULT = 0;
678                         FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));
679                         if (MOD_RESULT == 1)
680                                 return this->GetUserCounter();
681                 }
682                 /* Set to -1 by OnUserPreKick if explicit allow was set */
683                 if (MOD_RESULT != -1)
684                 {
685                         FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));
686                         if ((MOD_RESULT == ACR_DENY) && (!ServerInstance->ULine(src->server)))
687                                 return this->GetUserCounter();
688
689                         if ((MOD_RESULT == ACR_DEFAULT) || (!ServerInstance->ULine(src->server)))
690                         {
691                                 int them = this->GetStatus(src);
692                                 int us = this->GetStatus(user);
693                                 if ((them < STATUS_HOP) || (them < us))
694                                 {
695                                         src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",src->nick.c_str(), this->name.c_str(), them == STATUS_HOP ? "" : "half-");
696                                         return this->GetUserCounter();
697                                 }
698                         }
699                 }
700         }
701
702         FOREACH_MOD(I_OnUserKick,OnUserKick(src, user, this, reason, silent));
703
704         UCListIter i = user->chans.find(this);
705         if (i != user->chans.end())
706         {
707                 /* zap it from the channel list of the user */
708                 if (!silent)
709                         this->WriteChannel(src, "KICK %s %s :%s", this->name.c_str(), user->nick.c_str(), reason);
710
711                 user->chans.erase(i);
712                 this->RemoveAllPrefixes(user);
713         }
714
715         if (!this->DelUser(user))
716         /* if there are no users left on the channel */
717         {
718                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name.c_str());
719
720                 /* kill the record */
721                 if (iter != ServerInstance->chanlist->end())
722                 {
723                         int MOD_RESULT = 0;
724                         FOREACH_RESULT_I(ServerInstance,I_OnChannelPreDelete, OnChannelPreDelete(this));
725                         if (MOD_RESULT == 1)
726                                 return 1; // delete halted by module
727                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
728                         ServerInstance->chanlist->erase(iter);
729                 }
730                 return 0;
731         }
732
733         return this->GetUserCounter();
734 }
735
736 void Channel::WriteChannel(User* user, const char* text, ...)
737 {
738         char textbuffer[MAXBUF];
739         va_list argsPtr;
740
741         if (!user || !text)
742                 return;
743
744         va_start(argsPtr, text);
745         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
746         va_end(argsPtr);
747
748         this->WriteChannel(user, std::string(textbuffer));
749 }
750
751 void Channel::WriteChannel(User* user, const std::string &text)
752 {
753         CUList *ulist = this->GetUsers();
754         char tb[MAXBUF];
755
756         if (!user)
757                 return;
758
759         snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str());
760         std::string out = tb;
761
762         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
763         {
764                 if (IS_LOCAL(i->first))
765                         i->first->Write(out);
766         }
767 }
768
769 void Channel::WriteChannelWithServ(const char* ServName, const char* text, ...)
770 {
771         char textbuffer[MAXBUF];
772         va_list argsPtr;
773
774         if (!text)
775                 return;
776
777         va_start(argsPtr, text);
778         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
779         va_end(argsPtr);
780
781         this->WriteChannelWithServ(ServName, std::string(textbuffer));
782 }
783
784 void Channel::WriteChannelWithServ(const char* ServName, const std::string &text)
785 {
786         CUList *ulist = this->GetUsers();
787         char tb[MAXBUF];
788
789         snprintf(tb,MAXBUF,":%s %s", ServName ? ServName : ServerInstance->Config->ServerName, text.c_str());
790         std::string out = tb;
791
792         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
793         {
794                 if (IS_LOCAL(i->first))
795                         i->first->Write(out);
796         }
797 }
798
799 /* write formatted text from a source user to all users on a channel except
800  * for the sender (for privmsg etc) */
801 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const char* text, ...)
802 {
803         char textbuffer[MAXBUF];
804         va_list argsPtr;
805
806         if (!text)
807                 return;
808
809         va_start(argsPtr, text);
810         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
811         va_end(argsPtr);
812
813         this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer));
814 }
815
816 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...)
817 {
818         char textbuffer[MAXBUF];
819         va_list argsPtr;
820
821         if (!text)
822                 return;
823
824         va_start(argsPtr, text);
825         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
826         va_end(argsPtr);
827
828         this->WriteAllExcept(user, serversource, status, except_list, std::string(textbuffer));
829 }
830
831 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &text)
832 {
833         CUList *ulist = this->GetUsers();
834         char tb[MAXBUF];
835
836         snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str());
837         std::string out = tb;
838
839         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
840         {
841                 if ((IS_LOCAL(i->first)) && (except_list.find(i->first) == except_list.end()))
842                 {
843                         /* User doesnt have the status we're after */
844                         if (status && !strchr(this->GetAllPrefixChars(i->first), status))
845                                 continue;
846
847                         if (serversource)
848                                 i->first->WriteServ(text);
849                         else
850                                 i->first->Write(out);
851                 }
852         }
853 }
854
855 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const std::string& text)
856 {
857         CUList except_list;
858         except_list[user] = user->nick;
859         this->WriteAllExcept(user, serversource, status, except_list, std::string(text));
860 }
861
862 /*
863  * return a count of the users on a specific channel accounting for
864  * invisible users who won't increase the count. e.g. for /LIST
865  */
866 int Channel::CountInvisible()
867 {
868         int count = 0;
869         CUList *ulist= this->GetUsers();
870         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
871         {
872                 if (!(i->first->IsModeSet('i')))
873                         count++;
874         }
875
876         return count;
877 }
878
879 char* Channel::ChanModes(bool showkey)
880 {
881         static char scratch[MAXBUF];
882         static char sparam[MAXBUF];
883         char* offset = scratch;
884         std::string extparam;
885
886         *scratch = '\0';
887         *sparam = '\0';
888
889         /* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */
890         for(int n = 0; n < 64; n++)
891         {
892                 if(this->modes[n])
893                 {
894                         *offset++ = n + 65;
895                         extparam.clear();
896                         switch (n)
897                         {
898                                 case CM_KEY:
899                                         // Unfortunately this must be special-cased, as we definitely don't want to always display key.
900                                         if (showkey)
901                                         {
902                                                 extparam = this->GetModeParameter('k');
903                                         }
904                                         else
905                                         {
906                                                 extparam = "<key>";
907                                         }
908                                         break;
909                                 case CM_NOEXTERNAL:
910                                 case CM_TOPICLOCK:
911                                 case CM_INVITEONLY:
912                                 case CM_MODERATED:
913                                 case CM_SECRET:
914                                 case CM_PRIVATE:
915                                         /* We know these have no parameters */
916                                 break;
917                                 default:
918                                         extparam = this->GetModeParameter(n + 65);
919                                 break;
920                         }
921                         if (!extparam.empty())
922                         {
923                                 charlcat(sparam,' ',MAXBUF);
924                                 strlcat(sparam,extparam.c_str(),MAXBUF);
925                         }
926                 }
927         }
928
929         /* Null terminate scratch */
930         *offset = '\0';
931         strlcat(scratch,sparam,MAXBUF);
932         return scratch;
933 }
934
935 /* compile a userlist of a channel into a string, each nick seperated by
936  * spaces and op, voice etc status shown as @ and +, and send it to 'user'
937  */
938 void Channel::UserList(User *user, CUList *ulist)
939 {
940         char list[MAXBUF];
941         size_t dlen, curlen;
942         int MOD_RESULT = 0;
943         bool call_modules = true;
944
945         if (!IS_LOCAL(user))
946                 return;
947
948         FOREACH_RESULT(I_OnUserList,OnUserList(user, this, ulist));
949         if (MOD_RESULT == 1)
950                 call_modules = false;
951
952         if (MOD_RESULT != -1)
953         {
954                 if ((this->IsModeSet('s')) && (!this->HasUser(user)))
955                 {
956                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
957                         return;
958                 }
959         }
960
961         dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=',  this->name.c_str());
962
963         int numusers = 0;
964         char* ptr = list + dlen;
965
966         if (!ulist)
967                 ulist = this->GetUsers();
968
969         /* Improvement by Brain - this doesnt change in value, so why was it inside
970          * the loop?
971          */
972         bool has_user = this->HasUser(user);
973
974         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
975         {
976                 if ((!has_user) && (i->first->IsModeSet('i')))
977                 {
978                         /*
979                          * user is +i, and source not on the channel, does not show
980                          * nick in NAMES list
981                          */
982                         continue;
983                 }
984
985                 if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))
986                         continue;
987
988                 std::string prefixlist = this->GetPrefixChar(i->first);
989                 std::string nick = i->first->nick;
990
991                 if (call_modules)
992                 {
993                         FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->first, this, prefixlist, nick));
994
995                         /* Nick was nuked, a module wants us to skip it */
996                         if (nick.empty())
997                                 continue;
998                 }
999
1000                 size_t ptrlen = 0;
1001
1002                 if (curlen + prefixlist.length() + nick.length() + 1 > 480)
1003                 {
1004                         /* list overflowed into multiple numerics */
1005                         user->WriteServ(std::string(list));
1006
1007                         /* reset our lengths */
1008                         dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
1009                         ptr = list + dlen;
1010
1011                         ptrlen = 0;
1012                         numusers = 0;
1013                 }
1014
1015                 ptrlen = snprintf(ptr, MAXBUF, "%s%s ", prefixlist.c_str(), nick.c_str());
1016
1017                 curlen += ptrlen;
1018                 ptr += ptrlen;
1019
1020                 numusers++;
1021         }
1022
1023         /* if whats left in the list isnt empty, send it */
1024         if (numusers)
1025         {
1026                 user->WriteNumeric(RPL_NAMREPLY, std::string(list));
1027         }
1028
1029         user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
1030 }
1031
1032 long Channel::GetMaxBans()
1033 {
1034         /* Return the cached value if there is one */
1035         if (this->maxbans)
1036                 return this->maxbans;
1037
1038         /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */
1039         for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
1040         {
1041                 if (match(this->name,n->first))
1042                 {
1043                         this->maxbans = n->second;
1044                         return n->second;
1045                 }
1046         }
1047
1048         /* Screw it, just return the default of 64 */
1049         this->maxbans = 64;
1050         return this->maxbans;
1051 }
1052
1053 void Channel::ResetMaxBans()
1054 {
1055         this->maxbans = 0;
1056 }
1057
1058 /* returns the status character for a given user on a channel, e.g. @ for op,
1059  * % for halfop etc. If the user has several modes set, the highest mode
1060  * the user has must be returned.
1061  */
1062 const char* Channel::GetPrefixChar(User *user)
1063 {
1064         static char pf[2] = {0, 0};
1065
1066         prefixlist::iterator n = prefixes.find(user);
1067         if (n != prefixes.end())
1068         {
1069                 if (n->second.size())
1070                 {
1071                         /* If the user has any prefixes, their highest prefix
1072                          * will always be at the head of the list, as the list is
1073                          * sorted in rank order highest first (see SetPrefix()
1074                          * for reasons why)
1075                          */
1076                         *pf = n->second.begin()->first;
1077                         return pf;
1078                 }
1079         }
1080
1081         *pf = 0;
1082         return pf;
1083 }
1084
1085
1086 const char* Channel::GetAllPrefixChars(User* user)
1087 {
1088         static char prefix[MAXBUF];
1089         int ctr = 0;
1090         *prefix = 0;
1091
1092         prefixlist::iterator n = prefixes.find(user);
1093         if (n != prefixes.end())
1094         {
1095                 for (std::vector<prefixtype>::iterator x = n->second.begin(); x != n->second.end(); x++)
1096                 {
1097                         prefix[ctr++] = x->first;
1098                 }
1099         }
1100
1101         prefix[ctr] = 0;
1102
1103         return prefix;
1104 }
1105
1106 unsigned int Channel::GetPrefixValue(User* user)
1107 {
1108         prefixlist::iterator n = prefixes.find(user);
1109         if (n != prefixes.end())
1110         {
1111                 if (n->second.size())
1112                         return n->second.begin()->second;
1113         }
1114         return 0;
1115 }
1116
1117 int Channel::GetStatusFlags(User *user)
1118 {
1119         UCListIter i = user->chans.find(this);
1120         if (i != user->chans.end())
1121         {
1122                 return i->second;
1123         }
1124         return 0;
1125 }
1126
1127 int Channel::GetStatus(User *user)
1128 {
1129         if (ServerInstance->ULine(user->server))
1130                 return STATUS_OP;
1131
1132         UCListIter i = user->chans.find(this);
1133         if (i != user->chans.end())
1134         {
1135                 if ((i->second & UCMODE_OP) > 0)
1136                 {
1137                         return STATUS_OP;
1138                 }
1139                 if ((i->second & UCMODE_HOP) > 0)
1140                 {
1141                         return STATUS_HOP;
1142                 }
1143                 if ((i->second & UCMODE_VOICE) > 0)
1144                 {
1145                         return STATUS_VOICE;
1146                 }
1147                 return STATUS_NORMAL;
1148         }
1149         return STATUS_NORMAL;
1150 }
1151
1152 void Channel::SetPrefix(User* user, char prefix, unsigned int prefix_value, bool adding)
1153 {
1154         prefixlist::iterator n = prefixes.find(user);
1155         prefixtype pfx = std::make_pair(prefix,prefix_value);
1156         if (adding)
1157         {
1158                 if (n != prefixes.end())
1159                 {
1160                         if (std::find(n->second.begin(), n->second.end(), pfx) == n->second.end())
1161                         {
1162                                 n->second.push_back(pfx);
1163                                 /* We must keep prefixes in rank order, largest first.
1164                                  * This is for two reasons, firstly because x-chat *ass-u-me's* this
1165                                  * state, and secondly it turns out to be a benefit to us later.
1166                                  * See above in GetPrefix().
1167                                  */
1168                                 std::sort(n->second.begin(), n->second.end(), ModeParser::PrefixComparison);
1169                         }
1170                 }
1171                 else
1172                 {
1173                         pfxcontainer one;
1174                         one.push_back(pfx);
1175                         prefixes.insert(std::make_pair<User*,pfxcontainer>(user, one));
1176                 }
1177         }
1178         else
1179         {
1180                 if (n != prefixes.end())
1181                 {
1182                         pfxcontainer::iterator x = std::find(n->second.begin(), n->second.end(), pfx);
1183                         if (x != n->second.end())
1184                                 n->second.erase(x);
1185                 }
1186         }
1187 }
1188
1189 void Channel::RemoveAllPrefixes(User* user)
1190 {
1191         prefixlist::iterator n = prefixes.find(user);
1192         if (n != prefixes.end())
1193         {
1194                 prefixes.erase(n);
1195         }
1196 }
1197