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