]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/channels.cpp
Mass-tidyup of module global vars, theyre no longer global vars.
[user/henk/code/inspircd.git] / src / channels.cpp
1 /*   +------------------------------------+
2  *   | Inspire Internet Relay Chat Daemon |
3  *   +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *   E-mail:
7  *        <brain@chatspike.net>
8  *        <Craig@chatspike.net>
9  * 
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *      the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include <string>
20 #include <map>
21 #include <sstream>
22 #include <vector>
23 #include <deque>
24 #include <stdarg.h>
25 #include "configreader.h"
26 #include "inspircd.h"
27 #include "hash_map.h"
28 #include "users.h"
29 #include "ctables.h"
30 #include "globals.h"
31 #include "modules.h"
32 #include "dynamic.h"
33 #include "commands.h"
34 #include "wildcard.h"
35 #include "mode.h"
36 #include "xline.h"
37 #include "inspstring.h"
38 #include "helperfuncs.h"
39 #include "typedefs.h"
40
41 extern time_t TIME;
42
43 chanrec::chanrec(InspIRCd* Instance) : ServerInstance(Instance)
44 {
45         *name = *topic = *setby = *key = 0;
46         created = topicset = limit = 0;
47         internal_userlist.clear();
48         memset(&modes,0,64);
49 }
50
51 void chanrec::SetMode(char mode,bool mode_on)
52 {
53         modes[mode-65] = mode_on;
54         if (!mode_on)
55                 this->SetModeParam(mode,"",false);
56 }
57
58
59 void chanrec::SetModeParam(char mode,const char* parameter,bool mode_on)
60 {
61         log(DEBUG,"SetModeParam called");
62         
63         CustomModeList::iterator n = custom_mode_params.find(mode);     
64
65         if (mode_on)
66         {
67                 if (n == custom_mode_params.end())
68                 {
69                         custom_mode_params[mode] = strdup(parameter);
70                         log(DEBUG,"Custom mode parameter %c %s added",mode,parameter);
71                 }
72                 else
73                 {
74                         log(DEBUG, "Tried to set custom mode parameter for %c '%s' when it was already '%s'", mode, parameter, n->second);
75                 }
76         }
77         else
78         {
79                 if (n != custom_mode_params.end())
80                 {
81                         free(n->second);
82                         custom_mode_params.erase(n);
83                 }
84         }
85 }
86
87 bool chanrec::IsModeSet(char mode)
88 {
89         return modes[mode-65];
90 }
91
92 std::string chanrec::GetModeParameter(char mode)
93 {
94         if (mode == 'k')
95         {
96                 return this->key;
97         }
98         else if (mode == 'l')
99         {
100                 return ConvToStr(this->limit);
101         }
102         else
103         {
104                 CustomModeList::iterator n = custom_mode_params.find(mode);
105                 if (n != custom_mode_params.end())
106                 {
107                         return n->second;
108                 }
109                 return "";
110         }
111 }
112
113 long chanrec::GetUserCounter()
114 {
115         return (this->internal_userlist.size());
116 }
117
118 void chanrec::AddUser(userrec* user)
119 {
120         internal_userlist[user] = user;
121 }
122
123 unsigned long chanrec::DelUser(userrec* user)
124 {
125         CUListIter a = internal_userlist.find(user);
126         
127         if (a != internal_userlist.end())
128         {
129                 internal_userlist.erase(a);
130                 /* And tidy any others... */
131                 DelOppedUser(user);
132                 DelHalfoppedUser(user);
133                 DelVoicedUser(user);
134         }
135         
136         return internal_userlist.size();
137 }
138
139 bool chanrec::HasUser(userrec* user)
140 {
141         return (internal_userlist.find(user) != internal_userlist.end());
142 }
143
144 void chanrec::AddOppedUser(userrec* user)
145 {
146         internal_op_userlist[user] = user;
147 }
148
149 void chanrec::DelOppedUser(userrec* user)
150 {
151         CUListIter a = internal_op_userlist.find(user);
152         if (a != internal_op_userlist.end())
153         {
154                 internal_op_userlist.erase(a);
155                 return;
156         }
157 }
158
159 void chanrec::AddHalfoppedUser(userrec* user)
160 {
161         internal_halfop_userlist[user] = user;
162 }
163
164 void chanrec::DelHalfoppedUser(userrec* user)
165 {
166         CUListIter a = internal_halfop_userlist.find(user);
167
168         if (a != internal_halfop_userlist.end())
169         {   
170                 internal_halfop_userlist.erase(a);
171         }
172 }
173
174 void chanrec::AddVoicedUser(userrec* user)
175 {
176         internal_voice_userlist[user] = user;
177 }
178
179 void chanrec::DelVoicedUser(userrec* user)
180 {
181         CUListIter a = internal_voice_userlist.find(user);
182         
183         if (a != internal_voice_userlist.end())
184         {
185                 internal_voice_userlist.erase(a);
186         }
187 }
188
189 CUList* chanrec::GetUsers()
190 {
191         return &internal_userlist;
192 }
193
194 CUList* chanrec::GetOppedUsers()
195 {
196         return &internal_op_userlist;
197 }
198
199 CUList* chanrec::GetHalfoppedUsers()
200 {
201         return &internal_halfop_userlist;
202 }
203
204 CUList* chanrec::GetVoicedUsers()
205 {
206         return &internal_voice_userlist;
207 }
208
209 /* 
210  * add a channel to a user, creating the record for it if needed and linking
211  * it to the user record 
212  */
213 chanrec* chanrec::JoinUser(InspIRCd* Instance, userrec *user, const char* cn, bool override, const char* key)
214 {
215         if (!user || !cn)
216                 return NULL;
217
218         int created = 0;
219         char cname[MAXBUF];
220         int MOD_RESULT = 0;
221         strlcpy(cname,cn,CHANMAX);
222
223         chanrec* Ptr = Instance->FindChan(cname);
224
225         if (!Ptr)
226         {
227                 if (user->fd > -1)
228                 {
229                         MOD_RESULT = 0;
230                         FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,NULL,cname));
231                         if (MOD_RESULT == 1)
232                                 return NULL;
233                 }
234
235                 /* create a new one */
236                 Ptr = new chanrec(Instance);
237                 Instance->chanlist[cname] = Ptr;
238
239                 strlcpy(Ptr->name, cname,CHANMAX);
240                 Ptr->modes[CM_TOPICLOCK] = Ptr->modes[CM_NOEXTERNAL] = 1;
241                 Ptr->created = TIME;
242                 *Ptr->topic = 0;
243                 strlcpy(Ptr->setby, user->nick,NICKMAX-1);
244                 Ptr->topicset = 0;
245                 log(DEBUG,"chanrec::JoinUser(): created: %s",cname);
246                 /*
247                  * set created to 2 to indicate user
248                  * is the first in the channel
249                  * and should be given ops
250                  */
251                 created = 2;
252         }
253         else
254         {
255                 /* Already on the channel */
256                 if (Ptr->HasUser(user))
257                         return NULL;
258
259                 /*
260                  * remote users are allowed us to bypass channel modes
261                  * and bans (used by servers)
262                  */
263                 if (IS_LOCAL(user)) /* was a check on fd > -1 */
264                 {
265                         MOD_RESULT = 0;
266                         FOREACH_RESULT_I(Instance,I_OnUserPreJoin,OnUserPreJoin(user,Ptr,cname));
267                         if (MOD_RESULT == 1)
268                         {
269                                 return NULL;
270                         }
271                         else if (MOD_RESULT == 0)
272                         {
273                                 if (*Ptr->key)
274                                 {
275                                         MOD_RESULT = 0;
276                                         FOREACH_RESULT_I(Instance,I_OnCheckKey,OnCheckKey(user, Ptr, key ? key : ""));
277                                         if (!MOD_RESULT)
278                                         {
279                                                 if (!key)
280                                                 {
281                                                         log(DEBUG,"chanrec::JoinUser(): no key given in JOIN");
282                                                         user->WriteServ("475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
283                                                         return NULL;
284                                                 }
285                                                 else
286                                                 {
287                                                         if (strcmp(key,Ptr->key))
288                                                         {
289                                                                 log(DEBUG,"chanrec::JoinUser(): bad key given in JOIN");
290                                                                 user->WriteServ("475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
291                                                                 return NULL;
292                                                         }
293                                                 }
294                                         }
295                                 }
296                                 if (Ptr->modes[CM_INVITEONLY])
297                                 {
298                                         MOD_RESULT = 0;
299                                         irc::string xname(Ptr->name);
300                                         FOREACH_RESULT_I(Instance,I_OnCheckInvite,OnCheckInvite(user, Ptr));
301                                         if (!MOD_RESULT)
302                                         {
303                                                 if (user->IsInvited(xname))
304                                                 {
305                                                         /* user was invited to channel */
306                                                         /* there may be an optional channel NOTICE here */
307                                                 }
308                                                 else
309                                                 {
310                                                         user->WriteServ("473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
311                                                         return NULL;
312                                                 }
313                                         }
314                                         user->RemoveInvite(xname);
315                                 }
316                                 if (Ptr->limit)
317                                 {
318                                         MOD_RESULT = 0;
319                                         FOREACH_RESULT_I(Instance,I_OnCheckLimit,OnCheckLimit(user, Ptr));
320                                         if (!MOD_RESULT)
321                                         {
322                                                 if (Ptr->GetUserCounter() >= Ptr->limit)
323                                                 {
324                                                         user->WriteServ("471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
325                                                         return NULL;
326                                                 }
327                                         }
328                                 }
329                                 if (Ptr->bans.size())
330                                 {
331                                         MOD_RESULT = 0;
332                                         FOREACH_RESULT_I(Instance,I_OnCheckBan,OnCheckBan(user, Ptr));
333                                         char mask[MAXBUF];
334                                         sprintf(mask,"%s!%s@%s",user->nick, user->ident, user->GetIPString());
335                                         if (!MOD_RESULT)
336                                         {
337                                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
338                                                 {
339                                                         /* This allows CIDR ban matching
340                                                          * 
341                                                          *        Full masked host                      Full unmasked host                   IP with/without CIDR
342                                                          */
343                                                         if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match(mask, i->data, true)))
344                                                         {
345                                                                 user->WriteServ("474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
346                                                                 return NULL;
347                                                         }
348                                                 }
349                                         }
350                                 }
351                         }
352                 }
353                 else
354                 {
355                         log(DEBUG,"chanrec::JoinUser(): Overridden checks");
356                 }
357                 created = 1;
358         }
359
360         for (UserChanList::const_iterator index = user->chans.begin(); index != user->chans.end(); index++)
361         {
362                 if ((*index)->channel == NULL)
363                 {
364                         return chanrec::ForceChan(Instance, Ptr, *index, user, created);
365                 }
366         }
367
368         /*
369          * XXX: If the user is an oper here, we can just extend their user->chans vector by one
370          * and put the channel in here. Same for remote users which are not bound by
371          * the channel limits. Otherwise, nope, youre boned.
372          */
373         if (!IS_LOCAL(user)) /* was a check on fd < 0 */
374         {
375                 ucrec* a = new ucrec();
376                 chanrec* c = chanrec::ForceChan(Instance, Ptr,a,user,created);
377                 user->chans.push_back(a);
378                 return c;
379         }
380         else if (*user->oper)
381         {
382                 /* Oper allows extension up to the OPERMAXCHANS value */
383                 if (user->chans.size() < OPERMAXCHANS)
384                 {
385                         ucrec* a = new ucrec();
386                         chanrec* c = chanrec::ForceChan(Instance, Ptr,a,user,created);
387                         user->chans.push_back(a);
388                         return c;
389                 }
390         }
391
392         user->WriteServ("405 %s %s :You are on too many channels",user->nick, cname);
393
394         if (created == 2)
395         {
396                 log(DEBUG,"BLAMMO, Whacking channel.");
397                 /* Things went seriously pear shaped, so take this away. bwahaha. */
398                 chan_hash::iterator n = Instance->chanlist.find(cname);
399                 if (n != Instance->chanlist.end())
400                 {
401                         Ptr->DelUser(user);
402                         DELETE(Ptr);
403                         Instance->chanlist.erase(n);
404                         for (unsigned int index =0; index < user->chans.size(); index++)
405                         {
406                                 if (user->chans[index]->channel == Ptr)
407                                 {
408                                         user->chans[index]->channel = NULL;
409                                         user->chans[index]->uc_modes = 0;       
410                                 }
411                         }
412                 }
413         }
414         else
415         {
416                 for (unsigned int index =0; index < user->chans.size(); index++)
417                 {
418                         if (user->chans[index]->channel == Ptr)
419                         {
420                                 user->chans[index]->channel = NULL;
421                                 user->chans[index]->uc_modes = 0;
422                         }
423                 }
424         }
425         return NULL;
426 }
427
428 chanrec* chanrec::ForceChan(InspIRCd* Instance, chanrec* Ptr,ucrec *a,userrec* user, int created)
429 {
430         if (created == 2)
431         {
432                 /* first user in is given ops */
433                 a->uc_modes = UCMODE_OP;
434                 Ptr->AddOppedUser(user);
435         }
436         else
437         {
438                 a->uc_modes = 0;
439         }
440
441         a->channel = Ptr;
442         Ptr->AddUser(user);
443         Ptr->WriteChannel(user,"JOIN :%s",Ptr->name);
444
445         /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */
446         if (IS_LOCAL(user))
447         {
448                 log(DEBUG,"Sent JOIN to client");
449                 if (Ptr->topicset)
450                 {
451                         user->WriteServ("332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
452                         user->WriteServ("333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
453                 }
454                 Ptr->UserList(user);
455                 user->WriteServ("366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
456         }
457         FOREACH_MOD_I(Instance,I_OnUserJoin,OnUserJoin(user,Ptr));
458         return Ptr;
459 }
460
461 /* chanrec::PartUser
462  * remove a channel from a users record, and remove the record from the hash
463  * if the channel has become empty
464  */
465 long chanrec::PartUser(userrec *user, const char* reason)
466 {
467         if (!user)
468                 return this->GetUserCounter();
469
470         for (unsigned int i =0; i < user->chans.size(); i++)
471         {
472                 /* zap it from the channel list of the user */
473                 if (user->chans[i]->channel == this)
474                 {
475                         if (reason)
476                         {
477                                 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, reason));
478                                 this->WriteChannel(user, "PART %s :%s", this->name, reason);
479                         }
480                         else
481                         {
482                                 FOREACH_MOD(I_OnUserPart,OnUserPart(user, this, ""));
483                                 this->WriteChannel(user, "PART :%s", this->name);
484                         }
485                         user->chans[i]->uc_modes = 0;
486                         user->chans[i]->channel = NULL;
487                         break;
488                 }
489         }
490
491         if (!this->DelUser(user)) /* if there are no users left on the channel... */
492         {
493                 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
494                 /* kill the record */
495                 if (iter != ServerInstance->chanlist.end())
496                 {
497                         log(DEBUG,"del_channel: destroyed: %s", this->name);
498                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
499                         ServerInstance->chanlist.erase(iter);
500                 }
501                 return 0;
502         }
503
504         return this->GetUserCounter();
505 }
506
507 long chanrec::ServerKickUser(userrec* user, const char* reason, bool triggerevents)
508 {
509         if (!user || !reason)
510                 return this->GetUserCounter();
511
512         if (IS_LOCAL(user))
513         {
514                 if (!this->HasUser(user))
515                 {
516                         /* Not on channel */
517                         return this->GetUserCounter();
518                 }
519         }
520
521         if (triggerevents)
522         {
523                 FOREACH_MOD(I_OnUserKick,OnUserKick(NULL,user,this,reason));
524         }
525
526         for (unsigned int i =0; i < user->chans.size(); i++)
527         {
528                 if (user->chans[i]->channel == this)
529                 {
530                         this->WriteChannelWithServ(ServerInstance->Config->ServerName, "KICK %s %s :%s", this->name, user->nick, reason);
531                         user->chans[i]->uc_modes = 0;
532                         user->chans[i]->channel = NULL;
533                         break;
534                 }
535         }
536
537         if (!this->DelUser(user))
538         {
539                 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
540                 /* kill the record */
541                 if (iter != ServerInstance->chanlist.end())
542                 {
543                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
544                         ServerInstance->chanlist.erase(iter);
545                 }
546                 return 0;
547         }
548
549         return this->GetUserCounter();
550 }
551
552 long chanrec::KickUser(userrec *src, userrec *user, const char* reason)
553 {
554         if (!src || !user || !reason)
555                 return this->GetUserCounter();
556
557         if (IS_LOCAL(src))
558         {
559                 if (!this->HasUser(user))
560                 {
561                         src->WriteServ("441 %s %s %s :They are not on that channel",src->nick, user->nick, this->name);
562                         return this->GetUserCounter();
563                 }
564                 if ((is_uline(user->server)) && (!is_uline(src->server)))
565                 {
566                         src->WriteServ("482 %s %s :Only a u-line may kick a u-line from a channel.",src->nick, this->name);
567                         return this->GetUserCounter();
568                 }
569                 int MOD_RESULT = 0;
570
571                 if (!is_uline(src->server))
572                 {
573                         MOD_RESULT = 0;
574                         FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,this,reason));
575                         if (MOD_RESULT == 1)
576                                 return this->GetUserCounter();
577                 }
578                 /* Set to -1 by OnUserPreKick if explicit allow was set */
579                 if (MOD_RESULT != -1)
580                 {
581                         FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,this,AC_KICK));
582                         if ((MOD_RESULT == ACR_DENY) && (!is_uline(src->server)))
583                                 return this->GetUserCounter();
584         
585                         if ((MOD_RESULT == ACR_DEFAULT) || (!is_uline(src->server)))
586                         {
587                                 int them = this->GetStatus(src);
588                                 int us = this->GetStatus(user);
589                                 if ((them < STATUS_HOP) || (them < us))
590                                 {
591                                         if (them == STATUS_HOP)
592                                         {
593                                                 src->WriteServ("482 %s %s :You must be a channel operator",src->nick, this->name);
594                                         }
595                                         else
596                                         {
597                                                 src->WriteServ("482 %s %s :You must be at least a half-operator",src->nick, this->name);
598                                         }
599                                         return this->GetUserCounter();
600                                 }
601                         }
602                 }
603         }
604
605         FOREACH_MOD(I_OnUserKick,OnUserKick(src,user,this,reason));
606                         
607         for (UserChanList::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
608         {
609                 /* zap it from the channel list of the user */
610                 if ((*i)->channel == this)
611                 {
612                         this->WriteChannel(src, "KICK %s %s :%s", this->name, user->nick, reason);
613                         (*i)->uc_modes = 0;
614                         (*i)->channel = NULL;
615                         break;
616                 }
617         }
618
619         if (!this->DelUser(user))
620         /* if there are no users left on the channel */
621         {
622                 chan_hash::iterator iter = ServerInstance->chanlist.find(this->name);
623
624                 /* kill the record */
625                 if (iter != ServerInstance->chanlist.end())
626                 {
627                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(this));
628                         ServerInstance->chanlist.erase(iter);
629                 }
630                 return 0;
631         }
632
633         return this->GetUserCounter();
634 }
635
636 void chanrec::WriteChannel(userrec* user, char* text, ...)
637 {
638         char textbuffer[MAXBUF];
639         va_list argsPtr;
640
641         if (!user || !text)
642                 return;
643
644         va_start(argsPtr, text);
645         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
646         va_end(argsPtr);
647
648         this->WriteChannel(user, std::string(textbuffer));
649 }
650
651 void chanrec::WriteChannel(userrec* user, const std::string &text)
652 {
653         CUList *ulist = this->GetUsers();
654
655         if (!user)
656                 return;
657
658         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
659         {
660                 if (i->second->fd != FD_MAGIC_NUMBER)
661                         user->WriteTo(i->second,text);
662         }
663 }
664
665 void chanrec::WriteChannelWithServ(const char* ServName, const char* text, ...)
666 {
667         char textbuffer[MAXBUF];
668         va_list argsPtr;
669
670         if (!text)
671                 return;
672
673         va_start(argsPtr, text);
674         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
675         va_end(argsPtr);
676
677         this->WriteChannelWithServ(ServName, std::string(textbuffer));
678 }
679
680 void chanrec::WriteChannelWithServ(const char* ServName, const std::string &text)
681 {
682         CUList *ulist = this->GetUsers();
683
684         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
685         {
686                 if (IS_LOCAL(i->second))
687                         i->second->WriteServ(text);
688         }
689 }
690
691 /* write formatted text from a source user to all users on a channel except
692  * for the sender (for privmsg etc) */
693 void chanrec::WriteAllExceptSender(userrec* user, char status, char* text, ...)
694 {
695         char textbuffer[MAXBUF];
696         va_list argsPtr;
697
698         if (!user || !text)
699                 return;
700
701         va_start(argsPtr, text);
702         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
703         va_end(argsPtr);
704
705         this->WriteAllExceptSender(user, status, std::string(textbuffer));
706 }
707
708 void chanrec::WriteAllExceptSender(userrec* user, char status, const std::string& text)
709 {
710         CUList *ulist;
711
712         if (!user)
713                 return;
714
715         switch (status)
716         {
717                 case '@':
718                         ulist = this->GetOppedUsers();
719                         break;
720                 case '%':
721                         ulist = this->GetHalfoppedUsers();
722                         break;
723                 case '+':
724                         ulist = this->GetVoicedUsers();
725                         break;
726                 default:
727                         ulist = this->GetUsers();
728                         break;
729         }
730
731         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
732         {
733                 if ((IS_LOCAL(i->second)) && (user != i->second))
734                         i->second->WriteFrom(user,text);
735         }
736 }
737
738 /*
739  * return a count of the users on a specific channel accounting for
740  * invisible users who won't increase the count. e.g. for /LIST
741  */
742 int chanrec::CountInvisible()
743 {
744         int count = 0;
745         CUList *ulist= this->GetUsers();
746         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
747         {
748                 if (!(i->second->modes[UM_INVISIBLE]))
749                         count++;
750         }
751
752         return count;
753 }
754
755 char* chanrec::ChanModes(bool showkey)
756 {
757         static char scratch[MAXBUF];
758         static char sparam[MAXBUF];
759         char* offset = scratch;
760         std::string extparam = "";
761
762         *scratch = '\0';
763         *sparam = '\0';
764
765         /* This was still iterating up to 190, chanrec::custom_modes is only 64 elements -- Om */
766         for(int n = 0; n < 64; n++)
767         {
768                 if(this->modes[n])
769                 {
770                         *offset++ = n + 65;
771                         extparam = "";
772                         switch (n)
773                         {
774                                 case CM_KEY:
775                                         extparam = (showkey ? this->key : "<key>");
776                                 break;
777                                 case CM_LIMIT:
778                                         extparam = ConvToStr(this->limit);
779                                 break;
780                                 case CM_NOEXTERNAL:
781                                 case CM_TOPICLOCK:
782                                 case CM_INVITEONLY:
783                                 case CM_MODERATED:
784                                 case CM_SECRET:
785                                 case CM_PRIVATE:
786                                         /* We know these have no parameters */
787                                 break;
788                                 default:
789                                         extparam = this->GetModeParameter(n + 65);
790                                 break;
791                         }
792                         if (extparam != "")
793                         {
794                                 charlcat(sparam,' ',MAXBUF);
795                                 strlcat(sparam,extparam.c_str(),MAXBUF);
796                         }
797                 }
798         }
799
800         /* Null terminate scratch */
801         *offset = '\0';
802         strlcat(scratch,sparam,MAXBUF);
803         return scratch;
804 }
805
806 /* compile a userlist of a channel into a string, each nick seperated by
807  * spaces and op, voice etc status shown as @ and +, and send it to 'user'
808  */
809 void chanrec::UserList(userrec *user)
810 {
811         char list[MAXBUF];
812         size_t dlen, curlen;
813
814         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);
815
816         int numusers = 0;
817         char* ptr = list + dlen;
818
819         CUList *ulist= this->GetUsers();
820
821         /* Improvement by Brain - this doesnt change in value, so why was it inside
822          * the loop?
823          */
824         bool has_user = this->HasUser(user);
825
826         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
827         {
828                 if ((!has_user) && (i->second->modes[UM_INVISIBLE]))
829                 {
830                         /*
831                          * user is +i, and source not on the channel, does not show
832                          * nick in NAMES list
833                          */
834                         continue;
835                 }
836
837                 size_t ptrlen = snprintf(ptr, MAXBUF, "%s%s ", this->GetStatusChar(i->second), i->second->nick);
838
839                 curlen += ptrlen;
840                 ptr += ptrlen;
841
842                 numusers++;
843
844                 if (curlen > (480-NICKMAX))
845                 {
846                         /* list overflowed into multiple numerics */
847                         user->WriteServ(list);
848
849                         /* reset our lengths */
850                         dlen = curlen = snprintf(list,MAXBUF,"353 %s = %s :", user->nick, this->name);
851                         ptr = list + dlen;
852
853                         ptrlen = 0;
854                         numusers = 0;
855                 }
856         }
857
858         /* if whats left in the list isnt empty, send it */
859         if (numusers)
860         {
861                 user->WriteServ(list);
862         }
863 }
864
865 long chanrec::GetMaxBans()
866 {
867         std::string x;
868         for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++)
869         {
870                 x = n->first;
871                 if (match(this->name,x.c_str()))
872                 {
873                         return n->second;
874                 }
875         }
876         return 64;
877 }
878
879
880 /* returns the status character for a given user on a channel, e.g. @ for op,
881  * % for halfop etc. If the user has several modes set, the highest mode
882  * the user has must be returned. */
883
884 const char* chanrec::GetStatusChar(userrec *user)
885 {
886         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
887         {
888                 if ((*i)->channel == this)
889                 {
890                         if (((*i)->uc_modes & UCMODE_OP) > 0)
891                         {
892                                 return "@";
893                         }
894                         if (((*i)->uc_modes & UCMODE_HOP) > 0)
895                         {
896                                 return "%";
897                         }
898                         if (((*i)->uc_modes & UCMODE_VOICE) > 0)
899                         {
900                                 return "+";
901                         }
902                         return "";
903                 }
904         }
905         return "";
906 }
907
908
909 int chanrec::GetStatusFlags(userrec *user)
910 {
911         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
912         {
913                 if ((*i)->channel == this)
914                 {
915                         return (*i)->uc_modes;
916                 }
917         }
918         return 0;
919 }
920
921
922
923 int chanrec::GetStatus(userrec *user)
924 {
925         if (is_uline(user->server))
926                 return STATUS_OP;
927
928         for (std::vector<ucrec*>::const_iterator i = user->chans.begin(); i != user->chans.end(); i++)
929         {
930                 if ((*i)->channel == this)
931                 {
932                         if (((*i)->uc_modes & UCMODE_OP) > 0)
933                         {
934                                 return STATUS_OP;
935                         }
936                         if (((*i)->uc_modes & UCMODE_HOP) > 0)
937                         {
938                                 return STATUS_HOP;
939                         }
940                         if (((*i)->uc_modes & UCMODE_VOICE) > 0)
941                         {
942                                 return STATUS_VOICE;
943                         }
944                         return STATUS_NORMAL;
945                 }
946         }
947         return STATUS_NORMAL;
948 }
949
950