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