]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/channels.cpp
Correct this error message to confuse people less.
[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 (user->HasPrivPermission("channels/high-join-limit"))
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 long Channel::PartUser(User *user, std::string &reason)
568 {
569         bool silent = false;
570
571         if (!user)
572                 return this->GetUserCounter();
573
574         UCListIter i = user->chans.find(this);
575         if (i != user->chans.end())
576         {
577                 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason, silent));
578
579                 if (!silent)
580                         this->WriteChannel(user, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str());
581
582                 user->chans.erase(i);
583                 this->RemoveAllPrefixes(user);
584         }
585
586         if (!this->DelUser(user)) /* if there are no users left on the channel... */
587         {
588                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
589                 /* kill the record */
590                 if (iter != ServerInstance->chanlist->end())
591                 {
592                         int MOD_RESULT = 0;
593                         FOREACH_RESULT_I(ServerInstance,I_OnChannelPreDelete, OnChannelPreDelete(this));
594                         if (MOD_RESULT == 1)
595                                 return 1; // delete halted by module
596                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
597                         ServerInstance->chanlist->erase(iter);
598                 }
599                 return 0;
600         }
601
602         return this->GetUserCounter();
603 }
604
605 long Channel::ServerKickUser(User* user, const char* reason, bool triggerevents, const char* servername)
606 {
607         bool silent = false;
608
609         if (!user || !reason)
610                 return this->GetUserCounter();
611
612         if (IS_LOCAL(user))
613         {
614                 if (!this->HasUser(user))
615                 {
616                         /* Not on channel */
617                         return this->GetUserCounter();
618                 }
619         }
620
621         if (servername == NULL || *ServerInstance->Config->HideWhoisServer)
622                 servername = ServerInstance->Config->ServerName;
623
624         if (triggerevents)
625         {
626                 FOREACH_MOD(I_OnUserKick,OnUserKick(NULL, user, this, reason, silent));
627         }
628
629         UCListIter i = user->chans.find(this);
630         if (i != user->chans.end())
631         {
632                 if (!silent)
633                         this->WriteChannelWithServ(servername, "KICK %s %s :%s", this->name.c_str(), user->nick.c_str(), reason);
634
635                 user->chans.erase(i);
636                 this->RemoveAllPrefixes(user);
637         }
638
639         if (!this->DelUser(user))
640         {
641                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
642                 /* kill the record */
643                 if (iter != ServerInstance->chanlist->end())
644                 {
645                         int MOD_RESULT = 0;
646                         FOREACH_RESULT_I(ServerInstance,I_OnChannelPreDelete, OnChannelPreDelete(this));
647                         if (MOD_RESULT == 1)
648                                 return 1; // delete halted by module
649                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
650                         ServerInstance->chanlist->erase(iter);
651                 }
652                 return 0;
653         }
654
655         return this->GetUserCounter();
656 }
657
658 long Channel::KickUser(User *src, User *user, const char* reason)
659 {
660         bool silent = false;
661
662         if (!src || !user || !reason)
663                 return this->GetUserCounter();
664
665         if (IS_LOCAL(src))
666         {
667                 if (!this->HasUser(user))
668                 {
669                         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());
670                         return this->GetUserCounter();
671                 }
672                 if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))
673                 {
674                         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());
675                         return this->GetUserCounter();
676                 }
677                 int MOD_RESULT = 0;
678
679                 if (!ServerInstance->ULine(src->server))
680                 {
681                         MOD_RESULT = 0;
682                         FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));
683                         if (MOD_RESULT == 1)
684                                 return this->GetUserCounter();
685                 }
686                 /* Set to -1 by OnUserPreKick if explicit allow was set */
687                 if (MOD_RESULT != -1)
688                 {
689                         FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));
690                         if ((MOD_RESULT == ACR_DENY) && (!ServerInstance->ULine(src->server)))
691                                 return this->GetUserCounter();
692
693                         if ((MOD_RESULT == ACR_DEFAULT) || (!ServerInstance->ULine(src->server)))
694                         {
695                                 int them = this->GetStatus(src);
696                                 int us = this->GetStatus(user);
697                                 if ((them < STATUS_HOP) || (them < us))
698                                 {
699                                         src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",src->nick.c_str(), this->name.c_str(), them == STATUS_HOP ? "" : "half-");
700                                         return this->GetUserCounter();
701                                 }
702                         }
703                 }
704         }
705
706         FOREACH_MOD(I_OnUserKick,OnUserKick(src, user, this, reason, silent));
707
708         UCListIter i = user->chans.find(this);
709         if (i != user->chans.end())
710         {
711                 /* zap it from the channel list of the user */
712                 if (!silent)
713                         this->WriteChannel(src, "KICK %s %s :%s", this->name.c_str(), user->nick.c_str(), reason);
714
715                 user->chans.erase(i);
716                 this->RemoveAllPrefixes(user);
717         }
718
719         if (!this->DelUser(user))
720         /* if there are no users left on the channel */
721         {
722                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name.c_str());
723
724                 /* kill the record */
725                 if (iter != ServerInstance->chanlist->end())
726                 {
727                         int MOD_RESULT = 0;
728                         FOREACH_RESULT_I(ServerInstance,I_OnChannelPreDelete, OnChannelPreDelete(this));
729                         if (MOD_RESULT == 1)
730                                 return 1; // delete halted by module
731                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
732                         ServerInstance->chanlist->erase(iter);
733                 }
734                 return 0;
735         }
736
737         return this->GetUserCounter();
738 }
739
740 void Channel::WriteChannel(User* user, const char* text, ...)
741 {
742         char textbuffer[MAXBUF];
743         va_list argsPtr;
744
745         if (!user || !text)
746                 return;
747
748         va_start(argsPtr, text);
749         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
750         va_end(argsPtr);
751
752         this->WriteChannel(user, std::string(textbuffer));
753 }
754
755 void Channel::WriteChannel(User* user, const std::string &text)
756 {
757         CUList *ulist = this->GetUsers();
758         char tb[MAXBUF];
759
760         if (!user)
761                 return;
762
763         snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str());
764         std::string out = tb;
765
766         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
767         {
768                 if (IS_LOCAL(i->first))
769                         i->first->Write(out);
770         }
771 }
772
773 void Channel::WriteChannelWithServ(const char* ServName, const char* text, ...)
774 {
775         char textbuffer[MAXBUF];
776         va_list argsPtr;
777
778         if (!text)
779                 return;
780
781         va_start(argsPtr, text);
782         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
783         va_end(argsPtr);
784
785         this->WriteChannelWithServ(ServName, std::string(textbuffer));
786 }
787
788 void Channel::WriteChannelWithServ(const char* ServName, const std::string &text)
789 {
790         CUList *ulist = this->GetUsers();
791         char tb[MAXBUF];
792
793         snprintf(tb,MAXBUF,":%s %s", ServName ? ServName : ServerInstance->Config->ServerName, text.c_str());
794         std::string out = tb;
795
796         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
797         {
798                 if (IS_LOCAL(i->first))
799                         i->first->Write(out);
800         }
801 }
802
803 /* write formatted text from a source user to all users on a channel except
804  * for the sender (for privmsg etc) */
805 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const char* text, ...)
806 {
807         char textbuffer[MAXBUF];
808         va_list argsPtr;
809
810         if (!text)
811                 return;
812
813         va_start(argsPtr, text);
814         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
815         va_end(argsPtr);
816
817         this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer));
818 }
819
820 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...)
821 {
822         char textbuffer[MAXBUF];
823         va_list argsPtr;
824
825         if (!text)
826                 return;
827
828         va_start(argsPtr, text);
829         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
830         va_end(argsPtr);
831
832         this->WriteAllExcept(user, serversource, status, except_list, std::string(textbuffer));
833 }
834
835 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &text)
836 {
837         CUList *ulist = this->GetUsers();
838         char tb[MAXBUF];
839
840         snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str());
841         std::string out = tb;
842
843         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
844         {
845                 if ((IS_LOCAL(i->first)) && (except_list.find(i->first) == except_list.end()))
846                 {
847                         /* User doesnt have the status we're after */
848                         if (status && !strchr(this->GetAllPrefixChars(i->first), status))
849                                 continue;
850
851                         if (serversource)
852                                 i->first->WriteServ(text);
853                         else
854                                 i->first->Write(out);
855                 }
856         }
857 }
858
859 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const std::string& text)
860 {
861         CUList except_list;
862         except_list[user] = user->nick;
863         this->WriteAllExcept(user, serversource, status, except_list, std::string(text));
864 }
865
866 /*
867  * return a count of the users on a specific channel accounting for
868  * invisible users who won't increase the count. e.g. for /LIST
869  */
870 int Channel::CountInvisible()
871 {
872         int count = 0;
873         CUList *ulist= this->GetUsers();
874         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
875         {
876                 if (!(i->first->IsModeSet('i')))
877                         count++;
878         }
879
880         return count;
881 }
882
883 char* Channel::ChanModes(bool showkey)
884 {
885         static char scratch[MAXBUF];
886         static char sparam[MAXBUF];
887         char* offset = scratch;
888         std::string extparam;
889
890         *scratch = '\0';
891         *sparam = '\0';
892
893         /* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */
894         for(int n = 0; n < 64; n++)
895         {
896                 if(this->modes[n])
897                 {
898                         *offset++ = n + 65;
899                         extparam.clear();
900                         switch (n)
901                         {
902                                 case CM_KEY:
903                                         // Unfortunately this must be special-cased, as we definitely don't want to always display key.
904                                         if (showkey)
905                                         {
906                                                 extparam = this->GetModeParameter('k');
907                                         }
908                                         else
909                                         {
910                                                 extparam = "<key>";
911                                         }
912                                         break;
913                                 case CM_NOEXTERNAL:
914                                 case CM_TOPICLOCK:
915                                 case CM_INVITEONLY:
916                                 case CM_MODERATED:
917                                 case CM_SECRET:
918                                 case CM_PRIVATE:
919                                         /* We know these have no parameters */
920                                 break;
921                                 default:
922                                         extparam = this->GetModeParameter(n + 65);
923                                 break;
924                         }
925                         if (!extparam.empty())
926                         {
927                                 charlcat(sparam,' ',MAXBUF);
928                                 strlcat(sparam,extparam.c_str(),MAXBUF);
929                         }
930                 }
931         }
932
933         /* Null terminate scratch */
934         *offset = '\0';
935         strlcat(scratch,sparam,MAXBUF);
936         return scratch;
937 }
938
939 /* compile a userlist of a channel into a string, each nick seperated by
940  * spaces and op, voice etc status shown as @ and +, and send it to 'user'
941  */
942 void Channel::UserList(User *user, CUList *ulist)
943 {
944         char list[MAXBUF];
945         size_t dlen, curlen;
946         int MOD_RESULT = 0;
947         bool call_modules = true;
948
949         if (!IS_LOCAL(user))
950                 return;
951
952         FOREACH_RESULT(I_OnUserList,OnUserList(user, this, ulist));
953         if (MOD_RESULT == 1)
954                 call_modules = false;
955
956         if (MOD_RESULT != -1)
957         {
958                 if ((this->IsModeSet('s')) && (!this->HasUser(user)))
959                 {
960                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
961                         return;
962                 }
963         }
964
965         dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=',  this->name.c_str());
966
967         int numusers = 0;
968         char* ptr = list + dlen;
969
970         if (!ulist)
971                 ulist = this->GetUsers();
972
973         /* Improvement by Brain - this doesnt change in value, so why was it inside
974          * the loop?
975          */
976         bool has_user = this->HasUser(user);
977
978         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
979         {
980                 if ((!has_user) && (i->first->IsModeSet('i')))
981                 {
982                         /*
983                          * user is +i, and source not on the channel, does not show
984                          * nick in NAMES list
985                          */
986                         continue;
987                 }
988
989                 if (i->first->Visibility && !i->first->Visibility->VisibleTo(user))
990                         continue;
991
992                 std::string prefixlist = this->GetPrefixChar(i->first);
993                 std::string nick = i->first->nick;
994
995                 if (call_modules)
996                 {
997                         FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->first, this, prefixlist, nick));
998
999                         /* Nick was nuked, a module wants us to skip it */
1000                         if (nick.empty())
1001                                 continue;
1002                 }
1003
1004                 size_t ptrlen = 0;
1005
1006                 if (curlen + prefixlist.length() + nick.length() + 1 > 480)
1007                 {
1008                         /* list overflowed into multiple numerics */
1009                         user->WriteNumeric(RPL_NAMREPLY, std::string(list));
1010
1011                         /* reset our lengths */
1012                         dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
1013                         ptr = list + dlen;
1014
1015                         ptrlen = 0;
1016                         numusers = 0;
1017                 }
1018
1019                 ptrlen = snprintf(ptr, MAXBUF, "%s%s ", prefixlist.c_str(), nick.c_str());
1020
1021                 curlen += ptrlen;
1022                 ptr += ptrlen;
1023
1024                 numusers++;
1025         }
1026
1027         /* if whats left in the list isnt empty, send it */
1028         if (numusers)
1029         {
1030                 user->WriteNumeric(RPL_NAMREPLY, std::string(list));
1031         }
1032
1033         user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
1034 }
1035
1036 long Channel::GetMaxBans()
1037 {
1038         /* Return the cached value if there is one */
1039         if (this->maxbans)
1040                 return this->maxbans;
1041
1042         /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */
1043         for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
1044         {
1045                 if (InspIRCd::Match(this->name, n->first, NULL))
1046                 {
1047                         this->maxbans = n->second;
1048                         return n->second;
1049                 }
1050         }
1051
1052         /* Screw it, just return the default of 64 */
1053         this->maxbans = 64;
1054         return this->maxbans;
1055 }
1056
1057 void Channel::ResetMaxBans()
1058 {
1059         this->maxbans = 0;
1060 }
1061
1062 /* returns the status character for a given user on a channel, e.g. @ for op,
1063  * % for halfop etc. If the user has several modes set, the highest mode
1064  * the user has must be returned.
1065  */
1066 const char* Channel::GetPrefixChar(User *user)
1067 {
1068         static char pf[2] = {0, 0};
1069
1070         prefixlist::iterator n = prefixes.find(user);
1071         if (n != prefixes.end())
1072         {
1073                 if (n->second.size())
1074                 {
1075                         /* If the user has any prefixes, their highest prefix
1076                          * will always be at the head of the list, as the list is
1077                          * sorted in rank order highest first (see SetPrefix()
1078                          * for reasons why)
1079                          */
1080                         *pf = n->second.begin()->first;
1081                         return pf;
1082                 }
1083         }
1084
1085         *pf = 0;
1086         return pf;
1087 }
1088
1089
1090 const char* Channel::GetAllPrefixChars(User* user)
1091 {
1092         static char prefix[MAXBUF];
1093         int ctr = 0;
1094         *prefix = 0;
1095
1096         prefixlist::iterator n = prefixes.find(user);
1097         if (n != prefixes.end())
1098         {
1099                 for (std::vector<prefixtype>::iterator x = n->second.begin(); x != n->second.end(); x++)
1100                 {
1101                         prefix[ctr++] = x->first;
1102                 }
1103         }
1104
1105         prefix[ctr] = 0;
1106
1107         return prefix;
1108 }
1109
1110 unsigned int Channel::GetPrefixValue(User* user)
1111 {
1112         prefixlist::iterator n = prefixes.find(user);
1113         if (n != prefixes.end())
1114         {
1115                 if (n->second.size())
1116                         return n->second.begin()->second;
1117         }
1118         return 0;
1119 }
1120
1121 int Channel::GetStatusFlags(User *user)
1122 {
1123         UCListIter i = user->chans.find(this);
1124         if (i != user->chans.end())
1125         {
1126                 return i->second;
1127         }
1128         return 0;
1129 }
1130
1131 int Channel::GetStatus(User *user)
1132 {
1133         if (ServerInstance->ULine(user->server))
1134                 return STATUS_OP;
1135
1136         UCListIter i = user->chans.find(this);
1137         if (i != user->chans.end())
1138         {
1139                 if ((i->second & UCMODE_OP) > 0)
1140                 {
1141                         return STATUS_OP;
1142                 }
1143                 if ((i->second & UCMODE_HOP) > 0)
1144                 {
1145                         return STATUS_HOP;
1146                 }
1147                 if ((i->second & UCMODE_VOICE) > 0)
1148                 {
1149                         return STATUS_VOICE;
1150                 }
1151                 return STATUS_NORMAL;
1152         }
1153         return STATUS_NORMAL;
1154 }
1155
1156 void Channel::SetPrefix(User* user, char prefix, unsigned int prefix_value, bool adding)
1157 {
1158         prefixlist::iterator n = prefixes.find(user);
1159         prefixtype pfx = std::make_pair(prefix,prefix_value);
1160         if (adding)
1161         {
1162                 if (n != prefixes.end())
1163                 {
1164                         if (std::find(n->second.begin(), n->second.end(), pfx) == n->second.end())
1165                         {
1166                                 n->second.push_back(pfx);
1167                                 /* We must keep prefixes in rank order, largest first.
1168                                  * This is for two reasons, firstly because x-chat *ass-u-me's* this
1169                                  * state, and secondly it turns out to be a benefit to us later.
1170                                  * See above in GetPrefix().
1171                                  */
1172                                 std::sort(n->second.begin(), n->second.end(), ModeParser::PrefixComparison);
1173                         }
1174                 }
1175                 else
1176                 {
1177                         pfxcontainer one;
1178                         one.push_back(pfx);
1179                         prefixes.insert(std::make_pair<User*,pfxcontainer>(user, one));
1180                 }
1181         }
1182         else
1183         {
1184                 if (n != prefixes.end())
1185                 {
1186                         pfxcontainer::iterator x = std::find(n->second.begin(), n->second.end(), pfx);
1187                         if (x != n->second.end())
1188                                 n->second.erase(x);
1189                 }
1190         }
1191 }
1192
1193 void Channel::RemoveAllPrefixes(User* user)
1194 {
1195         prefixlist::iterator n = prefixes.find(user);
1196         if (n != prefixes.end())
1197         {
1198                 prefixes.erase(n);
1199         }
1200 }
1201