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