]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Added explicit oper tracking in a vector of userrec* pointers, optimizes sending...
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 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 #include "inspircd.h"
18 #include "inspircd_io.h"
19 #include "inspircd_util.h"
20 #include "inspircd_config.h"
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/utsname.h>
26 #include <cstdio>
27 #include <time.h>
28 #include <string>
29 #ifdef GCC3
30 #include <ext/hash_map>
31 #else
32 #include <hash_map>
33 #endif
34 #include <map>
35 #include <sstream>
36 #include <vector>
37 #include <errno.h>
38 #include <deque>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <sched.h>
42 #include "connection.h"
43 #include "users.h"
44 #include "servers.h"
45 #include "ctables.h"
46 #include "globals.h"
47 #include "modules.h"
48 #include "dynamic.h"
49 #include "wildcard.h"
50 #include "message.h"
51 #include "commands.h"
52 #include "xline.h"
53 #include "inspstring.h"
54
55 using namespace std;
56
57 extern int MODCOUNT;
58 extern std::vector<Module*> modules;
59 extern std::vector<ircd_module*> factory;
60 extern std::vector<std::string> module_names;
61
62
63 extern int LogLevel;
64 extern char ServerName[MAXBUF];
65 extern char Network[MAXBUF];
66 extern char ServerDesc[MAXBUF];
67 extern char AdminName[MAXBUF];
68 extern char AdminEmail[MAXBUF];
69 extern char AdminNick[MAXBUF];
70 extern char diepass[MAXBUF];
71 extern char restartpass[MAXBUF];
72 extern char motd[MAXBUF];
73 extern char rules[MAXBUF];
74 extern char list[MAXBUF];
75 extern char PrefixQuit[MAXBUF];
76 extern char DieValue[MAXBUF];
77
78 extern bool AllowHalfop;
79 extern bool AllowProtect;
80 extern bool AllowFounder;
81
82 extern time_t TIME;
83
84 char* give_ops(userrec *user,char *dest,chanrec *chan,int status)
85 {
86         userrec *d;
87         
88         if ((!user) || (!dest) || (!chan))
89         {
90                 log(DEFAULT,"*** BUG *** give_ops was given an invalid parameter");
91                 return NULL;
92         }
93
94         if (!isnick(dest))
95         {
96                 log(DEFAULT,"the target nickname given to give_ops was invalid");
97                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
98                 return NULL;
99         }
100         d = Find(dest);
101         if (!d)
102         {
103                 log(DEFAULT,"the target nickname given to give_ops couldnt be found");
104                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
105                 return NULL;
106         }
107         else
108         {
109
110                 int MOD_RESULT = 0;
111                 FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_OP));
112                 
113                 if (MOD_RESULT == ACR_DENY)
114                         return NULL;
115                 if (MOD_RESULT == ACR_DEFAULT)
116                 {
117                         if ((status < STATUS_OP) && (!is_uline(user->server)))
118                         {
119                                 log(DEBUG,"%s cant give ops to %s because they nave status %d and needs %d",user->nick,dest,status,STATUS_OP);
120                                 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
121                                 return NULL;
122                         }
123                 }
124
125
126                 for (int i = 0; i != MAXCHANS; i++)
127                 {
128                         if ((d->chans[i].channel != NULL) && (chan != NULL))
129                         if (!strcasecmp(d->chans[i].channel->name,chan->name))
130                         {
131                         if (d->chans[i].uc_modes & UCMODE_OP)
132                                 {
133                                         /* mode already set on user, dont allow multiple */
134                                         log(DEFAULT,"The target user given to give_ops was already opped on the channel");
135                                         return NULL;
136                                 }
137                                 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP;
138                                 log(DEBUG,"gave ops: %s %s",d->chans[i].channel->name,d->nick);
139                                 return d->nick;
140                         }
141                 }
142                 log(DEFAULT,"The target channel given to give_ops was not in the users mode list");
143         }
144         return NULL;
145 }
146
147 char* give_hops(userrec *user,char *dest,chanrec *chan,int status)
148 {
149         userrec *d;
150         
151         if ((!user) || (!dest) || (!chan))
152         {
153                 log(DEFAULT,"*** BUG *** give_hops was given an invalid parameter");
154                 return NULL;
155         }
156
157         d = Find(dest);
158         if (!isnick(dest))
159         {
160                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
161                 return NULL;
162         }
163         if (!d)
164         {
165                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
166                 return NULL;
167         }
168         else
169         {
170                 int MOD_RESULT = 0;
171                 FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_HALFOP));
172                 
173                 if (MOD_RESULT == ACR_DENY)
174                         return NULL;
175                 if (MOD_RESULT == ACR_DEFAULT)
176                 {
177                         if ((status < STATUS_OP) && (!is_uline(user->server)))
178                         {
179                                 WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name);
180                                 return NULL;
181                         }
182                 }
183
184                 for (int i = 0; i != MAXCHANS; i++)
185                 {
186                         if ((d->chans[i].channel != NULL) && (chan != NULL))
187                         if (!strcasecmp(d->chans[i].channel->name,chan->name))
188                         {
189                                 if (d->chans[i].uc_modes & UCMODE_HOP)
190                                 {
191                                         /* mode already set on user, dont allow multiple */
192                                         return NULL;
193                                 }
194                                 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP;
195                                 log(DEBUG,"gave h-ops: %s %s",d->chans[i].channel->name,d->nick);
196                                 return d->nick;
197                         }
198                 }
199         }
200         return NULL;
201 }
202
203 char* give_voice(userrec *user,char *dest,chanrec *chan,int status)
204 {
205         userrec *d;
206         
207         if ((!user) || (!dest) || (!chan))
208         {
209                 log(DEFAULT,"*** BUG *** give_voice was given an invalid parameter");
210                 return NULL;
211         }
212
213         d = Find(dest);
214         if (!isnick(dest))
215         {
216                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
217                 return NULL;
218         }
219         if (!d)
220         {
221                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
222                 return NULL;
223         }
224         else
225         {
226                 int MOD_RESULT = 0;
227                 FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_VOICE));
228                 
229                 if (MOD_RESULT == ACR_DENY)
230                         return NULL;
231                 if (MOD_RESULT == ACR_DEFAULT)
232                 {
233                         if ((status < STATUS_HOP) && (!is_uline(user->server)))
234                         {
235                                 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
236                                 return NULL;
237                         }
238                 }
239
240                 for (int i = 0; i != MAXCHANS; i++)
241                 {
242                         if ((d->chans[i].channel != NULL) && (chan != NULL))
243                         if (!strcasecmp(d->chans[i].channel->name,chan->name))
244                         {
245                                 if (d->chans[i].uc_modes & UCMODE_VOICE)
246                                 {
247                                         /* mode already set on user, dont allow multiple */
248                                         return NULL;
249                                 }
250                                 d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE;
251                                 log(DEBUG,"gave voice: %s %s",d->chans[i].channel->name,d->nick);
252                                 return d->nick;
253                         }
254                 }
255         }
256         return NULL;
257 }
258
259 char* take_ops(userrec *user,char *dest,chanrec *chan,int status)
260 {
261         userrec *d;
262         
263         if ((!user) || (!dest) || (!chan))
264         {
265                 log(DEFAULT,"*** BUG *** take_ops was given an invalid parameter");
266                 return NULL;
267         }
268
269         d = Find(dest);
270         if (!isnick(dest))
271         {
272                 log(DEBUG,"take_ops was given an invalid target nickname of %s",dest);
273                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
274                 return NULL;
275         }
276         if (!d)
277         {
278                 log(DEBUG,"take_ops couldnt resolve the target nickname: %s",dest);
279                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
280                 return NULL;
281         }
282         else
283         {
284                 int MOD_RESULT = 0;
285                 FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEOP));
286                 
287                 if (MOD_RESULT == ACR_DENY)
288                         return NULL;
289                 if (MOD_RESULT == ACR_DEFAULT)
290                 {
291                         if ((status < STATUS_OP) && (!is_uline(user->server)))
292                         {
293                                 WriteServ(user->fd,"482 %s %s :You are not a channel operator",user->nick, chan->name);
294                                 return NULL;
295                         }
296                 }
297
298                 for (int i = 0; i != MAXCHANS; i++)
299                 {
300                         if ((d->chans[i].channel != NULL) && (chan != NULL))
301                         if (!strcasecmp(d->chans[i].channel->name,chan->name))
302                         {
303                                 if ((d->chans[i].uc_modes & UCMODE_OP) == 0)
304                                 {
305                                         /* mode already set on user, dont allow multiple */
306                                         return NULL;
307                                 }
308                                 d->chans[i].uc_modes ^= UCMODE_OP;
309                                 log(DEBUG,"took ops: %s %s",d->chans[i].channel->name,d->nick);
310                                 return d->nick;
311                         }
312                 }
313                 log(DEBUG,"take_ops couldnt locate the target channel in the target users list");
314         }
315         return NULL;
316 }
317
318 char* take_hops(userrec *user,char *dest,chanrec *chan,int status)
319 {
320         userrec *d;
321         
322         if ((!user) || (!dest) || (!chan))
323         {
324                 log(DEFAULT,"*** BUG *** take_hops was given an invalid parameter");
325                 return NULL;
326         }
327
328         d = Find(dest);
329         if (!isnick(dest))
330         {
331                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
332                 return NULL;
333         }
334         if (!d)
335         {
336                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
337                 return NULL;
338         }
339         else
340         {
341                 int MOD_RESULT = 0;
342                 FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEHALFOP));
343                 
344                 if (MOD_RESULT == ACR_DENY)
345                         return NULL;
346                 if (MOD_RESULT == ACR_DEFAULT)
347                 {
348                         if ((status < STATUS_OP) && (!is_uline(user->server)))
349                         {
350                                 WriteServ(user->fd,"482 %s %s :You are not a channel operator",user->nick, chan->name);
351                                 return NULL;
352                         }
353                 }
354
355                 for (int i = 0; i != MAXCHANS; i++)
356                 {
357                         if ((d->chans[i].channel != NULL) && (chan != NULL))
358                         if (!strcasecmp(d->chans[i].channel->name,chan->name))
359                         {
360                                 if ((d->chans[i].uc_modes & UCMODE_HOP) == 0)
361                                 {
362                                         /* mode already set on user, dont allow multiple */
363                                         return NULL;
364                                 }
365                                 d->chans[i].uc_modes ^= UCMODE_HOP;
366                                 log(DEBUG,"took h-ops: %s %s",d->chans[i].channel->name,d->nick);
367                                 return d->nick;
368                         }
369                 }
370         }
371         return NULL;
372 }
373
374 char* take_voice(userrec *user,char *dest,chanrec *chan,int status)
375 {
376         userrec *d;
377         
378         if ((!user) || (!dest) || (!chan))
379         {
380                 log(DEFAULT,"*** BUG *** take_voice was given an invalid parameter");
381                 return NULL;
382         }
383
384         d = Find(dest);
385         if (!isnick(dest))
386         {
387                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
388                 return NULL;
389         }
390         if (!d)
391         {
392                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest);
393                 return NULL;
394         }
395         else
396         {
397                 int MOD_RESULT = 0;
398                 FOREACH_RESULT(OnAccessCheck(user,d,chan,AC_DEVOICE));
399                 
400                 if (MOD_RESULT == ACR_DENY)
401                         return NULL;
402                 if (MOD_RESULT == ACR_DEFAULT)
403                 {
404                         if ((status < STATUS_HOP) && (!is_uline(user->server)))
405                         {
406                                 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, chan->name);
407                                 return NULL;
408                         }
409                 }
410
411                 for (int i = 0; i != MAXCHANS; i++)
412                 {
413                         if ((d->chans[i].channel != NULL) && (chan != NULL))
414                         if (!strcasecmp(d->chans[i].channel->name,chan->name))
415                         {
416                                 if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0)
417                                 {
418                                         /* mode already set on user, dont allow multiple */
419                                         return NULL;
420                                 }
421                                 d->chans[i].uc_modes ^= UCMODE_VOICE;
422                                 log(DEBUG,"took voice: %s %s",d->chans[i].channel->name,d->nick);
423                                 return d->nick;
424                         }
425                 }
426         }
427         return NULL;
428 }
429
430 char* add_ban(userrec *user,char *dest,chanrec *chan,int status)
431 {
432         if ((!user) || (!dest) || (!chan)) {
433                 log(DEFAULT,"*** BUG *** add_ban was given an invalid parameter");
434                 return NULL;
435         }
436
437         BanItem b;
438         if ((!user) || (!dest) || (!chan))
439                 return NULL;
440         if (strchr(dest,'!')==0)
441                 return NULL;
442         if (strchr(dest,'@')==0)
443                 return NULL;
444         for (int i = 0; i < strlen(dest); i++)
445                 if (dest[i] < 32)
446                         return NULL;
447         for (int i = 0; i < strlen(dest); i++)
448                 if (dest[i] > 126)
449                         return NULL;
450         int c = 0;
451         for (int i = 0; i < strlen(dest); i++)
452                 if (dest[i] == '!')
453                         c++;
454         if (c>1)
455                 return NULL;
456         c = 0;
457         for (int i = 0; i < strlen(dest); i++)
458                 if (dest[i] == '@')
459                         c++;
460         if (c>1)
461                 return NULL;
462
463         long maxbans = GetMaxBans(chan->name);
464         if (chan->bans.size() > maxbans)
465         {
466                 WriteServ(user->fd,"478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %d)",user->nick, chan->name,chan->name,maxbans);
467                 return NULL;
468         }
469
470         log(DEBUG,"add_ban: %s %s",chan->name,user->nick);
471
472         TidyBan(dest);
473         for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
474         {
475                 if (!strcasecmp(i->data,dest))
476                 {
477                         // dont allow a user to set the same ban twice
478                         return NULL;
479                 }
480         }
481
482         b.set_time = TIME;
483         strncpy(b.data,dest,MAXBUF);
484         strncpy(b.set_by,user->nick,NICKMAX);
485         chan->bans.push_back(b);
486         return dest;
487 }
488
489 char* take_ban(userrec *user,char *dest,chanrec *chan,int status)
490 {
491         if ((!user) || (!dest) || (!chan)) {
492                 log(DEFAULT,"*** BUG *** take_ban was given an invalid parameter");
493                 return 0;
494         }
495
496         log(DEBUG,"del_ban: %s %s",chan->name,user->nick);
497         for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++)
498         {
499                 if (!strcasecmp(i->data,dest))
500                 {
501                         chan->bans.erase(i);
502                         return dest;
503                 }
504         }
505         return NULL;
506 }
507
508 void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt, bool servermode, bool silent, bool local)
509 {
510         if (!parameters) {
511                 log(DEFAULT,"*** BUG *** process_modes was given an invalid parameter");
512                 return;
513         }
514
515         char modelist[MAXBUF];
516         char outlist[MAXBUF];
517         char outstr[MAXBUF];
518         char outpars[32][MAXBUF];
519         int param = 2;
520         int pc = 0;
521         int ptr = 0;
522         int mdir = 1;
523         char* r = NULL;
524         bool k_set = false, l_set = false;
525
526         if (pcnt < 2)
527         {
528                 return;
529         }
530
531         int MOD_RESULT = 0;
532         FOREACH_RESULT(OnAccessCheck(user,NULL,chan,AC_GENERAL_MODE));
533         
534         if (MOD_RESULT == ACR_DENY)
535                 return;
536
537         log(DEBUG,"process_modes: start: parameters=%d",pcnt);
538
539         strlcpy(modelist,parameters[1],MAXBUF); /* mode list, e.g. +oo-o *
540                                                  * parameters[2] onwards are parameters for
541                                                  * modes that require them :) */
542         strlcpy(outlist,"+",MAXBUF);
543         mdir = 1;
544
545         log(DEBUG,"process_modes: modelist: %s",modelist);
546
547         for (ptr = 0; ptr < strlen(modelist); ptr++)
548         {
549                 r = NULL;
550
551                 {
552                         log(DEBUG,"process_modes: modechar: %c",modelist[ptr]);
553
554                         char modechar = modelist[ptr];
555                         switch (modelist[ptr])
556                         {
557                                 case '-':
558                                         if (mdir != 0)
559                                         {
560                                                 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
561                                                 {
562                                                         outlist[strlen(outlist)-1] = '-';
563                                                 }
564                                                 else
565                                                 {
566                                                         strcat(outlist,"-");
567                                                 }
568                                         }
569                                         mdir = 0;
570                                         
571                                 break;                  
572
573                                 case '+':
574                                         if (mdir != 1)
575                                         {
576                                                 if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-'))
577                                                 {
578                                                         outlist[strlen(outlist)-1] = '+';
579                                                 }
580                                                 else
581                                                 {
582                                                         strcat(outlist,"+");
583                                                 }
584                                         }
585                                         mdir = 1;
586                                 break;
587
588                                 case 'o':
589                                         log(DEBUG,"Ops");
590                                         if ((param >= pcnt)) break;
591                                         log(DEBUG,"Enough parameters left");
592                                         if (mdir == 1)
593                                         {
594                                                 MOD_RESULT = 0;
595                                                 FOREACH_RESULT(OnRawMode(user, chan, 'o', parameters[param], true, 1));
596                                                 if (!MOD_RESULT)
597                                                 {
598                                                         log(DEBUG,"calling give_ops");
599                                                         r = give_ops(user,parameters[param++],chan,status);
600                                                 }
601                                                 else param++;
602                                         }
603                                         else
604                                         {
605                                                 MOD_RESULT = 0;
606                                                 FOREACH_RESULT(OnRawMode(user, chan, 'o', parameters[param], false, 1));
607                                                 if (!MOD_RESULT)
608                                                 {
609                                                         log(DEBUG,"calling take_ops");
610                                                         r = take_ops(user,parameters[param++],chan,status);
611                                                 }
612                                                 else param++;
613                                         }
614                                         if (r)
615                                         {
616                                                 strlcat(outlist,"o",MAXBUF);
617                                                 strlcpy(outpars[pc++],r,MAXBUF);
618                                         }
619                                 break;
620                         
621                                 case 'h':
622                                         if (((param >= pcnt)) || (!AllowHalfop)) break;
623                                         if (mdir == 1)
624                                         {
625                                                 MOD_RESULT = 0;
626                                                 FOREACH_RESULT(OnRawMode(user, chan, 'h', parameters[param], true, 1));
627                                                 if (!MOD_RESULT)
628                                                 {
629                                                         r = give_hops(user,parameters[param++],chan,status);
630                                                 }
631                                                 else param++;
632                                         }
633                                         else
634                                         {
635                                                 MOD_RESULT = 0;
636                                                 FOREACH_RESULT(OnRawMode(user, chan, 'h', parameters[param], false, 1));
637                                                 if (!MOD_RESULT)
638                                                 {
639                                                         r = take_hops(user,parameters[param++],chan,status);
640                                                 }
641                                                 else param++;
642                                         }
643                                         if (r)
644                                         {
645                                                 strlcat(outlist,"h",MAXBUF);
646                                                 strlcpy(outpars[pc++],r,MAXBUF);
647                                         }
648                                 break;
649                         
650                                 
651                                 case 'v':
652                                         if ((param >= pcnt)) break;
653                                         if (mdir == 1)
654                                         {
655                                                 MOD_RESULT = 0;
656                                                 FOREACH_RESULT(OnRawMode(user, chan, 'v', parameters[param], true, 1));
657                                                 if (!MOD_RESULT)
658                                                 {
659                                                         r = give_voice(user,parameters[param++],chan,status);
660                                                 }
661                                                 else param++;
662                                         }
663                                         else
664                                         {
665                                                 MOD_RESULT = 0;
666                                                 FOREACH_RESULT(OnRawMode(user, chan, 'v', parameters[param], false, 1));
667                                                 if (!MOD_RESULT)
668                                                 {
669                                                         r = take_voice(user,parameters[param++],chan,status);
670                                                 }
671                                                 else param++;
672                                         }
673                                         if (r)
674                                         {
675                                                 strlcat(outlist,"v",MAXBUF);
676                                                 strlcpy(outpars[pc++],r,MAXBUF);
677                                         }
678                                 break;
679                                 
680                                 case 'b':
681                                         if ((param >= pcnt)) break;
682                                         if (mdir == 1)
683                                         {
684                                                 MOD_RESULT = 0;
685                                                 FOREACH_RESULT(OnRawMode(user, chan, 'b', parameters[param], true, 1));
686                                                 if (!MOD_RESULT)
687                                                 {
688                                                         r = add_ban(user,parameters[param++],chan,status);
689                                                 }
690                                                 else param++;
691                                         }
692                                         else
693                                         {
694                                                 MOD_RESULT = 0;
695                                                 FOREACH_RESULT(OnRawMode(user, chan, 'b', parameters[param], false, 1));
696                                                 if (!MOD_RESULT)
697                                                 {
698                                                         r = take_ban(user,parameters[param++],chan,status);
699                                                 }
700                                                 else param++;
701                                         }
702                                         if (r)
703                                         {
704                                                 strlcat(outlist,"b",MAXBUF);
705                                                 strlcpy(outpars[pc++],parameters[param-1],MAXBUF);
706                                         }
707                                 break;
708
709
710                                 case 'k':
711                                         if ((param >= pcnt))
712                                                 break;
713
714                                         if (mdir == 1)
715                                         {
716                                                 if (k_set)
717                                                         break;
718                                                 
719                                                 if (!strcmp(chan->key,""))
720                                                 {
721                                                         MOD_RESULT = 0;
722                                                         FOREACH_RESULT(OnRawMode(user, chan, 'k', parameters[param], true, 1));
723                                                         if (!MOD_RESULT)
724                                                         {
725                                                                 strcat(outlist,"k");
726                                                                 char key[MAXBUF];
727                                                                 strlcpy(key,parameters[param++],MAXBUF);
728                                                                 if (strlen(key)>32) {
729                                                                         key[31] = '\0';
730                                                                 }
731                                                                 strlcpy(outpars[pc++],key,MAXBUF);
732                                                                 strlcpy(chan->key,key,MAXBUF);
733                                                                 k_set = true;
734                                                         }
735                                                         else param++;
736                                                 }
737                                         }
738                                         else
739                                         {
740                                                 /* checks on -k are case sensitive and only accurate to the
741                                                    first 32 characters */
742                                                 char key[MAXBUF];
743                                                 MOD_RESULT = 0;
744                                                 FOREACH_RESULT(OnRawMode(user, chan, 'k', parameters[param], false, 1));
745                                                 if (!MOD_RESULT)
746                                                 {
747                                                         strlcpy(key,parameters[param++],MAXBUF);
748                                                         if (strlen(key)>32)
749                                                         {
750                                                                 key[31] = '\0';
751                                                         }
752                                                         /* only allow -k if correct key given */
753                                                         if (!strcmp(chan->key,key))
754                                                         {
755                                                                 strlcat(outlist,"k",MAXBUF);
756                                                                 strlcpy(chan->key,"",MAXBUF);
757                                                                 strlcpy(outpars[pc++],key,MAXBUF);
758                                                         }
759                                                 }
760                                                 else param++;
761                                         }
762                                 break;
763                                 
764                                 case 'l':
765                                         if (mdir == 0)
766                                         {
767                                                 MOD_RESULT = 0;
768                                                 FOREACH_RESULT(OnRawMode(user, chan, 'l', "", false, 0));
769                                                 if (!MOD_RESULT)
770                                                 {
771                                                         if (chan->limit)
772                                                         {
773                                                                 strcat(outlist,"l");
774                                                                 chan->limit = 0;
775                                                         }
776                                                 }
777                                         }
778                                         
779                                         if ((param >= pcnt)) break;
780                                         if (mdir == 1)
781                                         {
782                                                 if (l_set)
783                                                         break;
784                                                 
785                                                 bool invalid = false;
786                                                 for (int i = 0; i < strlen(parameters[param]); i++)
787                                                 {
788                                                         if ((parameters[param][i] < '0') || (parameters[param][i] > '9'))
789                                                         {
790                                                                 invalid = true;
791                                                         }
792                                                 }
793                                                 if (atoi(parameters[param]) < 1)
794                                                 {
795                                                         invalid = true;
796                                                 }
797
798                                                 if (invalid)
799                                                         break;
800
801                                                 MOD_RESULT = 0;
802                                                 FOREACH_RESULT(OnRawMode(user, chan, 'l', parameters[param], true, 1));
803                                                 if (!MOD_RESULT)
804                                                 {
805         
806                                                         chan->limit = atoi(parameters[param]);
807                                                         
808                                                         // reported by mech: large values cause underflow
809                                                         if (chan->limit < 0)
810                                                                 chan->limit = 0x7FFFFF;
811                                                 }
812                                                         
813                                                 if (chan->limit)
814                                                 {
815                                                         strlcat(outlist,"l",MAXBUF);
816                                                         strlcpy(outpars[pc++],parameters[param++],MAXBUF);
817                                                         l_set = true;
818                                                 }
819                                         }
820                                 break;
821                                 
822                                 case 'i':
823                                         MOD_RESULT = 0;
824                                         FOREACH_RESULT(OnRawMode(user, chan, 'i', "", mdir, 0));
825                                         if (!MOD_RESULT)
826                                         {
827                                                 if (chan->inviteonly != mdir)
828                                                 {
829                                                         strlcat(outlist,"i",MAXBUF);
830                                                 }
831                                                 chan->inviteonly = mdir;
832                                         }
833                                 break;
834                                 
835                                 case 't':
836                                         MOD_RESULT = 0;
837                                         FOREACH_RESULT(OnRawMode(user, chan, 't', "", mdir, 0));
838                                         if (!MOD_RESULT)
839                                         {
840                                                 if (chan->topiclock != mdir)
841                                                 {
842                                                         strlcat(outlist,"t",MAXBUF);
843                                                 }
844                                                 chan->topiclock = mdir;
845                                         }
846                                 break;
847                                 
848                                 case 'n':
849                                         MOD_RESULT = 0;
850                                         FOREACH_RESULT(OnRawMode(user, chan, 'n', "", mdir, 0));
851                                         if (!MOD_RESULT)
852                                         {
853                                                 if (chan->noexternal != mdir)
854                                                 {
855                                                         strlcat(outlist,"n",MAXBUF);
856                                                 }
857                                                 chan->noexternal = mdir;
858                                         }
859                                 break;
860                                 
861                                 case 'm':
862                                         MOD_RESULT = 0;
863                                         FOREACH_RESULT(OnRawMode(user, chan, 'm', "", mdir, 0));
864                                         if (!MOD_RESULT)
865                                         {
866                                                 if (chan->moderated != mdir)
867                                                 {
868                                                         strlcat(outlist,"m",MAXBUF);
869                                                 }
870                                                 chan->moderated = mdir;
871                                         }
872                                 break;
873                                 
874                                 case 's':
875                                         MOD_RESULT = 0;
876                                         FOREACH_RESULT(OnRawMode(user, chan, 's', "", mdir, 0));
877                                         if (!MOD_RESULT)
878                                         {
879                                                 if (chan->secret != mdir)
880                                                 {
881                                                         strcat(outlist,"s");
882                                                         if (chan->c_private)
883                                                         {
884                                                                 chan->c_private = 0;
885                                                                 if (mdir)
886                                                                 {
887                                                                         strlcat(outlist,"-p+",MAXBUF);
888                                                                 }
889                                                                 else
890                                                                 {
891                                                                         strlcat(outlist,"+p-",MAXBUF);
892                                                                 }
893                                                         }
894                                                 }
895                                                 chan->secret = mdir;
896                                         }
897                                 break;
898                                 
899                                 case 'p':
900                                         MOD_RESULT = 0;
901                                         FOREACH_RESULT(OnRawMode(user, chan, 'p', "", mdir, 0));
902                                         if (!MOD_RESULT)
903                                         {
904                                                 if (chan->c_private != mdir)
905                                                 {
906                                                         strlcat(outlist,"p",MAXBUF);
907                                                         if (chan->secret)
908                                                         {
909                                                                 chan->secret = 0;
910                                                                 if (mdir)
911                                                                 {
912                                                                         strlcat(outlist,"-s+",MAXBUF);
913                                                                 }
914                                                                 else
915                                                                 {
916                                                                         strlcat(outlist,"+s-",MAXBUF);
917                                                                 }
918                                                         }
919                                                 }
920                                                 chan->c_private = mdir;
921                                         }
922                                 break;
923                                 
924                                 default:
925                                         log(DEBUG,"Preprocessing custom mode %c: modelist: %s",modechar,chan->custom_modes);
926                                         string_list p;
927                                         p.clear();
928                                         if (((!strchr(chan->custom_modes,modechar)) && (!mdir)) || ((strchr(chan->custom_modes,modechar)) && (mdir)))
929                                         {
930                                                 if (!ModeIsListMode(modechar,MT_CHANNEL))
931                                                 {
932                                                         log(DEBUG,"Mode %c isnt set on %s but trying to remove!",modechar,chan->name);
933                                                         break;
934                                                 }
935                                         }
936                                         if (ModeDefined(modechar,MT_CHANNEL))
937                                         {
938                                                 log(DEBUG,"A module has claimed this mode");
939                                                 if (param<pcnt)
940                                                 {
941                                                         if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
942                                                         {
943                                                                 p.push_back(parameters[param]);
944                                                         }
945                                                         if ((ModeDefinedOff(modechar,MT_CHANNEL)>0) && (!mdir))
946                                                         {
947                                                                 p.push_back(parameters[param]);
948                                                         }
949                                                 }
950                                                 bool handled = false;
951                                                 if (param>=pcnt)
952                                                 {
953                                                         // we're supposed to have a parameter, but none was given... so dont handle the mode.
954                                                         if (((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir)) || ((ModeDefinedOff(modechar,MT_CHANNEL)>0) && (!mdir))) 
955                                                         {
956                                                                 log(DEBUG,"Not enough parameters for module-mode %c",modechar);
957                                                                 handled = true;
958                                                                 param++;
959                                                         }
960                                                 }
961
962                                                 // BIG ASS IDIOTIC CODER WARNING!
963                                                 // Using OnRawMode on another modules mode's behavour 
964                                                 // will confuse the crap out of admins! just because you CAN
965                                                 // do it, doesnt mean you SHOULD!
966                                                 MOD_RESULT = 0;
967                                                 std::string para = "";
968                                                 if (p.size())
969                                                         para = p[0];
970                                                 FOREACH_RESULT(OnRawMode(user, chan, modechar, para, mdir, pcnt));
971                                                 if (!MOD_RESULT)
972                                                 {
973                                                         for (int i = 0; i <= MODCOUNT; i++)
974                                                         {
975                                                                 if (!handled)
976                                                                 {
977                                                                         int t = modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p);
978                                                                         if (t != 0)
979                                                                         {
980                                                                                 log(DEBUG,"OnExtendedMode returned nonzero for a module");
981                                                                                 char app[] = {modechar, 0};
982                                                                                 if (ModeIsListMode(modechar,MT_CHANNEL))
983                                                                                 {
984                                                                                         if (t == -1)
985                                                                                         {
986                                                                                                 pc++;
987                                                                                         }
988                                                                                         else
989                                                                                         {
990                                                                                                 if (ptr>0)
991                                                                                                 {
992                                                                                                         strlcat(outlist, app,MAXBUF);
993                                                                                                 }
994                                                                                                 strlcpy(outpars[pc++],parameters[param++],MAXBUF);
995                                                                                         }
996                                                                                 }
997                                                                                 else
998                                                                                 {
999                                                                                         if (ptr>0)
1000                                                                                         {
1001                                                                                                 if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
1002                                                                                                 {
1003                                                                                                         strlcat(outlist, app,MAXBUF);
1004                                                                                                 }
1005                                                                                                 else if (!strchr(outlist,modechar))
1006                                                                                                 {
1007                                                                                                         strlcat(outlist, app,MAXBUF);
1008                                                                                                 }
1009                                                                                         }
1010                                                                                         chan->SetCustomMode(modechar,mdir);
1011                                                                                         // include parameters in output if mode has them
1012                                                                                         if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
1013                                                                                         {
1014                                                                                                 chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
1015                                                                                                 strlcpy(outpars[pc++],parameters[param++],MAXBUF);
1016                                                                                         }
1017                                                                                 }
1018                                                                                 // break, because only one module can handle the mode.
1019                                                                                 handled = true;
1020                                                                         }
1021                                                                 }
1022                                                         }
1023                                                 }
1024                                         }
1025                                         else
1026                                         {
1027                                                 WriteServ(user->fd,"472 %s %c :is unknown mode char to me",user->nick,modechar);
1028                                         }
1029                                 break;
1030                                 
1031                         }
1032                 }
1033         }
1034
1035         /* this ensures only the *valid* modes are sent out onto the network */
1036         while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+'))
1037         {
1038                 outlist[strlen(outlist)-1] = '\0';
1039         }
1040         if (strcmp(outlist,""))
1041         {
1042                 strlcpy(outstr,outlist,MAXBUF);
1043                 for (ptr = 0; ptr < pc; ptr++)
1044                 {
1045                         strlcat(outstr," ",MAXBUF);
1046                         strlcat(outstr,outpars[ptr],MAXBUF);
1047                 }
1048                 if (local)
1049                 {
1050                         log(DEBUG,"Local mode change");
1051                         WriteChannelLocal(chan, user, "MODE %s %s",chan->name,outstr);
1052                 }
1053                 else
1054                 {
1055                         if (servermode)
1056                         {
1057                                 if (!silent)
1058                                 {
1059                                         WriteChannelWithServ(ServerName,chan,user,"MODE %s %s",chan->name,outstr);
1060                                         // M token for a usermode must go to all servers
1061                                         char buffer[MAXBUF];
1062                                         snprintf(buffer,MAXBUF,"M %s %s",chan->name, outstr);
1063                                         NetSendToAll(buffer);
1064                                 }
1065                                         
1066                         }
1067                         else
1068                         {
1069                                 if (!silent)
1070                                 {
1071                                         WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
1072                                         // M token for a usermode must go to all servers
1073                                         char buffer[MAXBUF];
1074                                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick,chan->name, outstr);
1075                                         NetSendToAll(buffer);
1076                                 }
1077                         }
1078                 }
1079         }
1080 }
1081
1082 // based on sourcemodes, return true or false to determine if umode is a valid mode a user may set on themselves or others.
1083
1084 bool allowed_umode(char umode, char* sourcemodes,bool adding)
1085 {
1086         log(DEBUG,"Allowed_umode: %c %s",umode,sourcemodes);
1087         // RFC1459 specified modes
1088         if ((umode == 'w') || (umode == 's') || (umode == 'i'))
1089         {
1090                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
1091                 return true;
1092         }
1093         
1094         // user may not +o themselves or others, but an oper may de-oper other opers or themselves
1095         if ((strchr(sourcemodes,'o')) && (!adding))
1096         {
1097                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
1098                 return true;
1099         }
1100         else if (umode == 'o')
1101         {
1102                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
1103                 return false;
1104         }
1105         
1106         // process any module-defined modes that need oper
1107         if ((ModeDefinedOper(umode,MT_CLIENT)) && (strchr(sourcemodes,'o')))
1108         {
1109                 log(DEBUG,"umode %c allowed by module handler (oper only mode)",umode);
1110                 return true;
1111         }
1112         else
1113         if (ModeDefined(umode,MT_CLIENT))
1114         {
1115                 // process any module-defined modes that don't need oper
1116                 log(DEBUG,"umode %c allowed by module handler (non-oper mode)",umode);
1117                 if ((ModeDefinedOper(umode,MT_CLIENT)) && (!strchr(sourcemodes,'o')))
1118                 {
1119                         // no, this mode needs oper, and this user 'aint got what it takes!
1120                         return false;
1121                 }
1122                 return true;
1123         }
1124
1125         // anything else - return false.
1126         log(DEBUG,"umode %c not known by any ruleset",umode);
1127         return false;
1128 }
1129
1130 bool process_module_umode(char umode, userrec* source, void* dest, bool adding)
1131 {
1132         userrec* s2;
1133         bool faked = false;
1134         if (!source)
1135         {
1136                 s2 = new userrec;
1137                 strlcpy(s2->nick,ServerName,NICKMAX);
1138                 strcpy(s2->modes,"o");
1139                 s2->fd = -1;
1140                 source = s2;
1141                 faked = true;
1142         }
1143         string_list p;
1144         p.clear();
1145         if (ModeDefined(umode,MT_CLIENT))
1146         {
1147                 for (int i = 0; i <= MODCOUNT; i++)
1148                 {
1149                         if (modules[i]->OnExtendedMode(source,(void*)dest,umode,MT_CLIENT,adding,p))
1150                         {
1151                                 log(DEBUG,"Module %s claims umode %c",module_names[i].c_str(),umode);
1152                                 return true;
1153                         }
1154                 }
1155                 log(DEBUG,"No module claims umode %c",umode);
1156                 if (faked)
1157                 {
1158                         delete s2;
1159                         source = NULL;
1160                 }
1161                 return false;
1162         }
1163         else
1164         {
1165                 if (faked)
1166                 {
1167                         delete s2;
1168                         source = NULL;
1169                 }
1170                 return false;
1171         }
1172 }
1173
1174 void handle_mode(char **parameters, int pcnt, userrec *user)
1175 {
1176         chanrec* Ptr;
1177         userrec* dest;
1178         int can_change;
1179         int direction = 1;
1180         char outpars[MAXBUF];
1181
1182         dest = Find(parameters[0]);
1183
1184         if (!user)
1185         {
1186                 return;
1187         }
1188
1189         if ((dest) && (pcnt == 1))
1190         {
1191                 WriteServ(user->fd,"221 %s :+%s",dest->nick,dest->modes);
1192                 return;
1193         }
1194
1195         if ((dest) && (pcnt > 1))
1196         {
1197                 char dmodes[MAXBUF];
1198                 strlcpy(dmodes,dest->modes,MAXBUF);
1199                 log(DEBUG,"pulled up dest user modes: %s",dmodes);
1200         
1201                 can_change = 0;
1202                 if (user != dest)
1203                 {
1204                         if (strchr(user->modes,'o'))
1205                         {
1206                                 can_change = 1;
1207                         }
1208                 }
1209                 else
1210                 {
1211                         can_change = 1;
1212                 }
1213                 if (!can_change)
1214                 {
1215                         WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
1216                         return;
1217                 }
1218                 
1219                 strcpy(outpars,"+");
1220                 direction = 1;
1221
1222                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1223                         return;
1224
1225                 for (int i = 0; i < strlen(parameters[1]); i++)
1226                 {
1227                         if (parameters[1][i] == '+')
1228                         {
1229                                 if (direction != 1)
1230                                 {
1231                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1232                                         {
1233                                                 outpars[strlen(outpars)-1] = '+';
1234                                         }
1235                                         else
1236                                         {
1237                                                 strcat(outpars,"+");
1238                                         }
1239                                 }
1240                                 direction = 1;
1241                         }
1242                         else
1243                         if (parameters[1][i] == '-')
1244                         {
1245                                 if (direction != 0)
1246                                 {
1247                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1248                                         {
1249                                                 outpars[strlen(outpars)-1] = '-';
1250                                         }
1251                                         else
1252                                         {
1253                                                 strcat(outpars,"-");
1254                                         }
1255                                 }
1256                                 direction = 0;
1257                         }
1258                         else
1259                         {
1260                                 can_change = 0;
1261                                 if (strchr(user->modes,'o'))
1262                                 {
1263                                         can_change = 1;
1264                                 }
1265                                 else
1266                                 {
1267                                         if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's') || (allowed_umode(parameters[1][i],user->modes,direction)))
1268                                         {
1269                                                 can_change = 1;
1270                                         }
1271                                 }
1272                                 if (can_change)
1273                                 {
1274                                         if (direction == 1)
1275                                         {
1276                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1277                                                 {
1278                                                         char umode = parameters[1][i];
1279                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1280                                                         {
1281                                                                 dmodes[strlen(dmodes)+1]='\0';
1282                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1283                                                                 outpars[strlen(outpars)+1]='\0';
1284                                                                 outpars[strlen(outpars)] = parameters[1][i];
1285                                                                 if (parameters[1][i] == 'o')
1286                                                                 {
1287                                                                         FOREACH_MOD OnGlobalOper(dest);
1288                                                                 }
1289                                                         }
1290                                                 }
1291                                         }
1292                                         else
1293                                         {
1294                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1295                                                 {
1296                                                         char umode = parameters[1][i];
1297                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1298                                                         {
1299                                                                 int q = 0;
1300                                                                 char temp[MAXBUF];      
1301                                                                 char moo[MAXBUF];       
1302
1303                                                                 outpars[strlen(outpars)+1]='\0';
1304                                                                 outpars[strlen(outpars)] = parameters[1][i];
1305                                                         
1306                                                                 strcpy(temp,"");
1307                                                                 for (q = 0; q < strlen(dmodes); q++)
1308                                                                 {
1309                                                                         if (dmodes[q] != parameters[1][i])
1310                                                                         {
1311                                                                                 moo[0] = dmodes[q];
1312                                                                                 moo[1] = '\0';
1313                                                                                 strlcat(temp,moo,MAXBUF);
1314                                                                         }
1315                                                                 }
1316                                                                 strlcpy(dmodes,temp,MAXBUF);
1317
1318                                                                 if (umode == 'o')
1319                                                                         DeleteOper(dest);
1320                                                         }
1321                                                 }
1322                                         }
1323                                 }
1324                         }
1325                 }
1326                 if (strlen(outpars))
1327                 {
1328                         char b[MAXBUF];
1329                         strlcpy(b,"",MAXBUF);
1330                         int z = 0;
1331                         int i = 0;
1332                         while (i < strlen (outpars))
1333                         {
1334                                 b[z++] = outpars[i++];
1335                                 b[z] = '\0';
1336                                 if (i<strlen(outpars)-1)
1337                                 {
1338                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1339                                         {
1340                                                 // someones playing silly buggers and trying
1341                                                 // to put a +- or -+ into the line...
1342                                                 i++;
1343                                         }
1344                                 }
1345                                 if (i == strlen(outpars)-1)
1346                                 {
1347                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1348                                         {
1349                                                 i++;
1350                                         }
1351                                 }
1352                         }
1353
1354                         z = strlen(b)-1;
1355                         if ((b[z] == '-') || (b[z] == '+'))
1356                                 b[z] = '\0';
1357
1358                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1359                                 return;
1360
1361                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1362
1363                         // M token for a usermode must go to all servers
1364                         char buffer[MAXBUF];
1365                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick, dest->nick, b);
1366                         NetSendToAll(buffer);
1367
1368                         if (strlen(dmodes)>MAXMODES)
1369                         {
1370                                 dmodes[MAXMODES-1] = '\0';
1371                         }
1372                         log(DEBUG,"Stripped mode line");
1373                         log(DEBUG,"Line dest is now %s",dmodes);
1374                         strlcpy(dest->modes,dmodes,MAXMODES);
1375
1376                 }
1377
1378                 return;
1379         }
1380         
1381         Ptr = FindChan(parameters[0]);
1382         if (Ptr)
1383         {
1384                 if (pcnt == 1)
1385                 {
1386                         /* just /modes #channel */
1387                         WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
1388                         WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1389                         return;
1390                 }
1391                 else
1392                 if (pcnt == 2)
1393                 {
1394                         char* mode = parameters[1];
1395                         if (*mode == '+')
1396                                 mode++;
1397                         int MOD_RESULT = 0;
1398                         FOREACH_RESULT(OnRawMode(user, Ptr, *mode, "", false, 0));
1399                         if (!MOD_RESULT)
1400                         {
1401                                 if (*mode == 'b')
1402                                 {
1403
1404                                         for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1405                                         {
1406                                                 WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
1407                                         }
1408                                         WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
1409                                         return;
1410                                 }
1411                                 if ((ModeDefined(*mode,MT_CHANNEL)) && (ModeIsListMode(*mode,MT_CHANNEL)))
1412                                 {
1413                                         // list of items for an extmode
1414                                         log(DEBUG,"Calling OnSendList for all modules, list output for mode %c",*mode);
1415                                         FOREACH_MOD OnSendList(user,Ptr,*mode);
1416                                         return;
1417                                 }
1418                         }
1419                 }
1420
1421                 if ((Ptr) && (!has_channel(user,Ptr)))
1422                 {
1423                         WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, Ptr->name);
1424                         return;
1425                 }
1426
1427                 if (Ptr)
1428                 {
1429                         int MOD_RESULT = 0;
1430                         FOREACH_RESULT(OnAccessCheck(user,NULL,Ptr,AC_GENERAL_MODE));
1431                         
1432                         if (MOD_RESULT == ACR_DENY)
1433                                 return;
1434                         if (MOD_RESULT == ACR_DEFAULT)
1435                         {
1436                                 if (cstatus(user,Ptr) < STATUS_HOP)
1437                                 {
1438                                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, Ptr->name);
1439                                         return;
1440                                 }
1441                         }
1442
1443                         process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,false);
1444                 }
1445         }
1446         else
1447         {
1448                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
1449         }
1450 }
1451
1452
1453
1454
1455 void server_mode(char **parameters, int pcnt, userrec *user)
1456 {
1457         chanrec* Ptr;
1458         userrec* dest;
1459         int can_change;
1460         int direction = 1;
1461         char outpars[MAXBUF];
1462
1463         dest = Find(parameters[0]);
1464         
1465         // fix: ChroNiCk found this - we cant use this as debug if its null!
1466         if (dest)
1467         {
1468                 log(DEBUG,"server_mode on %s",dest->nick);
1469         }
1470
1471         if ((dest) && (pcnt > 1))
1472         {
1473                 log(DEBUG,"params > 1");
1474
1475                 char dmodes[MAXBUF];
1476                 strlcpy(dmodes,dest->modes,MAXBUF);
1477
1478                 strcpy(outpars,"+");
1479                 direction = 1;
1480
1481                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1482                         return;
1483
1484                 for (int i = 0; i < strlen(parameters[1]); i++)
1485                 {
1486                         if (parameters[1][i] == '+')
1487                         {
1488                                 if (direction != 1)
1489                                 {
1490                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1491                                         {
1492                                                 outpars[strlen(outpars)-1] = '+';
1493                                         }
1494                                         else
1495                                         {
1496                                                 strcat(outpars,"+");
1497                                         }
1498                                 }
1499                                 direction = 1;
1500                         }
1501                         else
1502                         if (parameters[1][i] == '-')
1503                         {
1504                                 if (direction != 0)
1505                                 {
1506                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1507                                         {
1508                                                 outpars[strlen(outpars)-1] = '-';
1509                                         }
1510                                         else
1511                                         {
1512                                                 strcat(outpars,"-");
1513                                         }
1514                                 }
1515                                 direction = 0;
1516                         }
1517                         else
1518                         {
1519                                 log(DEBUG,"begin mode processing entry");
1520                                 can_change = 1;
1521                                 if (can_change)
1522                                 {
1523                                         if (direction == 1)
1524                                         {
1525                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1526                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1527                                                 {
1528                                                         char umode = parameters[1][i];
1529                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1530                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1531                                                         {
1532                                                                 dmodes[strlen(dmodes)+1]='\0';
1533                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1534                                                                 outpars[strlen(outpars)+1]='\0';
1535                                                                 outpars[strlen(outpars)] = parameters[1][i];
1536                                                         }
1537                                                 }
1538                                         }
1539                                         else
1540                                         {
1541                                                 // can only remove a mode they already have
1542                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1543                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1544                                                 {
1545                                                         char umode = parameters[1][i];
1546                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1547                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1548                                                         {
1549                                                                 int q = 0;
1550                                                                 char temp[MAXBUF];
1551                                                                 char moo[MAXBUF];       
1552
1553                                                                 outpars[strlen(outpars)+1]='\0';
1554                                                                 outpars[strlen(outpars)] = parameters[1][i];
1555                                                         
1556                                                                 strcpy(temp,"");
1557                                                                 for (q = 0; q < strlen(dmodes); q++)
1558                                                                 {
1559                                                                         if (dmodes[q] != parameters[1][i])
1560                                                                         {
1561                                                                                 moo[0] = dmodes[q];
1562                                                                                 moo[1] = '\0';
1563                                                                                 strlcat(temp,moo,MAXBUF);
1564                                                                         }
1565                                                                 }
1566                                                                 strlcpy(dmodes,temp,MAXBUF);
1567                                                         }
1568                                                 }
1569                                         }
1570                                 }
1571                         }
1572                 }
1573                 if (strlen(outpars))
1574                 {
1575                         char b[MAXBUF];
1576                         strlcpy(b,"",MAXBUF);
1577                         int z = 0;
1578                         int i = 0;
1579                         while (i < strlen (outpars))
1580                         {
1581                                 b[z++] = outpars[i++];
1582                                 b[z] = '\0';
1583                                 if (i<strlen(outpars)-1)
1584                                 {
1585                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1586                                         {
1587                                                 // someones playing silly buggers and trying
1588                                                 // to put a +- or -+ into the line...
1589                                                 i++;
1590                                         }
1591                                 }
1592                                 if (i == strlen(outpars)-1)
1593                                 {
1594                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1595                                         {
1596                                                 i++;
1597                                         }
1598                                 }
1599                         }
1600
1601                         z = strlen(b)-1;
1602                         if ((b[z] == '-') || (b[z] == '+'))
1603                                 b[z] = '\0';
1604
1605                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1606                                 return;
1607
1608                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1609
1610                         // M token for a usermode must go to all servers
1611                         char buffer[MAXBUF];
1612                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick, dest->nick, b);
1613                         NetSendToAll(buffer);
1614                         
1615                         if (strlen(dmodes)>MAXMODES)
1616                         {
1617                                 dmodes[MAXMODES-1] = '\0';
1618                         }
1619                         log(DEBUG,"Stripped mode line");
1620                         log(DEBUG,"Line dest is now %s",dmodes);
1621                         strlcpy(dest->modes,dmodes,MAXMODES);
1622
1623                 }
1624
1625                 return;
1626         }
1627         
1628         Ptr = FindChan(parameters[0]);
1629         if (Ptr)
1630         {
1631                 process_modes(parameters,user,Ptr,STATUS_OP,pcnt,true,false,false);
1632         }
1633         else
1634         {
1635                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
1636         }
1637 }
1638
1639
1640
1641 void merge_mode(char **parameters, int pcnt)
1642 {
1643         chanrec* Ptr;
1644         userrec* dest;
1645         int can_change;
1646         int direction = 1;
1647         char outpars[MAXBUF];
1648
1649         dest = Find(parameters[0]);
1650         
1651         // fix: ChroNiCk found this - we cant use this as debug if its null!
1652         if (dest)
1653         {
1654                 log(DEBUG,"merge_mode on %s",dest->nick);
1655         }
1656
1657         if ((dest) && (pcnt > 1))
1658         {
1659                 log(DEBUG,"params > 1");
1660
1661                 char dmodes[MAXBUF];
1662                 strlcpy(dmodes,dest->modes,MAXBUF);
1663
1664                 strcpy(outpars,"+");
1665                 direction = 1;
1666
1667                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1668                         return;
1669
1670                 for (int i = 0; i < strlen(parameters[1]); i++)
1671                 {
1672                         if (parameters[1][i] == '+')
1673                         {
1674                                 if (direction != 1)
1675                                 {
1676                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1677                                         {
1678                                                 outpars[strlen(outpars)-1] = '+';
1679                                         }
1680                                         else
1681                                         {
1682                                                 strcat(outpars,"+");
1683                                         }
1684                                 }
1685                                 direction = 1;
1686                         }
1687                         else
1688                         if (parameters[1][i] == '-')
1689                         {
1690                                 if (direction != 0)
1691                                 {
1692                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1693                                         {
1694                                                 outpars[strlen(outpars)-1] = '-';
1695                                         }
1696                                         else
1697                                         {
1698                                                 strcat(outpars,"-");
1699                                         }
1700                                 }
1701                                 direction = 0;
1702                         }
1703                         else
1704                         {
1705                                 log(DEBUG,"begin mode processing entry");
1706                                 can_change = 1;
1707                                 if (can_change)
1708                                 {
1709                                         if (direction == 1)
1710                                         {
1711                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1712                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],"o",true)))
1713                                                 {
1714                                                         char umode = parameters[1][i];
1715                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1716                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1717                                                         {
1718                                                                 dmodes[strlen(dmodes)+1]='\0';
1719                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1720                                                                 outpars[strlen(outpars)+1]='\0';
1721                                                                 outpars[strlen(outpars)] = parameters[1][i];
1722                                                         }
1723                                                 }
1724                                         }
1725                                         else
1726                                         {
1727                                                 // can only remove a mode they already have
1728                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1729                                                 if ((allowed_umode(parameters[1][i],"o",false)) && (strchr(dmodes,parameters[1][i])))
1730                                                 {
1731                                                         char umode = parameters[1][i];
1732                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1733                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1734                                                         {
1735                                                                 int q = 0;
1736                                                                 char temp[MAXBUF];
1737                                                                 char moo[MAXBUF];       
1738
1739                                                                 outpars[strlen(outpars)+1]='\0';
1740                                                                 outpars[strlen(outpars)] = parameters[1][i];
1741                                                         
1742                                                                 strcpy(temp,"");
1743                                                                 for (q = 0; q < strlen(dmodes); q++)
1744                                                                 {
1745                                                                         if (dmodes[q] != parameters[1][i])
1746                                                                         {
1747                                                                                 moo[0] = dmodes[q];
1748                                                                                 moo[1] = '\0';
1749                                                                                 strlcat(temp,moo,MAXBUF);
1750                                                                         }
1751                                                                 }
1752                                                                 strlcpy(dmodes,temp,MAXBUF);
1753                                                         }
1754                                                 }
1755                                         }
1756                                 }
1757                         }
1758                 }
1759                 if (strlen(outpars))
1760                 {
1761                         char b[MAXBUF];
1762                         strcpy(b,"");
1763                         int z = 0;
1764                         int i = 0;
1765                         while (i < strlen (outpars))
1766                         {
1767                                 b[z++] = outpars[i++];
1768                                 b[z] = '\0';
1769                                 if (i<strlen(outpars)-1)
1770                                 {
1771                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1772                                         {
1773                                                 // someones playing silly buggers and trying
1774                                                 // to put a +- or -+ into the line...
1775                                                 i++;
1776                                         }
1777                                 }
1778                                 if (i == strlen(outpars)-1)
1779                                 {
1780                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1781                                         {
1782                                                 i++;
1783                                         }
1784                                 }
1785                         }
1786
1787                         z = strlen(b)-1;
1788                         if ((b[z] == '-') || (b[z] == '+'))
1789                                 b[z] = '\0';
1790
1791                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1792                                 return;
1793
1794                         if (strlen(dmodes)>MAXMODES)
1795                         {
1796                                 dmodes[MAXMODES-1] = '\0';
1797                         }
1798                         log(DEBUG,"Stripped mode line");
1799                         log(DEBUG,"Line dest is now %s",dmodes);
1800                         strlcpy(dest->modes,dmodes,MAXMODES);
1801
1802                 }
1803
1804                 return;
1805         }
1806         
1807         Ptr = FindChan(parameters[0]);
1808         if (Ptr)
1809         {
1810                 userrec s2;
1811                 strlcpy(s2.nick,ServerName,NICKMAX);
1812                 strcpy(s2.modes,"o");
1813                 s2.fd = -1;
1814                 process_modes(parameters,&s2,Ptr,STATUS_OP,pcnt,true,true,false);
1815         }
1816 }
1817
1818
1819 void merge_mode2(char **parameters, int pcnt, userrec* user)
1820 {
1821         chanrec* Ptr;
1822         userrec* dest;
1823         int can_change;
1824         int direction = 1;
1825         char outpars[MAXBUF];
1826
1827         dest = Find(parameters[0]);
1828         
1829         // fix: ChroNiCk found this - we cant use this as debug if its null!
1830         if (dest)
1831         {
1832                 log(DEBUG,"merge_mode on %s",dest->nick);
1833         }
1834
1835         if ((dest) && (pcnt > 1))
1836         {
1837                 log(DEBUG,"params > 1");
1838
1839                 char dmodes[MAXBUF];
1840                 strlcpy(dmodes,dest->modes,MAXBUF);
1841
1842                 strcpy(outpars,"+");
1843                 direction = 1;
1844
1845                 if ((parameters[1][0] == ':') && (strlen(parameters[1])>1))
1846                 {
1847                         // some stupid 3rd party things (such as services packages) put a colon on the mode list...
1848                         log(DEBUG,"Some muppet put a colon on the modelist! changed to '%s'",++parameters[1]);
1849                 }
1850                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1851                 return;
1852
1853                 for (int i = 0; i < strlen(parameters[1]); i++)
1854                 {
1855                         if (parameters[1][i] == '+')
1856                         {
1857                                 if (direction != 1)
1858                                 {
1859                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1860                                         {
1861                                                 outpars[strlen(outpars)-1] = '+';
1862                                         }
1863                                         else
1864                                         {
1865                                                 strcat(outpars,"+");
1866                                         }
1867                                 }
1868                                 direction = 1;
1869                         }
1870                         else
1871                         if (parameters[1][i] == '-')
1872                         {
1873                                 if (direction != 0)
1874                                 {
1875                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1876                                         {
1877                                                 outpars[strlen(outpars)-1] = '-';
1878                                         }
1879                                         else
1880                                         {
1881                                                 strcat(outpars,"-");
1882                                         }
1883                                 }
1884                                 direction = 0;
1885                         }
1886                         else
1887                         {
1888                                 log(DEBUG,"begin mode processing entry");
1889                                 can_change = 1;
1890                                 if (can_change)
1891                                 {
1892                                         if (direction == 1)
1893                                         {
1894                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1895                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1896                                                 {
1897                                                         char umode = parameters[1][i];
1898                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1899                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1900                                                         {
1901                                                                 dmodes[strlen(dmodes)+1]='\0';
1902                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1903                                                                 outpars[strlen(outpars)+1]='\0';
1904                                                                 outpars[strlen(outpars)] = parameters[1][i];
1905                                                                 log(DEBUG,"OUTPARS='%s', DMODES='%s'",outpars,dmodes);
1906                                                         }
1907                                                 }
1908                                         }
1909                                         else
1910                                         {
1911                                                 // can only remove a mode they already have
1912                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1913                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1914                                                 {
1915                                                         char umode = parameters[1][i];
1916                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1917                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1918                                                         {
1919                                                                 int q = 0;
1920                                                                 char temp[MAXBUF];
1921                                                                 char moo[MAXBUF];       
1922
1923                                                                 outpars[strlen(outpars)+1]='\0';
1924                                                                 outpars[strlen(outpars)] = parameters[1][i];
1925                                                         
1926                                                                 strcpy(temp,"");
1927                                                                 for (q = 0; q < strlen(dmodes); q++)
1928                                                                 {
1929                                                                         if (dmodes[q] != parameters[1][i])
1930                                                                         {
1931                                                                                 moo[0] = dmodes[q];
1932                                                                                 moo[1] = '\0';
1933                                                                                 strlcat(temp,moo,MAXBUF);
1934                                                                         }
1935                                                                 }
1936                                                                 strlcpy(dmodes,temp,MAXBUF);
1937                                                         }
1938                                                 }
1939                                         }
1940                                 }
1941                         }
1942                 }
1943                 log(DEBUG,"DONE! OUTPARS='%s', DMODES='%s'",outpars,dmodes);
1944                 if (strlen(outpars))
1945                 {
1946                         char b[MAXBUF];
1947                         strcpy(b,"");
1948                         int z = 0;
1949                         int i = 0;
1950                         while (i < strlen (outpars))
1951                         {
1952                                 b[z++] = outpars[i++];
1953                                 b[z] = '\0';
1954                                 if (i<strlen(outpars)-1)
1955                                 {
1956                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1957                                         {
1958                                                 // someones playing silly buggers and trying
1959                                                 // to put a +- or -+ into the line...
1960                                                 i++;
1961                                         }
1962                                 }
1963                                 if (i == strlen(outpars)-1)
1964                                 {
1965                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1966                                         {
1967                                                 i++;
1968                                         }
1969                                 }
1970                         }
1971
1972                         z = strlen(b)-1;
1973                         if ((b[z] == '-') || (b[z] == '+'))
1974                                 b[z] = '\0';
1975
1976                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1977                                 return;
1978
1979                         // was sending 'b'
1980                         WriteTo(user,dest,"MODE %s :%s",dest->nick,b);
1981                         log(DEBUG,"Sent: :%s MODE %s",user->nick,b);
1982
1983                         if (strlen(dmodes)>MAXMODES)
1984                         {
1985                                 dmodes[MAXMODES-1] = '\0';
1986                         }
1987                         log(DEBUG,"Stripped mode line");
1988                         log(DEBUG,"Line dest is now %s",dmodes);
1989                         strlcpy(dest->modes,dmodes,MAXMODES);
1990
1991                 }
1992
1993                 return;
1994         }
1995         
1996         Ptr = FindChan(parameters[0]);
1997         if (Ptr)
1998         {
1999                 log(DEBUG,"merge_mode2: found channel %s",Ptr->name);
2000                 if (Ptr)
2001                 {
2002                         if ((cstatus(user,Ptr) < STATUS_HOP) && (!is_uline(user->server)))
2003                         {
2004                                 return;
2005                         }
2006                         process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,true);
2007                 }
2008         }
2009 }
2010
2011