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