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