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