]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/channels.cpp
- Fixed some HORRIBLE indenting. Tabs, please.
[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 "inspircd_config.h"
20 #include "inspircd.h"
21 #include "inspircd_io.h"
22 #include <unistd.h>
23 #include <sys/errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/utsname.h>
26 #include <time.h>
27 #include <string>
28 #ifdef GCC3
29 #include <ext/hash_map>
30 #else
31 #include <hash_map>
32 #endif
33 #include <map>
34 #include <sstream>
35 #include <vector>
36 #include <deque>
37 #include "users.h"
38 #include "ctables.h"
39 #include "globals.h"
40 #include "modules.h"
41 #include "dynamic.h"
42 #include "commands.h"
43 #include "wildcard.h"
44 #include "message.h"
45 #include "mode.h"
46 #include "xline.h"
47 #include "inspstring.h"
48 #include "helperfuncs.h"
49 #include "typedefs.h"
50
51 #ifdef GCC3
52 #define nspace __gnu_cxx
53 #else
54 #define nspace std
55 #endif
56
57 extern ServerConfig* Config;
58
59 extern int MODCOUNT;
60 extern std::vector<Module*> modules;
61 extern std::vector<ircd_module*> factory;
62 extern int WHOWAS_STALE;
63 extern int WHOWAS_MAX;
64 extern time_t TIME;
65 extern chan_hash chanlist;
66
67 using namespace std;
68
69 std::vector<ModeParameter> custom_mode_params;
70
71 chanrec* ForceChan(chanrec* Ptr,ucrec &a,userrec* user, int created);
72
73 chanrec::chanrec()
74 {
75         *name = *custom_modes = *topic = *setby = *key = 0;
76         created = topicset = limit = binarymodes = 0;
77         internal_userlist.clear();
78 }
79
80 void chanrec::SetCustomMode(char mode,bool mode_on)
81 {
82         if (mode_on)
83         {
84                 static char m[3];
85                 m[0] = mode;
86                 m[1] = '\0';
87                 if (!strchr(this->custom_modes,mode))
88                 {
89                         strlcat(custom_modes,m,MAXMODES);
90                 }
91                 log(DEBUG,"Custom mode %c set",mode);
92         }
93         else {
94
95                 std::string a = this->custom_modes;
96                 int pos = a.find(mode);
97                 a.erase(pos,1);
98                 strlcpy(this->custom_modes,a.c_str(),MAXMODES);
99
100                 log(DEBUG,"Custom mode %c removed: modelist='%s'",mode,this->custom_modes);
101                 this->SetCustomModeParam(mode,"",false);
102         }
103 }
104
105
106 void chanrec::SetCustomModeParam(char mode,char* parameter,bool mode_on)
107 {
108
109         log(DEBUG,"SetCustomModeParam called");
110         ModeParameter M;
111         M.mode = mode;
112         strlcpy(M.channel,this->name,CHANMAX);
113         strlcpy(M.parameter,parameter,MAXBUF);
114         if (mode_on)
115         {
116                 log(DEBUG,"Custom mode parameter %c %s added",mode,parameter);
117                 custom_mode_params.push_back(M);
118         }
119         else
120         {
121                 if (custom_mode_params.size())
122                 {
123                         for (vector<ModeParameter>::iterator i = custom_mode_params.begin(); i < custom_mode_params.end(); i++)
124                         {
125                                 if ((i->mode == mode) && (!strcasecmp(this->name,i->channel)))
126                                 {
127                                         log(DEBUG,"Custom mode parameter %c %s removed",mode,parameter);
128                                         custom_mode_params.erase(i);
129                                         return;
130                                 }
131                         }
132                 }
133                 log(DEBUG,"*** BUG *** Attempt to remove non-existent mode parameter!");
134         }
135 }
136
137 bool chanrec::IsCustomModeSet(char mode)
138 {
139         return (strchr(this->custom_modes,mode));
140 }
141
142 /* XXX - would it not be better to store a vector for each channel, rather than one huge list? -- w00t */
143 std::string chanrec::GetModeParameter(char mode)
144 {
145         if (custom_mode_params.size())
146         {
147                 for (vector<ModeParameter>::iterator i = custom_mode_params.begin(); i < custom_mode_params.end(); i++)
148                 {
149                         if ((i->mode == mode) && (!strcasecmp(this->name,i->channel)))
150                         {
151                                 return i->parameter;
152                         }
153                 }
154         }
155         return "";
156 }
157
158 long chanrec::GetUserCounter()
159 {
160         return (this->internal_userlist.size());
161 }
162
163 void chanrec::AddUser(char* castuser)
164 {
165         internal_userlist[castuser] = castuser;
166         log(DEBUG,"Added casted user to channel's internal list");
167 }
168
169 void chanrec::DelUser(char* castuser)
170 {
171         std::map<char*,char*>::iterator a = internal_userlist.find(castuser);
172         if (a != internal_userlist.end())
173         {
174                 log(DEBUG,"Removed casted user from channel's internal list");
175                 internal_userlist.erase(a);
176                 /* And tidy any others... */
177                 DelOppedUser(castuser);
178                 DelHalfoppedUser(castuser);
179                 DelVoicedUser(castuser);
180                 return;
181         }
182 }
183
184 void chanrec::AddOppedUser(char* castuser)
185 {
186         internal_op_userlist[castuser] = castuser;
187         log(DEBUG,"Added casted user to channel's internal list");
188 }
189
190 void chanrec::DelOppedUser(char* castuser)
191 {
192         std::map<char*,char*>::iterator a = internal_op_userlist.find(castuser);
193         if (a != internal_op_userlist.end())
194         {
195                 log(DEBUG,"Removed casted user from channel's internal list");
196                 internal_op_userlist.erase(a);
197                 return;
198         }
199 }
200
201 void chanrec::AddHalfoppedUser(char* castuser)
202 {
203         internal_halfop_userlist[castuser] = castuser;
204         log(DEBUG,"Added casted user to channel's internal list");
205 }
206
207 void chanrec::DelHalfoppedUser(char* castuser)
208 {
209         std::map<char*,char*>::iterator a = internal_halfop_userlist.find(castuser);
210         if (a != internal_halfop_userlist.end())
211         {   
212                 log(DEBUG,"Removed casted user from channel's internal list");
213                 internal_halfop_userlist.erase(a);
214                 return; 
215         }
216 }
217
218 void chanrec::AddVoicedUser(char* castuser)
219 {
220         internal_voice_userlist[castuser] = castuser;
221         log(DEBUG,"Added casted user to channel's internal list");
222 }
223
224 void chanrec::DelVoicedUser(char* castuser)
225 {
226         std::map<char*,char*>::iterator a = internal_voice_userlist.find(castuser);
227         if (a != internal_voice_userlist.end())
228         {
229                 log(DEBUG,"Removed casted user from channel's internal list");
230                 internal_voice_userlist.erase(a);
231                 return; 
232         }
233 }
234
235 std::map<char*,char*> *chanrec::GetUsers()
236 {
237         return &internal_userlist;
238 }
239
240 std::map<char*,char*> *chanrec::GetOppedUsers()
241 {
242         return &internal_op_userlist;
243 }
244
245 std::map<char*,char*> *chanrec::GetHalfoppedUsers()
246 {
247         return &internal_halfop_userlist;
248 }
249
250 std::map<char*,char*> *chanrec::GetVoicedUsers()
251 {
252         return &internal_voice_userlist;
253 }
254
255 /* 
256  * add a channel to a user, creating the record for it if needed and linking
257  * it to the user record 
258  */
259
260 chanrec* add_channel(userrec *user, const char* cn, const char* key, bool override)
261 {
262         if ((!user) || (!cn))
263         {
264                 log(DEFAULT,"*** BUG *** add_channel was given an invalid parameter");
265                 return 0;
266         }
267
268         int created = 0;
269         char cname[MAXBUF];
270         int MOD_RESULT = 0;
271         strlcpy(cname,cn,CHANMAX);
272         log(DEBUG,"cname='%s' cn='%s'",cname,cn);
273
274         log(DEBUG,"add_channel: %s %s",user->nick,cname);
275
276         chanrec* Ptr = FindChan(cname);
277
278         if (!Ptr)
279         {
280                 if (user->fd > -1)
281                 {
282                         MOD_RESULT = 0;
283                         FOREACH_RESULT(I_OnUserPreJoin,OnUserPreJoin(user,NULL,cname));
284                         if (MOD_RESULT == 1)
285                                 return NULL;
286                 }
287
288                 /* create a new one */
289                 chanlist[cname] = new chanrec();
290                 strlcpy(chanlist[cname]->name, cname,CHANMAX);
291                 chanlist[cname]->binarymodes = CM_TOPICLOCK | CM_NOEXTERNAL;
292                 chanlist[cname]->created = TIME;
293                 *chanlist[cname]->topic = 0;
294                 strlcpy(chanlist[cname]->setby, user->nick,NICKMAX);
295                 chanlist[cname]->topicset = 0;
296                 Ptr = chanlist[cname];
297                 log(DEBUG,"add_channel: created: %s",cname);
298                 /*
299                  * set created to 2 to indicate user
300                  * is the first in the channel
301                  * and should be given ops
302                  */
303                 created = 2;
304         }
305         else
306         {
307                 /* Already on the channel */
308                 if (has_channel(user,Ptr))
309                         return NULL;
310
311                 /*
312                  * remote users are allowed us to bypass channel modes
313                  * and bans (used by servers)
314                  */
315                 if (IS_LOCAL(user)) /* was a check on fd > -1 */
316                 {
317                         MOD_RESULT = 0;
318                         FOREACH_RESULT(I_OnUserPreJoin,OnUserPreJoin(user,Ptr,cname));
319                         if (MOD_RESULT == 1)
320                         {
321                                 return NULL;
322                         }
323                         else if (MOD_RESULT == 0)
324                         {
325                                 if (*Ptr->key)
326                                 {
327                                         MOD_RESULT = 0;
328                                         FOREACH_RESULT(I_OnCheckKey,OnCheckKey(user, Ptr, key ? key : ""));
329                                         if (!MOD_RESULT)
330                                         {
331                                                 if (!key)
332                                                 {
333                                                         log(DEBUG,"add_channel: no key given in JOIN");
334                                                         WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name);
335                                                         return NULL;
336                                                 }
337                                                 else
338                                                 {
339                                                         if (strcmp(key,Ptr->key))
340                                                         {
341                                                                 log(DEBUG,"add_channel: bad key given in JOIN");
342                                                                 WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name);
343                                                                 return NULL;
344                                                         }
345                                                 }
346                                         }
347                                 }
348                                 if (Ptr->binarymodes & CM_INVITEONLY)
349                                 {
350                                         MOD_RESULT = 0;
351                                         irc::string xname(Ptr->name);
352                                         FOREACH_RESULT(I_OnCheckInvite,OnCheckInvite(user, Ptr));
353                                         if (!MOD_RESULT)
354                                         {
355                                                 log(DEBUG,"add_channel: channel is +i");
356                                                 if (user->IsInvited(xname))
357                                                 {
358                                                         /* user was invited to channel */
359                                                         /* there may be an optional channel NOTICE here */
360                                                 }
361                                                 else
362                                                 {
363                                                         WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name);
364                                                         return NULL;
365                                                 }
366                                         }
367                                         user->RemoveInvite(xname);
368                                 }
369                                 if (Ptr->limit)
370                                 {
371                                         MOD_RESULT = 0;
372                                         FOREACH_RESULT(I_OnCheckLimit,OnCheckLimit(user, Ptr));
373                                         if (!MOD_RESULT)
374                                         {
375                                                 if (usercount(Ptr) >= Ptr->limit)
376                                                 {
377                                                         WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name);
378                                                         return NULL;
379                                                 }
380                                         }
381                                 }
382                                 if (Ptr->bans.size())
383                                 {
384                                         log(DEBUG,"add_channel: about to walk banlist");
385                                         MOD_RESULT = 0;
386                                         FOREACH_RESULT(I_OnCheckBan,OnCheckBan(user, Ptr));
387                                         if (!MOD_RESULT)
388                                         {
389                                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
390                                                 {
391                                                         if ((match(user->GetFullHost(),i->data)) || (match(user->GetFullRealHost(),i->data)) || (match((char*)inet_ntoa(user->ip4),i->data)))
392                                                         {
393                                                                 WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name);
394                                                                 return NULL;
395                                                         }
396                                                 }
397                                         }
398                                 }
399                         }
400                 }
401                 else
402                 {
403                         log(DEBUG,"Overridden checks");
404                 }
405                 created = 1;
406         }
407
408         log(DEBUG,"Passed channel checks");
409
410         for (unsigned int index =0; index < user->chans.size(); index++)
411         {
412                 if (user->chans[index].channel == NULL)
413                 {
414                         return ForceChan(Ptr,user->chans[index],user,created);
415                 }
416         }
417
418         /*
419          * XXX: If the user is an oper here, we can just extend their user->chans vector by one
420          * and put the channel in here. Same for remote users which are not bound by
421          * the channel limits. Otherwise, nope, youre boned.
422          */
423         if (!IS_LOCAL(user)) /* was a check on fd < 0 */
424         {
425                 ucrec a;
426                 chanrec* c = ForceChan(Ptr,a,user,created);
427                 user->chans.push_back(a);
428                 return c;
429         }
430         else if (strchr(user->modes,'o'))
431         {
432                 /* Oper allows extension up to the OPERMAXCHANS value */
433                 if (user->chans.size() < OPERMAXCHANS)
434                 {
435                         ucrec a;
436                         chanrec* c = ForceChan(Ptr,a,user,created);
437                         user->chans.push_back(a);
438                         return c;
439                 }
440         }
441
442         log(DEBUG,"add_channel: user channel max exceeded: %s %s",user->nick,cname);
443         WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname);
444         return NULL;
445 }
446
447 chanrec* ForceChan(chanrec* Ptr,ucrec &a,userrec* user, int created)
448 {
449         if (created == 2)
450         {
451                 /* first user in is given ops */
452                 a.uc_modes = UCMODE_OP;
453                 Ptr->AddOppedUser((char*)user);
454         }
455         else
456         {
457                 a.uc_modes = 0;
458         }
459
460         a.channel = Ptr;
461         Ptr->AddUser((char*)user);
462         WriteChannel(Ptr,user,"JOIN :%s",Ptr->name);
463         log(DEBUG,"Sent JOIN to client");
464
465         if (Ptr->topicset)
466         {
467                 WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic);
468                 WriteServ(user->fd,"333 %s %s %s %lu", user->nick, Ptr->name, Ptr->setby, (unsigned long)Ptr->topicset);
469         }
470
471         userlist(user,Ptr);
472         WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name);
473         FOREACH_MOD(I_OnUserJoin,OnUserJoin(user,Ptr));
474         return Ptr;
475 }
476
477 /*
478  *remove a channel from a users record, and remove the record from memory
479  * if the channel has become empty
480  */
481
482 chanrec* del_channel(userrec *user, const char* cname, const char* reason, bool local)
483 {
484         if ((!user) || (!cname))
485         {
486                 log(DEFAULT,"*** BUG *** del_channel was given an invalid parameter");
487                 return NULL;
488         }
489
490         chanrec* Ptr = FindChan(cname);
491
492         if (!Ptr)
493                 return NULL;
494
495         log(DEBUG,"del_channel: removing: %s %s",user->nick,Ptr->name);
496
497         for (unsigned int i =0; i < user->chans.size(); i++)
498         {
499                 /* zap it from the channel list of the user */
500                 if (user->chans[i].channel == Ptr)
501                 {
502                         if (reason)
503                         {
504                                 FOREACH_MOD(I_OnUserPart,OnUserPart(user,Ptr,reason));
505                                 WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason);
506                         }
507                         else
508                         {
509                                 FOREACH_MOD(I_OnUserPart,OnUserPart(user,Ptr,""));
510                                 WriteChannel(Ptr,user,"PART :%s",Ptr->name);
511                         }
512                         user->chans[i].uc_modes = 0;
513                         user->chans[i].channel = NULL;
514                         log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
515                         break;
516                 }
517         }
518
519         Ptr->DelUser((char*)user);
520
521         /* if there are no users left on the channel */
522         if (!usercount(Ptr))
523         {
524                 chan_hash::iterator iter = chanlist.find(Ptr->name);
525
526                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
527
528                 /* kill the record */
529                 if (iter != chanlist.end())
530                 {
531                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
532                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(Ptr));
533                         delete Ptr;
534                         chanlist.erase(iter);
535                 }
536         }
537
538         return NULL;
539 }
540
541 void server_kick_channel(userrec* user, chanrec* Ptr, char* reason, bool triggerevents)
542 {
543         if ((!user) || (!Ptr) || (!reason))
544         {
545                 return;
546         }
547
548         if (IS_LOCAL(user))
549         {
550                 if (!has_channel(user,Ptr))
551                 {
552                         /* Not on channel */
553                         return;
554                 }
555         }
556         
557         if (triggerevents)
558         {
559                 FOREACH_MOD(I_OnUserKick,OnUserKick(NULL,user,Ptr,reason));
560         }
561
562         for (unsigned int i =0; i < user->chans.size(); i++)
563         {
564                 if (user->chans[i].channel)
565                 if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
566                 {
567                         WriteChannelWithServ(Config->ServerName,Ptr,"KICK %s %s :%s",Ptr->name, user->nick, reason);
568                         user->chans[i].uc_modes = 0;
569                         user->chans[i].channel = NULL;
570                         break;
571                 }
572         }
573
574         Ptr->DelUser((char*)user);
575
576         if (!usercount(Ptr))
577         {
578                 chan_hash::iterator iter = chanlist.find(Ptr->name);
579                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
580                 /* kill the record */
581                 if (iter != chanlist.end())
582                 {
583                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
584                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(Ptr));
585                         delete Ptr;
586                         chanlist.erase(iter);
587                 }
588         }
589 }
590
591 void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason)
592 {
593         if ((!src) || (!user) || (!Ptr) || (!reason))
594         {
595                 log(DEFAULT,"*** BUG *** kick_channel was given an invalid parameter");
596                 return;
597         }
598
599         log(DEBUG,"kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick);
600
601         if (IS_LOCAL(src))
602         {
603                 if (!has_channel(user,Ptr))
604                 {
605                         WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name);
606                         return;
607                 }
608                 int MOD_RESULT = 0;
609
610                 if (!is_uline(src->server))
611                 {
612                         MOD_RESULT = 0;
613                         FOREACH_RESULT(I_OnUserPreKick,OnUserPreKick(src,user,Ptr,reason));
614                         if (MOD_RESULT == 1)
615                                 return;
616                 }
617                 /* Set to -1 by OnUserPreKick if explicit allow was set */
618                 if (MOD_RESULT != -1)
619                 {
620                         FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(src,user,Ptr,AC_KICK));
621                         if ((MOD_RESULT == ACR_DENY) && (!is_uline(src->server)))
622                                 return;
623         
624                         if ((MOD_RESULT == ACR_DEFAULT) || (!is_uline(src->server)))
625                         {
626                                 if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr)))
627                                 {
628                                         if (cstatus(src,Ptr) == STATUS_HOP)
629                                         {
630                                                 WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name);
631                                         }
632                                         else
633                                         {
634                                                 WriteServ(src->fd,"482 %s %s :You must be at least a half-operator",src->nick, Ptr->name);
635                                         }
636                 
637                                         return;
638                                 }
639                         }
640                 }
641         }
642
643         FOREACH_MOD(I_OnUserKick,OnUserKick(src,user,Ptr,reason));
644
645         for (unsigned int i =0; i < user->chans.size(); i++)
646         {
647                 /* zap it from the channel list of the user */
648                 if (user->chans[i].channel)
649                 {
650                         if (!strcasecmp(user->chans[i].channel->name,Ptr->name))
651                         {
652                                 WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason);
653                                 user->chans[i].uc_modes = 0;
654                                 user->chans[i].channel = NULL;
655                                 log(DEBUG,"del_channel: unlinked: %s %s",user->nick,Ptr->name);
656                                 break;
657                         }
658                 }
659         }
660
661         Ptr->DelUser((char*)user);
662
663         /* if there are no users left on the channel */
664         if (!usercount(Ptr))
665         {
666                 chan_hash::iterator iter = chanlist.find(Ptr->name);
667
668                 log(DEBUG,"del_channel: destroying channel: %s",Ptr->name);
669
670                 /* kill the record */
671                 if (iter != chanlist.end())
672                 {
673                         log(DEBUG,"del_channel: destroyed: %s",Ptr->name);
674                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(Ptr));
675                         delete Ptr;
676                         chanlist.erase(iter);
677                 }
678         }
679 }
680
681