]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Finally fixed a load of umode change stuff!
[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         strlcpy(modelist,parameters[1],MAXBUF); /* mode list, e.g. +oo-o *
536                                                  * parameters[2] onwards are parameters for
537                                                  * modes that require them :) */
538         strlcpy(outlist,"+",MAXBUF);
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                                                 strlcat(outlist,"o",MAXBUF);
600                                                 strlcpy(outpars[pc++],r,MAXBUF);
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                                                 strlcat(outlist,"h",MAXBUF);
617                                                 strlcpy(outpars[pc++],r,MAXBUF);
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                                                 strlcat(outlist,"v",MAXBUF);
635                                                 strlcpy(outpars[pc++],r,MAXBUF);
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                                                 strlcat(outlist,"b",MAXBUF);
652                                                 strlcpy(outpars[pc++],parameters[param-1],MAXBUF);
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                                                         strlcpy(key,parameters[param++],MAXBUF);
671                                                         if (strlen(key)>32) {
672                                                                 key[31] = '\0';
673                                                         }
674                                                         strlcpy(outpars[pc++],key,MAXBUF);
675                                                         strlcpy(chan->key,key,MAXBUF);
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                                                 strlcpy(key,parameters[param++],MAXBUF);
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                                                         strlcat(outlist,"k",MAXBUF);
692                                                         strlcpy(chan->key,"",MAXBUF);
693                                                         strlcpy(outpars[pc++],key,MAXBUF);
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                                                         strlcat(outlist,"l",MAXBUF);
739                                                         strlcpy(outpars[pc++],parameters[param++],MAXBUF);
740                                                         l_set = true;
741                                                 }
742                                         }
743                                 break;
744                                 
745                                 case 'i':
746                                         if (chan->inviteonly != mdir)
747                                         {
748                                                 strlcat(outlist,"i",MAXBUF);
749                                         }
750                                         chan->inviteonly = mdir;
751                                 break;
752                                 
753                                 case 't':
754                                         if (chan->topiclock != mdir)
755                                         {
756                                                 strlcat(outlist,"t",MAXBUF);
757                                         }
758                                         chan->topiclock = mdir;
759                                 break;
760                                 
761                                 case 'n':
762                                         if (chan->noexternal != mdir)
763                                         {
764                                                 strlcat(outlist,"n",MAXBUF);
765                                         }
766                                         chan->noexternal = mdir;
767                                 break;
768                                 
769                                 case 'm':
770                                         if (chan->moderated != mdir)
771                                         {
772                                                 strlcat(outlist,"m",MAXBUF);
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                                                                 strlcat(outlist,"-p+",MAXBUF);
787                                                         }
788                                                         else
789                                                         {
790                                                                 strlcat(outlist,"+p-",MAXBUF);
791                                                         }
792                                                 }
793                                         }
794                                         chan->secret = mdir;
795                                 break;
796                                 
797                                 case 'p':
798                                         if (chan->c_private != mdir)
799                                         {
800                                                 strlcat(outlist,"p",MAXBUF);
801                                                 if (chan->secret)
802                                                 {
803                                                         chan->secret = 0;
804                                                         if (mdir)
805                                                         {
806                                                                 strlcat(outlist,"-s+",MAXBUF);
807                                                         }
808                                                         else
809                                                         {
810                                                                 strlcat(outlist,"+s-",MAXBUF);
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                                                                                                 strlcat(outlist, app,MAXBUF);
874                                                                                         }
875                                                                                         strlcpy(outpars[pc++],parameters[param++],MAXBUF);
876                                                                                 }
877                                                                         }
878                                                                         else
879                                                                         {
880                                                                                 if (ptr>0)
881                                                                                 {
882                                                                                         if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
883                                                                                         {
884                                                                                                 strlcat(outlist, app,MAXBUF);
885                                                                                         }
886                                                                                         else if (!strchr(outlist,modechar))
887                                                                                         {
888                                                                                                 strlcat(outlist, app,MAXBUF);
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                                                                                         strlcpy(outpars[pc++],parameters[param++],MAXBUF);
897                                                                                 }
898                                                                         }
899                                                                         // break, because only one module can handle the mode.
900                                                                         handled = true;
901                                                                 }
902                                                         }
903                                                 }
904                                         }
905                                         else
906                                         {
907                                                 WriteServ(user->fd,"472 %s %c :is unknown mode char to me",user->nick,modechar);
908                                         }
909                                 break;
910                                 
911                         }
912                 }
913         }
914
915         /* this ensures only the *valid* modes are sent out onto the network */
916         while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+'))
917         {
918                 outlist[strlen(outlist)-1] = '\0';
919         }
920         if (strcmp(outlist,""))
921         {
922                 strlcpy(outstr,outlist,MAXBUF);
923                 for (ptr = 0; ptr < pc; ptr++)
924                 {
925                         strlcat(outstr," ",MAXBUF);
926                         strlcat(outstr,outpars[ptr],MAXBUF);
927                 }
928                 if (local)
929                 {
930                         log(DEBUG,"Local mode change");
931                         WriteChannelLocal(chan, user, "MODE %s %s",chan->name,outstr);
932                 }
933                 else
934                 {
935                         if (servermode)
936                         {
937                                 if (!silent)
938                                 {
939                                         WriteChannelWithServ(ServerName,chan,user,"MODE %s %s",chan->name,outstr);
940                                         // M token for a usermode must go to all servers
941                                         char buffer[MAXBUF];
942                                         snprintf(buffer,MAXBUF,"M %s %s",chan->name, outstr);
943                                         NetSendToAll(buffer);
944                                 }
945                                         
946                         }
947                         else
948                         {
949                                 if (!silent)
950                                 {
951                                         WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
952                                         // M token for a usermode must go to all servers
953                                         char buffer[MAXBUF];
954                                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick,chan->name, outstr);
955                                         NetSendToAll(buffer);
956                                 }
957                         }
958                 }
959         }
960 }
961
962 // based on sourcemodes, return true or false to determine if umode is a valid mode a user may set on themselves or others.
963
964 bool allowed_umode(char umode, char* sourcemodes,bool adding)
965 {
966         log(DEBUG,"Allowed_umode: %c %s",umode,sourcemodes);
967         // RFC1459 specified modes
968         if ((umode == 'w') || (umode == 's') || (umode == 'i'))
969         {
970                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
971                 return true;
972         }
973         
974         // user may not +o themselves or others, but an oper may de-oper other opers or themselves
975         if ((strchr(sourcemodes,'o')) && (!adding))
976         {
977                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
978                 return true;
979         }
980         else if (umode == 'o')
981         {
982                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
983                 return false;
984         }
985         
986         // process any module-defined modes that need oper
987         if ((ModeDefinedOper(umode,MT_CLIENT)) && (strchr(sourcemodes,'o')))
988         {
989                 log(DEBUG,"umode %c allowed by module handler (oper only mode)",umode);
990                 return true;
991         }
992         else
993         if (ModeDefined(umode,MT_CLIENT))
994         {
995                 // process any module-defined modes that don't need oper
996                 log(DEBUG,"umode %c allowed by module handler (non-oper mode)",umode);
997                 if ((ModeDefinedOper(umode,MT_CLIENT)) && (!strchr(sourcemodes,'o')))
998                 {
999                         // no, this mode needs oper, and this user 'aint got what it takes!
1000                         return false;
1001                 }
1002                 return true;
1003         }
1004
1005         // anything else - return false.
1006         log(DEBUG,"umode %c not known by any ruleset",umode);
1007         return false;
1008 }
1009
1010 bool process_module_umode(char umode, userrec* source, void* dest, bool adding)
1011 {
1012         userrec* s2;
1013         bool faked = false;
1014         if (!source)
1015         {
1016                 s2 = new userrec;
1017                 strlcpy(s2->nick,ServerName,NICKMAX);
1018                 strcpy(s2->modes,"o");
1019                 s2->fd = -1;
1020                 source = s2;
1021                 faked = true;
1022         }
1023         string_list p;
1024         p.clear();
1025         if (ModeDefined(umode,MT_CLIENT))
1026         {
1027                 for (int i = 0; i <= MODCOUNT; i++)
1028                 {
1029                         if (modules[i]->OnExtendedMode(source,(void*)dest,umode,MT_CLIENT,adding,p))
1030                         {
1031                                 log(DEBUG,"Module %s claims umode %c",module_names[i].c_str(),umode);
1032                                 return true;
1033                         }
1034                 }
1035                 log(DEBUG,"No module claims umode %c",umode);
1036                 if (faked)
1037                 {
1038                         delete s2;
1039                         source = NULL;
1040                 }
1041                 return false;
1042         }
1043         else
1044         {
1045                 if (faked)
1046                 {
1047                         delete s2;
1048                         source = NULL;
1049                 }
1050                 return false;
1051         }
1052 }
1053
1054 void handle_mode(char **parameters, int pcnt, userrec *user)
1055 {
1056         chanrec* Ptr;
1057         userrec* dest;
1058         int can_change,i;
1059         int direction = 1;
1060         char outpars[MAXBUF];
1061
1062         dest = Find(parameters[0]);
1063
1064         if (!user)
1065         {
1066                 return;
1067         }
1068
1069         if ((dest) && (pcnt == 1))
1070         {
1071                 WriteServ(user->fd,"221 %s :+%s",dest->nick,dest->modes);
1072                 return;
1073         }
1074
1075         if ((dest) && (pcnt > 1))
1076         {
1077                 char dmodes[MAXBUF];
1078                 strlcpy(dmodes,dest->modes,MAXBUF);
1079                 log(DEBUG,"pulled up dest user modes: %s",dmodes);
1080         
1081                 can_change = 0;
1082                 if (user != dest)
1083                 {
1084                         if (strchr(user->modes,'o'))
1085                         {
1086                                 can_change = 1;
1087                         }
1088                 }
1089                 else
1090                 {
1091                         can_change = 1;
1092                 }
1093                 if (!can_change)
1094                 {
1095                         WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
1096                         return;
1097                 }
1098                 
1099                 strcpy(outpars,"+");
1100                 direction = 1;
1101
1102                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1103                         return;
1104
1105                 for (int i = 0; i < strlen(parameters[1]); i++)
1106                 {
1107                         if (parameters[1][i] == '+')
1108                         {
1109                                 if (direction != 1)
1110                                 {
1111                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1112                                         {
1113                                                 outpars[strlen(outpars)-1] = '+';
1114                                         }
1115                                         else
1116                                         {
1117                                                 strcat(outpars,"+");
1118                                         }
1119                                 }
1120                                 direction = 1;
1121                         }
1122                         else
1123                         if (parameters[1][i] == '-')
1124                         {
1125                                 if (direction != 0)
1126                                 {
1127                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1128                                         {
1129                                                 outpars[strlen(outpars)-1] = '-';
1130                                         }
1131                                         else
1132                                         {
1133                                                 strcat(outpars,"-");
1134                                         }
1135                                 }
1136                                 direction = 0;
1137                         }
1138                         else
1139                         {
1140                                 can_change = 0;
1141                                 if (strchr(user->modes,'o'))
1142                                 {
1143                                         can_change = 1;
1144                                 }
1145                                 else
1146                                 {
1147                                         if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's') || (allowed_umode(parameters[1][i],user->modes,direction)))
1148                                         {
1149                                                 can_change = 1;
1150                                         }
1151                                 }
1152                                 if (can_change)
1153                                 {
1154                                         if (direction == 1)
1155                                         {
1156                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1157                                                 {
1158                                                         char umode = parameters[1][i];
1159                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1160                                                         {
1161                                                                 dmodes[strlen(dmodes)+1]='\0';
1162                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1163                                                                 outpars[strlen(outpars)+1]='\0';
1164                                                                 outpars[strlen(outpars)] = parameters[1][i];
1165                                                         }
1166                                                 }
1167                                         }
1168                                         else
1169                                         {
1170                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1171                                                 {
1172                                                         char umode = parameters[1][i];
1173                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1174                                                         {
1175                                                                 int q = 0;
1176                                                                 char temp[MAXBUF];      
1177                                                                 char moo[MAXBUF];       
1178
1179                                                                 outpars[strlen(outpars)+1]='\0';
1180                                                                 outpars[strlen(outpars)] = parameters[1][i];
1181                                                         
1182                                                                 strcpy(temp,"");
1183                                                                 for (q = 0; q < strlen(dmodes); q++)
1184                                                                 {
1185                                                                         if (dmodes[q] != parameters[1][i])
1186                                                                         {
1187                                                                                 moo[0] = dmodes[q];
1188                                                                                 moo[1] = '\0';
1189                                                                                 strlcat(temp,moo,MAXBUF);
1190                                                                         }
1191                                                                 }
1192                                                                 strlcpy(dmodes,temp,MAXBUF);
1193                                                         }
1194                                                 }
1195                                         }
1196                                 }
1197                         }
1198                 }
1199                 if (strlen(outpars))
1200                 {
1201                         char b[MAXBUF];
1202                         strlcpy(b,"",MAXBUF);
1203                         int z = 0;
1204                         int i = 0;
1205                         while (i < strlen (outpars))
1206                         {
1207                                 b[z++] = outpars[i++];
1208                                 b[z] = '\0';
1209                                 if (i<strlen(outpars)-1)
1210                                 {
1211                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1212                                         {
1213                                                 // someones playing silly buggers and trying
1214                                                 // to put a +- or -+ into the line...
1215                                                 i++;
1216                                         }
1217                                 }
1218                                 if (i == strlen(outpars)-1)
1219                                 {
1220                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1221                                         {
1222                                                 i++;
1223                                         }
1224                                 }
1225                         }
1226
1227                         z = strlen(b)-1;
1228                         if ((b[z] == '-') || (b[z] == '+'))
1229                                 b[z] == '\0';
1230
1231                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1232                                 return;
1233
1234                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1235
1236                         // M token for a usermode must go to all servers
1237                         char buffer[MAXBUF];
1238                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick, dest->nick, b);
1239                         NetSendToAll(buffer);
1240
1241                         if (strlen(dmodes)>MAXMODES)
1242                         {
1243                                 dmodes[MAXMODES-1] = '\0';
1244                         }
1245                         log(DEBUG,"Stripped mode line");
1246                         log(DEBUG,"Line dest is now %s",dmodes);
1247                         strlcpy(dest->modes,dmodes,MAXMODES);
1248
1249                 }
1250
1251                 return;
1252         }
1253         
1254         Ptr = FindChan(parameters[0]);
1255         if (Ptr)
1256         {
1257                 if (pcnt == 1)
1258                 {
1259                         /* just /modes #channel */
1260                         WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
1261                         WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1262                         return;
1263                 }
1264                 else
1265                 if (pcnt == 2)
1266                 {
1267                         if ((!strcmp(parameters[1],"+b")) || (!strcmp(parameters[1],"b")))
1268                         {
1269
1270                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1271                                 {
1272                                         WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
1273                                 }
1274                                 WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
1275                                 return;
1276                         }
1277                 }
1278
1279                 int MOD_RESULT = 0;
1280                 FOREACH_RESULT(OnAccessCheck(user,NULL,Ptr,AC_GENERAL_MODE));
1281                 
1282                 if (MOD_RESULT == ACR_DENY)
1283                         return;
1284                 if (MOD_RESULT == ACR_DEFAULT)
1285                 {
1286                         if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
1287                         {
1288                                 WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, Ptr->name);
1289                                 return;
1290                         }
1291                 }
1292
1293                 process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,false);
1294         }
1295         else
1296         {
1297                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
1298         }
1299 }
1300
1301
1302
1303
1304 void server_mode(char **parameters, int pcnt, userrec *user)
1305 {
1306         chanrec* Ptr;
1307         userrec* dest;
1308         int can_change,i;
1309         int direction = 1;
1310         char outpars[MAXBUF];
1311
1312         dest = Find(parameters[0]);
1313         
1314         // fix: ChroNiCk found this - we cant use this as debug if its null!
1315         if (dest)
1316         {
1317                 log(DEBUG,"server_mode on %s",dest->nick);
1318         }
1319
1320         if ((dest) && (pcnt > 1))
1321         {
1322                 log(DEBUG,"params > 1");
1323
1324                 char dmodes[MAXBUF];
1325                 strlcpy(dmodes,dest->modes,MAXBUF);
1326
1327                 strcpy(outpars,"+");
1328                 direction = 1;
1329
1330                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1331                         return;
1332
1333                 for (int i = 0; i < strlen(parameters[1]); i++)
1334                 {
1335                         if (parameters[1][i] == '+')
1336                         {
1337                                 if (direction != 1)
1338                                 {
1339                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1340                                         {
1341                                                 outpars[strlen(outpars)-1] = '+';
1342                                         }
1343                                         else
1344                                         {
1345                                                 strcat(outpars,"+");
1346                                         }
1347                                 }
1348                                 direction = 1;
1349                         }
1350                         else
1351                         if (parameters[1][i] == '-')
1352                         {
1353                                 if (direction != 0)
1354                                 {
1355                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1356                                         {
1357                                                 outpars[strlen(outpars)-1] = '-';
1358                                         }
1359                                         else
1360                                         {
1361                                                 strcat(outpars,"-");
1362                                         }
1363                                 }
1364                                 direction = 0;
1365                         }
1366                         else
1367                         {
1368                                 log(DEBUG,"begin mode processing entry");
1369                                 can_change = 1;
1370                                 if (can_change)
1371                                 {
1372                                         if (direction == 1)
1373                                         {
1374                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1375                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1376                                                 {
1377                                                         char umode = parameters[1][i];
1378                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1379                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1380                                                         {
1381                                                                 dmodes[strlen(dmodes)+1]='\0';
1382                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1383                                                                 outpars[strlen(outpars)+1]='\0';
1384                                                                 outpars[strlen(outpars)] = parameters[1][i];
1385                                                         }
1386                                                 }
1387                                         }
1388                                         else
1389                                         {
1390                                                 // can only remove a mode they already have
1391                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1392                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1393                                                 {
1394                                                         char umode = parameters[1][i];
1395                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1396                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1397                                                         {
1398                                                                 int q = 0;
1399                                                                 char temp[MAXBUF];
1400                                                                 char moo[MAXBUF];       
1401
1402                                                                 outpars[strlen(outpars)+1]='\0';
1403                                                                 outpars[strlen(outpars)] = parameters[1][i];
1404                                                         
1405                                                                 strcpy(temp,"");
1406                                                                 for (q = 0; q < strlen(dmodes); q++)
1407                                                                 {
1408                                                                         if (dmodes[q] != parameters[1][i])
1409                                                                         {
1410                                                                                 moo[0] = dmodes[q];
1411                                                                                 moo[1] = '\0';
1412                                                                                 strlcat(temp,moo,MAXBUF);
1413                                                                         }
1414                                                                 }
1415                                                                 strlcpy(dmodes,temp,MAXBUF);
1416                                                         }
1417                                                 }
1418                                         }
1419                                 }
1420                         }
1421                 }
1422                 if (strlen(outpars))
1423                 {
1424                         char b[MAXBUF];
1425                         strlcpy(b,"",MAXBUF);
1426                         int z = 0;
1427                         int i = 0;
1428                         while (i < strlen (outpars))
1429                         {
1430                                 b[z++] = outpars[i++];
1431                                 b[z] = '\0';
1432                                 if (i<strlen(outpars)-1)
1433                                 {
1434                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1435                                         {
1436                                                 // someones playing silly buggers and trying
1437                                                 // to put a +- or -+ into the line...
1438                                                 i++;
1439                                         }
1440                                 }
1441                                 if (i == strlen(outpars)-1)
1442                                 {
1443                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1444                                         {
1445                                                 i++;
1446                                         }
1447                                 }
1448                         }
1449
1450                         z = strlen(b)-1;
1451                         if ((b[z] == '-') || (b[z] == '+'))
1452                                 b[z] == '\0';
1453
1454                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1455                                 return;
1456
1457                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1458
1459                         // M token for a usermode must go to all servers
1460                         char buffer[MAXBUF];
1461                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick, dest->nick, b);
1462                         NetSendToAll(buffer);
1463                         
1464                         if (strlen(dmodes)>MAXMODES)
1465                         {
1466                                 dmodes[MAXMODES-1] = '\0';
1467                         }
1468                         log(DEBUG,"Stripped mode line");
1469                         log(DEBUG,"Line dest is now %s",dmodes);
1470                         strlcpy(dest->modes,dmodes,MAXMODES);
1471
1472                 }
1473
1474                 return;
1475         }
1476         
1477         Ptr = FindChan(parameters[0]);
1478         if (Ptr)
1479         {
1480                 process_modes(parameters,user,Ptr,STATUS_OP,pcnt,true,false,false);
1481         }
1482         else
1483         {
1484                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
1485         }
1486 }
1487
1488
1489
1490 void merge_mode(char **parameters, int pcnt)
1491 {
1492         chanrec* Ptr;
1493         userrec* dest;
1494         int can_change,i;
1495         int direction = 1;
1496         char outpars[MAXBUF];
1497
1498         dest = Find(parameters[0]);
1499         
1500         // fix: ChroNiCk found this - we cant use this as debug if its null!
1501         if (dest)
1502         {
1503                 log(DEBUG,"merge_mode on %s",dest->nick);
1504         }
1505
1506         if ((dest) && (pcnt > 1))
1507         {
1508                 log(DEBUG,"params > 1");
1509
1510                 char dmodes[MAXBUF];
1511                 strlcpy(dmodes,dest->modes,MAXBUF);
1512
1513                 strcpy(outpars,"+");
1514                 direction = 1;
1515
1516                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1517                         return;
1518
1519                 for (int i = 0; i < strlen(parameters[1]); i++)
1520                 {
1521                         if (parameters[1][i] == '+')
1522                         {
1523                                 if (direction != 1)
1524                                 {
1525                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1526                                         {
1527                                                 outpars[strlen(outpars)-1] = '+';
1528                                         }
1529                                         else
1530                                         {
1531                                                 strcat(outpars,"+");
1532                                         }
1533                                 }
1534                                 direction = 1;
1535                         }
1536                         else
1537                         if (parameters[1][i] == '-')
1538                         {
1539                                 if (direction != 0)
1540                                 {
1541                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1542                                         {
1543                                                 outpars[strlen(outpars)-1] = '-';
1544                                         }
1545                                         else
1546                                         {
1547                                                 strcat(outpars,"-");
1548                                         }
1549                                 }
1550                                 direction = 0;
1551                         }
1552                         else
1553                         {
1554                                 log(DEBUG,"begin mode processing entry");
1555                                 can_change = 1;
1556                                 if (can_change)
1557                                 {
1558                                         if (direction == 1)
1559                                         {
1560                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1561                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],"o",true)))
1562                                                 {
1563                                                         char umode = parameters[1][i];
1564                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1565                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1566                                                         {
1567                                                                 dmodes[strlen(dmodes)+1]='\0';
1568                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1569                                                                 outpars[strlen(outpars)+1]='\0';
1570                                                                 outpars[strlen(outpars)] = parameters[1][i];
1571                                                         }
1572                                                 }
1573                                         }
1574                                         else
1575                                         {
1576                                                 // can only remove a mode they already have
1577                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1578                                                 if ((allowed_umode(parameters[1][i],"o",false)) && (strchr(dmodes,parameters[1][i])))
1579                                                 {
1580                                                         char umode = parameters[1][i];
1581                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1582                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1583                                                         {
1584                                                                 int q = 0;
1585                                                                 char temp[MAXBUF];
1586                                                                 char moo[MAXBUF];       
1587
1588                                                                 outpars[strlen(outpars)+1]='\0';
1589                                                                 outpars[strlen(outpars)] = parameters[1][i];
1590                                                         
1591                                                                 strcpy(temp,"");
1592                                                                 for (q = 0; q < strlen(dmodes); q++)
1593                                                                 {
1594                                                                         if (dmodes[q] != parameters[1][i])
1595                                                                         {
1596                                                                                 moo[0] = dmodes[q];
1597                                                                                 moo[1] = '\0';
1598                                                                                 strlcat(temp,moo,MAXBUF);
1599                                                                         }
1600                                                                 }
1601                                                                 strlcpy(dmodes,temp,MAXBUF);
1602                                                         }
1603                                                 }
1604                                         }
1605                                 }
1606                         }
1607                 }
1608                 if (strlen(outpars))
1609                 {
1610                         char b[MAXBUF];
1611                         strcpy(b,"");
1612                         int z = 0;
1613                         int i = 0;
1614                         while (i < strlen (outpars))
1615                         {
1616                                 b[z++] = outpars[i++];
1617                                 b[z] = '\0';
1618                                 if (i<strlen(outpars)-1)
1619                                 {
1620                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1621                                         {
1622                                                 // someones playing silly buggers and trying
1623                                                 // to put a +- or -+ into the line...
1624                                                 i++;
1625                                         }
1626                                 }
1627                                 if (i == strlen(outpars)-1)
1628                                 {
1629                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1630                                         {
1631                                                 i++;
1632                                         }
1633                                 }
1634                         }
1635
1636                         z = strlen(b)-1;
1637                         if ((b[z] == '-') || (b[z] == '+'))
1638                                 b[z] == '\0';
1639
1640                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1641                                 return;
1642
1643                         if (strlen(dmodes)>MAXMODES)
1644                         {
1645                                 dmodes[MAXMODES-1] = '\0';
1646                         }
1647                         log(DEBUG,"Stripped mode line");
1648                         log(DEBUG,"Line dest is now %s",dmodes);
1649                         strlcpy(dest->modes,dmodes,MAXMODES);
1650
1651                 }
1652
1653                 return;
1654         }
1655         
1656         Ptr = FindChan(parameters[0]);
1657         if (Ptr)
1658         {
1659                 userrec s2;
1660                 strlcpy(s2.nick,ServerName,NICKMAX);
1661                 strcpy(s2.modes,"o");
1662                 s2.fd = -1;
1663                 process_modes(parameters,&s2,Ptr,STATUS_OP,pcnt,true,true,false);
1664         }
1665 }
1666
1667
1668 void merge_mode2(char **parameters, int pcnt, userrec* user)
1669 {
1670         chanrec* Ptr;
1671         userrec* dest;
1672         int can_change,i;
1673         int direction = 1;
1674         char outpars[MAXBUF];
1675
1676         dest = Find(parameters[0]);
1677         
1678         // fix: ChroNiCk found this - we cant use this as debug if its null!
1679         if (dest)
1680         {
1681                 log(DEBUG,"merge_mode on %s",dest->nick);
1682         }
1683
1684         if ((dest) && (pcnt > 1))
1685         {
1686                 log(DEBUG,"params > 1");
1687
1688                 char dmodes[MAXBUF];
1689                 strlcpy(dmodes,dest->modes,MAXBUF);
1690
1691                 strcpy(outpars,"+");
1692                 direction = 1;
1693
1694                 if ((parameters[1][0] == ':') && (strlen(parameters[1])>1))
1695                 {
1696                         // some stupid 3rd party things (such as services packages) put a colon on the mode list...
1697                         log(DEBUG,"Some muppet put a colon on the modelist! changed to '%s'",++parameters[1]);
1698                 }
1699                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1700                 return;
1701
1702                 for (int i = 0; i < strlen(parameters[1]); i++)
1703                 {
1704                         if (parameters[1][i] == '+')
1705                         {
1706                                 if (direction != 1)
1707                                 {
1708                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1709                                         {
1710                                                 outpars[strlen(outpars)-1] = '+';
1711                                         }
1712                                         else
1713                                         {
1714                                                 strcat(outpars,"+");
1715                                         }
1716                                 }
1717                                 direction = 1;
1718                         }
1719                         else
1720                         if (parameters[1][i] == '-')
1721                         {
1722                                 if (direction != 0)
1723                                 {
1724                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1725                                         {
1726                                                 outpars[strlen(outpars)-1] = '-';
1727                                         }
1728                                         else
1729                                         {
1730                                                 strcat(outpars,"-");
1731                                         }
1732                                 }
1733                                 direction = 0;
1734                         }
1735                         else
1736                         {
1737                                 log(DEBUG,"begin mode processing entry");
1738                                 can_change = 1;
1739                                 if (can_change)
1740                                 {
1741                                         if (direction == 1)
1742                                         {
1743                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1744                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1745                                                 {
1746                                                         char umode = parameters[1][i];
1747                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1748                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1749                                                         {
1750                                                                 dmodes[strlen(dmodes)+1]='\0';
1751                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1752                                                                 outpars[strlen(outpars)+1]='\0';
1753                                                                 outpars[strlen(outpars)] = parameters[1][i];
1754                                                                 log(DEBUG,"OUTPARS='%s', DMODES='%s'",outpars,dmodes);
1755                                                         }
1756                                                 }
1757                                         }
1758                                         else
1759                                         {
1760                                                 // can only remove a mode they already have
1761                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1762                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1763                                                 {
1764                                                         char umode = parameters[1][i];
1765                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1766                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1767                                                         {
1768                                                                 int q = 0;
1769                                                                 char temp[MAXBUF];
1770                                                                 char moo[MAXBUF];       
1771
1772                                                                 outpars[strlen(outpars)+1]='\0';
1773                                                                 outpars[strlen(outpars)] = parameters[1][i];
1774                                                         
1775                                                                 strcpy(temp,"");
1776                                                                 for (q = 0; q < strlen(dmodes); q++)
1777                                                                 {
1778                                                                         if (dmodes[q] != parameters[1][i])
1779                                                                         {
1780                                                                                 moo[0] = dmodes[q];
1781                                                                                 moo[1] = '\0';
1782                                                                                 strlcat(temp,moo,MAXBUF);
1783                                                                         }
1784                                                                 }
1785                                                                 strlcpy(dmodes,temp,MAXBUF);
1786                                                         }
1787                                                 }
1788                                         }
1789                                 }
1790                         }
1791                 }
1792                 log(DEBUG,"DONE! OUTPARS='%s', DMODES='%s'",outpars,dmodes);
1793                 if (strlen(outpars))
1794                 {
1795                         char b[MAXBUF];
1796                         strcpy(b,"");
1797                         int z = 0;
1798                         int i = 0;
1799                         while (i < strlen (outpars))
1800                         {
1801                                 b[z++] = outpars[i++];
1802                                 b[z] = '\0';
1803                                 if (i<strlen(outpars)-1)
1804                                 {
1805                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1806                                         {
1807                                                 // someones playing silly buggers and trying
1808                                                 // to put a +- or -+ into the line...
1809                                                 i++;
1810                                         }
1811                                 }
1812                                 if (i == strlen(outpars)-1)
1813                                 {
1814                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1815                                         {
1816                                                 i++;
1817                                         }
1818                                 }
1819                         }
1820
1821                         z = strlen(b)-1;
1822                         if ((b[z] == '-') || (b[z] == '+'))
1823                                 b[z] == '\0';
1824
1825                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1826                                 return;
1827
1828                         // was sending 'b'
1829                         WriteTo(user,dest,"MODE %s :%s",dest->nick,b);
1830                         log(DEBUG,"Sent: :%s MODE %s",user->nick,b);
1831
1832                         if (strlen(dmodes)>MAXMODES)
1833                         {
1834                                 dmodes[MAXMODES-1] = '\0';
1835                         }
1836                         log(DEBUG,"Stripped mode line");
1837                         log(DEBUG,"Line dest is now %s",dmodes);
1838                         strlcpy(dest->modes,dmodes,MAXMODES);
1839
1840                 }
1841
1842                 return;
1843         }
1844         
1845         Ptr = FindChan(parameters[0]);
1846         if (Ptr)
1847         {
1848                 log(DEBUG,"merge_mode2: found channel %s",Ptr->name);
1849                 if (Ptr)
1850                 {
1851                         if ((cstatus(user,Ptr) < STATUS_HOP) && (!is_uline(user->server)))
1852                         {
1853                                 return;
1854                         }
1855                         process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,true);
1856                 }
1857         }
1858 }
1859
1860