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