]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/channels.cpp
Fix kick level check to scan all status modes and not skip checks for modeless users
[user/henk/code/inspircd.git] / src / channels.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/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(const std::string &cname, time_t ts)
21 {
22         chan_hash::iterator findchan = ServerInstance->chanlist->find(cname);
23         if (findchan != ServerInstance->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->age = ts ? ts : ServerInstance->Time();
29
30         maxbans = topicset = 0;
31         modes.reset();
32 }
33
34 void Channel::SetMode(char mode,bool mode_on)
35 {
36         modes[mode-65] = mode_on;
37 }
38
39 void Channel::SetMode(ModeHandler* mh, bool on)
40 {
41         modes[mh->GetModeChar() - 65] = on;
42 }
43
44 void Channel::SetModeParam(char mode, const std::string& parameter)
45 {
46         CustomModeList::iterator n = custom_mode_params.find(mode);
47         // always erase, even if changing, so that the map gets the new value
48         if (n != custom_mode_params.end())
49                 custom_mode_params.erase(n);
50         if (parameter.empty())
51         {
52                 modes[mode-65] = false;
53         }
54         else
55         {
56                 custom_mode_params[mode] = parameter;
57                 modes[mode-65] = true;
58         }
59 }
60
61 void Channel::SetModeParam(ModeHandler* mode, const std::string& parameter)
62 {
63         SetModeParam(mode->GetModeChar(), parameter);
64 }
65
66 std::string Channel::GetModeParameter(char mode)
67 {
68         CustomModeList::iterator n = custom_mode_params.find(mode);
69         if (n != custom_mode_params.end())
70                 return n->second;
71         return "";
72 }
73
74 std::string Channel::GetModeParameter(ModeHandler* mode)
75 {
76         CustomModeList::iterator n = custom_mode_params.find(mode->GetModeChar());
77         if (n != custom_mode_params.end())
78                 return n->second;
79         return "";
80 }
81
82 int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
83 {
84         if (!u)
85                 u = ServerInstance->FakeClient;
86         if (IS_LOCAL(u) && !forceset)
87         {
88                 ModResult res;
89                 FIRST_MOD_RESULT(OnPreTopicChange, res, (u,this,ntopic));
90
91                 if (res == MOD_RES_DENY)
92                         return CMD_FAILURE;
93                 if (res != MOD_RES_ALLOW)
94                 {
95                         if (!this->HasUser(u))
96                         {
97                                 u->WriteNumeric(442, "%s %s :You're not on that channel!",u->nick.c_str(), this->name.c_str());
98                                 return CMD_FAILURE;
99                         }
100                         if (IsModeSet('t') && !ServerInstance->OnCheckExemption(u,this,"topiclock").check(GetPrefixValue(u) >= HALFOP_VALUE))
101                         {
102                                 u->WriteNumeric(482, "%s %s :You do not have access to change the topic on this channel", u->nick.c_str(), this->name.c_str());
103                                 return CMD_FAILURE;
104                         }
105                 }
106         }
107
108         this->topic.assign(ntopic, 0, ServerInstance->Config->Limits.MaxTopic);
109         if (u)
110         {
111                 this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128);
112                 this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
113         }
114         else
115         {
116                 this->setby.assign(ServerInstance->Config->ServerName);
117                 this->WriteChannelWithServ(ServerInstance->Config->ServerName, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
118         }
119
120         this->topicset = ServerInstance->Time();
121
122         FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic));
123
124         return CMD_SUCCESS;
125 }
126
127 long Channel::GetUserCounter()
128 {
129         return userlist.size();
130 }
131
132 Membership* Channel::AddUser(User* user)
133 {
134         Membership* memb = new Membership(user, this);
135         userlist[user] = memb;
136         return memb;
137 }
138
139 void Channel::DelUser(User* user)
140 {
141         UserMembIter a = userlist.find(user);
142
143         if (a != userlist.end())
144         {
145                 a->second->cull();
146                 delete a->second;
147                 userlist.erase(a);
148         }
149
150         if (userlist.empty())
151         {
152                 ModResult res;
153                 FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
154                 if (res == MOD_RES_DENY)
155                         return;
156                 chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
157                 /* kill the record */
158                 if (iter != ServerInstance->chanlist->end())
159                 {
160                         FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
161                         ServerInstance->chanlist->erase(iter);
162                 }
163                 ServerInstance->GlobalCulls.AddItem(this);
164         }
165 }
166
167 bool Channel::HasUser(User* user)
168 {
169         return (userlist.find(user) != userlist.end());
170 }
171
172 Membership* Channel::GetUser(User* user)
173 {
174         UserMembIter i = userlist.find(user);
175         if (i == userlist.end())
176                 return NULL;
177         return i->second;
178 }
179
180 const UserMembList* Channel::GetUsers()
181 {
182         return &userlist;
183 }
184
185 void Channel::SetDefaultModes()
186 {
187         ServerInstance->Logs->Log("CHANNELS", DEBUG, "SetDefaultModes %s",
188                 ServerInstance->Config->DefaultModes.c_str());
189         irc::spacesepstream list(ServerInstance->Config->DefaultModes);
190         std::string modeseq;
191         std::string parameter;
192
193         list.GetToken(modeseq);
194
195         for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n)
196         {
197                 ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
198                 if (mode)
199                 {
200                         if (mode->GetNumParams(true))
201                                 list.GetToken(parameter);
202                         else
203                                 parameter.clear();
204
205                         mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, parameter, true);
206                 }
207         }
208 }
209
210 /*
211  * add a channel to a user, creating the record for it if needed and linking
212  * it to the user record
213  */
214 Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char* key, bool bursting, time_t TS)
215 {
216         // Fix: unregistered users could be joined using /SAJOIN
217         if (!user || !cn || user->registered != REG_ALL)
218                 return NULL;
219
220         char cname[MAXBUF];
221         std::string privs;
222         Channel *Ptr;
223
224         /*
225          * We don't restrict the number of channels that remote users or users that are override-joining may be in.
226          * We restrict local users to MaxChans channels.
227          * We restrict local operators to OperMaxChans channels.
228          * This is a lot more logical than how it was formerly. -- w00t
229          */
230         if (IS_LOCAL(user) && !override)
231         {
232                 if (user->HasPrivPermission("channels/high-join-limit"))
233                 {
234                         if (user->chans.size() >= ServerInstance->Config->OperMaxChans)
235                         {
236                                 user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
237                                 return NULL;
238                         }
239                 }
240                 else
241                 {
242                         unsigned int maxchans = user->GetClass()->maxchans;
243                         if (!maxchans)
244                                 maxchans = ServerInstance->Config->MaxChans;
245                         if (user->chans.size() >= maxchans)
246                         {
247                                 user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cn);
248                                 return NULL;
249                         }
250                 }
251         }
252
253         strlcpy(cname, cn, ServerInstance->Config->Limits.ChanMax);
254         Ptr = ServerInstance->FindChan(cname);
255         bool created_by_local = false;
256
257         if (!Ptr)
258         {
259                 /*
260                  * Fix: desync bug was here, don't set @ on remote users - spanningtree handles their permissions. bug #358. -- w00t
261                  */
262                 if (!IS_LOCAL(user))
263                 {
264                         if (!TS)
265                                 ServerInstance->Logs->Log("CHANNEL",DEBUG,"*** BUG *** Channel::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick.c_str(), cn);
266                 }
267                 else
268                 {
269                         privs = "o";
270                         created_by_local = true;
271                 }
272
273                 if (IS_LOCAL(user) && override == false)
274                 {
275                         ModResult MOD_RESULT;
276                         FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname, privs, key ? key : ""));
277                         if (MOD_RESULT == MOD_RES_DENY)
278                                 return NULL;
279                 }
280
281                 Ptr = new Channel(cname, TS);
282         }
283         else
284         {
285                 /* Already on the channel */
286                 if (Ptr->HasUser(user))
287                         return NULL;
288
289                 /*
290                  * remote users are allowed us to bypass channel modes
291                  * and bans (used by servers)
292                  */
293                 if (IS_LOCAL(user) && override == false)
294                 {
295                         ModResult MOD_RESULT;
296                         FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, Ptr, cname, privs, key ? key : ""));
297                         if (MOD_RESULT == MOD_RES_DENY)
298                         {
299                                 return NULL;
300                         }
301                         else if (MOD_RESULT == MOD_RES_PASSTHRU)
302                         {
303                                 std::string ckey = Ptr->GetModeParameter('k');
304                                 bool invited = IS_LOCAL(user)->IsInvited(Ptr->name.c_str());
305                                 bool can_bypass = ServerInstance->Config->InvBypassModes && invited;
306
307                                 if (!ckey.empty())
308                                 {
309                                         FIRST_MOD_RESULT(OnCheckKey, MOD_RESULT, (user, Ptr, key ? key : ""));
310                                         if (!MOD_RESULT.check((key && ckey == key) || can_bypass))
311                                         {
312                                                 // If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled)
313                                                 user->WriteNumeric(ERR_BADCHANNELKEY, "%s %s :Cannot join channel (Incorrect channel key)",user->nick.c_str(), Ptr->name.c_str());
314                                                 return NULL;
315                                         }
316                                 }
317
318                                 if (Ptr->IsModeSet('i'))
319                                 {
320                                         FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, Ptr));
321                                         if (!MOD_RESULT.check(invited))
322                                         {
323                                                 user->WriteNumeric(ERR_INVITEONLYCHAN, "%s %s :Cannot join channel (Invite only)",user->nick.c_str(), Ptr->name.c_str());
324                                                 return NULL;
325                                         }
326                                 }
327
328                                 std::string limit = Ptr->GetModeParameter('l');
329                                 if (!limit.empty())
330                                 {
331                                         FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, Ptr));
332                                         if (!MOD_RESULT.check((Ptr->GetUserCounter() < atol(limit.c_str()) || can_bypass)))
333                                         {
334                                                 user->WriteNumeric(ERR_CHANNELISFULL, "%s %s :Cannot join channel (Channel is full)",user->nick.c_str(), Ptr->name.c_str());
335                                                 return NULL;
336                                         }
337                                 }
338
339                                 if (Ptr->IsBanned(user) && !can_bypass)
340                                 {
341                                         user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)",user->nick.c_str(), Ptr->name.c_str());
342                                         return NULL;
343                                 }
344
345                                 /*
346                                  * If the user has invites for this channel, remove them now
347                                  * after a successful join so they don't build up.
348                                  */
349                                 if (invited)
350                                 {
351                                         IS_LOCAL(user)->RemoveInvite(Ptr->name.c_str());
352                                 }
353                         }
354                 }
355         }
356
357         if (created_by_local)
358         {
359                 /* As spotted by jilles, dont bother to set this on remote users */
360                 Ptr->SetDefaultModes();
361         }
362
363         return Channel::ForceChan(Ptr, user, privs, bursting, created_by_local);
364 }
365
366 Channel* Channel::ForceChan(Channel* Ptr, User* user, const std::string &privs, bool bursting, bool created)
367 {
368         std::string nick = user->nick;
369
370         Membership* memb = Ptr->AddUser(user);
371         user->chans.insert(Ptr);
372
373         for (std::string::const_iterator x = privs.begin(); x != privs.end(); x++)
374         {
375                 const char status = *x;
376                 ModeHandler* mh = ServerInstance->Modes->FindMode(status, MODETYPE_CHANNEL);
377                 if (mh)
378                 {
379                         /* Set, and make sure that the mode handler knows this mode was now set */
380                         Ptr->SetPrefix(user, mh->GetModeChar(), true);
381                         mh->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, Ptr, nick, true);
382                 }
383         }
384
385         CUList except_list;
386         FOREACH_MOD(I_OnUserJoin,OnUserJoin(memb, bursting, created, except_list));
387
388         Ptr->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", Ptr->name.c_str());
389
390         /* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */
391         std::string ms = memb->modes;
392         for(unsigned int i=0; i < memb->modes.length(); i++)
393                 ms.append(" ").append(user->nick);
394         if ((Ptr->GetUserCounter() > 1) && (ms.length()))
395                 Ptr->WriteAllExceptSender(user, ServerInstance->Config->CycleHostsFromUser, 0, "MODE %s +%s", Ptr->name.c_str(), ms.c_str());
396
397         if (IS_LOCAL(user))
398         {
399                 if (Ptr->topicset)
400                 {
401                         user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), Ptr->name.c_str(), Ptr->topic.c_str());
402                         user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), Ptr->name.c_str(), Ptr->setby.c_str(), (unsigned long)Ptr->topicset);
403                 }
404                 Ptr->UserList(user);
405         }
406         FOREACH_MOD(I_OnPostJoin,OnPostJoin(memb));
407         return Ptr;
408 }
409
410 bool Channel::IsBanned(User* user)
411 {
412         ModResult result;
413         FIRST_MOD_RESULT(OnCheckChannelBan, result, (user, this));
414
415         if (result != MOD_RES_PASSTHRU)
416                 return (result == MOD_RES_DENY);
417
418         for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
419         {
420                 if (CheckBan(user, i->data))
421                         return true;
422         }
423         return false;
424 }
425
426 bool Channel::CheckBan(User* user, const std::string& mask)
427 {
428         ModResult result;
429         FIRST_MOD_RESULT(OnCheckBan, result, (user, this, mask));
430         if (result != MOD_RES_PASSTHRU)
431                 return (result == MOD_RES_DENY);
432
433         // extbans were handled above, if this is one it obviously didn't match
434         if (mask[1] == ':')
435                 return false;
436
437         std::string::size_type at = mask.find('@');
438         if (at == std::string::npos)
439                 return false;
440
441         char tomatch[MAXBUF];
442         snprintf(tomatch, MAXBUF, "%s!%s", user->nick.c_str(), user->ident.c_str());
443         std::string prefix = mask.substr(0, at);
444         if (InspIRCd::Match(tomatch, prefix, NULL))
445         {
446                 std::string suffix = mask.substr(at + 1);
447                 if (InspIRCd::Match(user->host, suffix, NULL) ||
448                         InspIRCd::Match(user->dhost, suffix, NULL) ||
449                         InspIRCd::MatchCIDR(user->GetIPString(), suffix, NULL))
450                         return true;
451         }
452         return false;
453 }
454
455 ModResult Channel::GetExtBanStatus(User *user, char type)
456 {
457         ModResult rv;
458         FIRST_MOD_RESULT(OnExtBanCheck, rv, (user, this, type));
459         if (rv != MOD_RES_PASSTHRU)
460                 return rv;
461         for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++)
462         {
463                 if (i->data[0] == type && i->data[1] == ':')
464                 {
465                         std::string val = i->data.substr(2);
466                         if (CheckBan(user, val))
467                                 return MOD_RES_DENY;
468                 }
469         }
470         return MOD_RES_PASSTHRU;
471 }
472
473 /* Channel::PartUser
474  * remove a channel from a users record, and return the number of users left.
475  * Therefore, if this function returns 0 the caller should delete the Channel.
476  */
477 void Channel::PartUser(User *user, std::string &reason)
478 {
479         if (!user)
480                 return;
481
482         Membership* memb = GetUser(user);
483
484         if (memb)
485         {
486                 CUList except_list;
487                 FOREACH_MOD(I_OnUserPart,OnUserPart(memb, reason, except_list));
488
489                 WriteAllExcept(user, false, 0, except_list, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str());
490
491                 user->chans.erase(this);
492                 this->RemoveAllPrefixes(user);
493         }
494
495         this->DelUser(user);
496 }
497
498 void Channel::KickUser(User *src, User *user, const char* reason)
499 {
500         if (!src || !user || !reason)
501                 return;
502
503         Membership* memb = GetUser(user);
504         if (IS_LOCAL(src))
505         {
506                 if (!memb)
507                 {
508                         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());
509                         return;
510                 }
511                 if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))
512                 {
513                         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());
514                         return;
515                 }
516
517                 ModResult res;
518                 if (ServerInstance->ULine(src->server))
519                         res = MOD_RES_ALLOW;
520                 else
521                         FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason));
522
523                 if (res == MOD_RES_DENY)
524                         return;
525
526                 if (res == MOD_RES_PASSTHRU)
527                 {
528                         unsigned int them = this->GetPrefixValue(src);
529                         unsigned int req = HALFOP_VALUE;
530                         for (std::string::size_type i = 0; i < memb->modes.length(); i++)
531                         {
532                                 ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL);
533                                 if (mh && mh->GetLevelRequired() > req)
534                                         req = mh->GetLevelRequired();
535                         }
536
537                         if (them < req)
538                         {
539                                 src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",
540                                         src->nick.c_str(), this->name.c_str(), req > HALFOP_VALUE ? "" : "half-");
541                                 return;
542                         }
543                 }
544         }
545
546         if (memb)
547         {
548                 CUList except_list;
549                 FOREACH_MOD(I_OnUserKick,OnUserKick(src, memb, reason, except_list));
550
551                 WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), user->nick.c_str(), reason);
552
553                 user->chans.erase(this);
554                 this->RemoveAllPrefixes(user);
555         }
556
557         this->DelUser(user);
558 }
559
560 void Channel::WriteChannel(User* user, const char* text, ...)
561 {
562         char textbuffer[MAXBUF];
563         va_list argsPtr;
564
565         if (!user || !text)
566                 return;
567
568         va_start(argsPtr, text);
569         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
570         va_end(argsPtr);
571
572         this->WriteChannel(user, std::string(textbuffer));
573 }
574
575 void Channel::WriteChannel(User* user, const std::string &text)
576 {
577         char tb[MAXBUF];
578
579         if (!user)
580                 return;
581
582         snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str());
583         std::string out = tb;
584
585         for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
586         {
587                 if (IS_LOCAL(i->first))
588                         i->first->Write(out);
589         }
590 }
591
592 void Channel::WriteChannelWithServ(const std::string& ServName, const char* text, ...)
593 {
594         char textbuffer[MAXBUF];
595         va_list argsPtr;
596
597         if (!text)
598                 return;
599
600         va_start(argsPtr, text);
601         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
602         va_end(argsPtr);
603
604         this->WriteChannelWithServ(ServName, std::string(textbuffer));
605 }
606
607 void Channel::WriteChannelWithServ(const std::string& ServName, const std::string &text)
608 {
609         char tb[MAXBUF];
610
611         snprintf(tb,MAXBUF,":%s %s", ServName.empty() ? ServerInstance->Config->ServerName.c_str() : ServName.c_str(), text.c_str());
612         std::string out = tb;
613
614         for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
615         {
616                 if (IS_LOCAL(i->first))
617                         i->first->Write(out);
618         }
619 }
620
621 /* write formatted text from a source user to all users on a channel except
622  * for the sender (for privmsg etc) */
623 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const char* text, ...)
624 {
625         char textbuffer[MAXBUF];
626         va_list argsPtr;
627
628         if (!text)
629                 return;
630
631         va_start(argsPtr, text);
632         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
633         va_end(argsPtr);
634
635         this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer));
636 }
637
638 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...)
639 {
640         char textbuffer[MAXBUF];
641         va_list argsPtr;
642
643         if (!text)
644                 return;
645
646         int offset = snprintf(textbuffer,MAXBUF,":%s ", user->GetFullHost().c_str());
647
648         va_start(argsPtr, text);
649         vsnprintf(textbuffer + offset, MAXBUF - offset, text, argsPtr);
650         va_end(argsPtr);
651
652         this->RawWriteAllExcept(user, serversource, status, except_list, std::string(textbuffer));
653 }
654
655 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &text)
656 {
657         char tb[MAXBUF];
658
659         snprintf(tb,MAXBUF,":%s %s", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str(), text.c_str());
660         std::string out = tb;
661
662         this->RawWriteAllExcept(user, serversource, status, except_list, std::string(tb));
663 }
664
665 void Channel::RawWriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &out)
666 {
667         unsigned int minrank = 0;
668         if (status)
669         {
670                 ModeHandler* mh = ServerInstance->Modes->FindPrefix(status);
671                 if (mh)
672                         minrank = mh->GetPrefixRank();
673         }
674         for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
675         {
676                 if (IS_LOCAL(i->first) && (except_list.find(i->first) == except_list.end()))
677                 {
678                         /* User doesn't have the status we're after */
679                         if (minrank && i->second->getRank() < minrank)
680                                 continue;
681
682                         i->first->Write(out);
683                 }
684         }
685 }
686
687 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const std::string& text)
688 {
689         CUList except_list;
690         except_list.insert(user);
691         this->WriteAllExcept(user, serversource, status, except_list, std::string(text));
692 }
693
694 /*
695  * return a count of the users on a specific channel accounting for
696  * invisible users who won't increase the count. e.g. for /LIST
697  */
698 int Channel::CountInvisible()
699 {
700         int count = 0;
701         for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
702         {
703                 if (!(i->first->IsModeSet('i')))
704                         count++;
705         }
706
707         return count;
708 }
709
710 char* Channel::ChanModes(bool showkey)
711 {
712         static char scratch[MAXBUF];
713         static char sparam[MAXBUF];
714         char* offset = scratch;
715         std::string extparam;
716
717         *scratch = '\0';
718         *sparam = '\0';
719
720         /* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */
721         for(int n = 0; n < 64; n++)
722         {
723                 if(this->modes[n])
724                 {
725                         *offset++ = n + 65;
726                         extparam.clear();
727                         if (n == 'k' - 65 && !showkey)
728                         {
729                                 extparam = "<key>";
730                         }
731                         else
732                         {
733                                 extparam = this->GetModeParameter(n + 65);
734                         }
735                         if (!extparam.empty())
736                         {
737                                 charlcat(sparam,' ',MAXBUF);
738                                 strlcat(sparam,extparam.c_str(),MAXBUF);
739                         }
740                 }
741         }
742
743         /* Null terminate scratch */
744         *offset = '\0';
745         strlcat(scratch,sparam,MAXBUF);
746         return scratch;
747 }
748
749 /* compile a userlist of a channel into a string, each nick seperated by
750  * spaces and op, voice etc status shown as @ and +, and send it to 'user'
751  */
752 void Channel::UserList(User *user)
753 {
754         char list[MAXBUF];
755         size_t dlen, curlen;
756
757         if (!IS_LOCAL(user))
758                 return;
759
760         if (this->IsModeSet('s') && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex"))
761         {
762                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
763                 return;
764         }
765
766         dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=',  this->name.c_str());
767
768         int numusers = 0;
769         char* ptr = list + dlen;
770
771         /* Improvement by Brain - this doesnt change in value, so why was it inside
772          * the loop?
773          */
774         bool has_user = this->HasUser(user);
775
776         for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
777         {
778                 if ((!has_user) && (i->first->IsModeSet('i')))
779                 {
780                         /*
781                          * user is +i, and source not on the channel, does not show
782                          * nick in NAMES list
783                          */
784                         continue;
785                 }
786
787                 std::string prefixlist = this->GetPrefixChar(i->first);
788                 std::string nick = i->first->nick;
789
790                 FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick));
791
792                 /* Nick was nuked, a module wants us to skip it */
793                 if (nick.empty())
794                         continue;
795
796                 size_t ptrlen = 0;
797
798                 if (curlen + prefixlist.length() + nick.length() + 1 > 480)
799                 {
800                         /* list overflowed into multiple numerics */
801                         user->WriteNumeric(RPL_NAMREPLY, std::string(list));
802
803                         /* reset our lengths */
804                         dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
805                         ptr = list + dlen;
806
807                         ptrlen = 0;
808                         numusers = 0;
809                 }
810
811                 ptrlen = snprintf(ptr, MAXBUF, "%s%s ", prefixlist.c_str(), nick.c_str());
812
813                 curlen += ptrlen;
814                 ptr += ptrlen;
815
816                 numusers++;
817         }
818
819         /* if whats left in the list isnt empty, send it */
820         if (numusers)
821         {
822                 user->WriteNumeric(RPL_NAMREPLY, std::string(list));
823         }
824
825         user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
826 }
827
828 long Channel::GetMaxBans()
829 {
830         /* Return the cached value if there is one */
831         if (this->maxbans)
832                 return this->maxbans;
833
834         /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */
835         for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
836         {
837                 if (InspIRCd::Match(this->name, n->first, NULL))
838                 {
839                         this->maxbans = n->second;
840                         return n->second;
841                 }
842         }
843
844         /* Screw it, just return the default of 64 */
845         this->maxbans = 64;
846         return this->maxbans;
847 }
848
849 void Channel::ResetMaxBans()
850 {
851         this->maxbans = 0;
852 }
853
854 /* returns the status character for a given user on a channel, e.g. @ for op,
855  * % for halfop etc. If the user has several modes set, the highest mode
856  * the user has must be returned.
857  */
858 const char* Channel::GetPrefixChar(User *user)
859 {
860         static char pf[2] = {0, 0};
861         *pf = 0;
862         unsigned int bestrank = 0;
863
864         UserMembIter m = userlist.find(user);
865         if (m != userlist.end())
866         {
867                 for(unsigned int i=0; i < m->second->modes.length(); i++)
868                 {
869                         char mchar = m->second->modes[i];
870                         ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
871                         if (mh && mh->GetPrefixRank() > bestrank && mh->GetPrefix())
872                         {
873                                 bestrank = mh->GetPrefixRank();
874                                 pf[0] = mh->GetPrefix();
875                         }
876                 }
877         }
878         return pf;
879 }
880
881 unsigned int Membership::getRank()
882 {
883         char mchar = modes.c_str()[0];
884         unsigned int rv = 0;
885         if (mchar)
886         {
887                 ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
888                 if (mh)
889                         rv = mh->GetPrefixRank();
890         }
891         return rv;
892 }
893
894 const char* Channel::GetAllPrefixChars(User* user)
895 {
896         static char prefix[64];
897         int ctr = 0;
898
899         UserMembIter m = userlist.find(user);
900         if (m != userlist.end())
901         {
902                 for(unsigned int i=0; i < m->second->modes.length(); i++)
903                 {
904                         char mchar = m->second->modes[i];
905                         ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
906                         if (mh && mh->GetPrefix())
907                                 prefix[ctr++] = mh->GetPrefix();
908                 }
909         }
910         prefix[ctr] = 0;
911
912         return prefix;
913 }
914
915 unsigned int Channel::GetPrefixValue(User* user)
916 {
917         UserMembIter m = userlist.find(user);
918         if (m == userlist.end())
919                 return 0;
920         return m->second->getRank();
921 }
922
923 bool Channel::SetPrefix(User* user, char prefix, bool adding)
924 {
925         ModeHandler* delta_mh = ServerInstance->Modes->FindMode(prefix, MODETYPE_CHANNEL);
926         if (!delta_mh)
927                 return false;
928         UserMembIter m = userlist.find(user);
929         if (m == userlist.end())
930                 return false;
931         for(unsigned int i=0; i < m->second->modes.length(); i++)
932         {
933                 char mchar = m->second->modes[i];
934                 ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
935                 if (mh && mh->GetPrefixRank() <= delta_mh->GetPrefixRank())
936                 {
937                         m->second->modes =
938                                 m->second->modes.substr(0,i) +
939                                 (adding ? std::string(1, prefix) : "") +
940                                 m->second->modes.substr(mchar == prefix ? i+1 : i);
941                         return adding != (mchar == prefix);
942                 }
943         }
944         if (adding)
945                 m->second->modes += std::string(1, prefix);
946         return adding;
947 }
948
949 void Channel::RemoveAllPrefixes(User* user)
950 {
951         UserMembIter m = userlist.find(user);
952         if (m != userlist.end())
953         {
954                 m->second->modes.clear();
955         }
956 }