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