]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
XLine fixes and fix to +l with large limits
[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                                                 
660                                                 // reported by mech: large values cause underflow
661                                                 if (chan->limit < 0)
662                                                         chan->limit = MAXINT;
663                                                         
664                                                 if (chan->limit)
665                                                 {
666                                                         strcat(outlist,"l");
667                                                         strcpy(outpars[pc++],parameters[param++]);
668                                                         l_set = true;
669                                                 }
670                                         }
671                                 break;
672                                 
673                                 case 'i':
674                                         if (chan->inviteonly != mdir)
675                                         {
676                                                 strcat(outlist,"i");
677                                         }
678                                         chan->inviteonly = mdir;
679                                 break;
680                                 
681                                 case 't':
682                                         if (chan->topiclock != mdir)
683                                         {
684                                                 strcat(outlist,"t");
685                                         }
686                                         chan->topiclock = mdir;
687                                 break;
688                                 
689                                 case 'n':
690                                         if (chan->noexternal != mdir)
691                                         {
692                                                 strcat(outlist,"n");
693                                         }
694                                         chan->noexternal = mdir;
695                                 break;
696                                 
697                                 case 'm':
698                                         if (chan->moderated != mdir)
699                                         {
700                                                 strcat(outlist,"m");
701                                         }
702                                         chan->moderated = mdir;
703                                 break;
704                                 
705                                 case 's':
706                                         if (chan->secret != mdir)
707                                         {
708                                                 strcat(outlist,"s");
709                                                 if (chan->c_private)
710                                                 {
711                                                         chan->c_private = 0;
712                                                         if (mdir)
713                                                         {
714                                                                 strcat(outlist,"-p+");
715                                                         }
716                                                         else
717                                                         {
718                                                                 strcat(outlist,"+p-");
719                                                         }
720                                                 }
721                                         }
722                                         chan->secret = mdir;
723                                 break;
724                                 
725                                 case 'p':
726                                         if (chan->c_private != mdir)
727                                         {
728                                                 strcat(outlist,"p");
729                                                 if (chan->secret)
730                                                 {
731                                                         chan->secret = 0;
732                                                         if (mdir)
733                                                         {
734                                                                 strcat(outlist,"-s+");
735                                                         }
736                                                         else
737                                                         {
738                                                                 strcat(outlist,"+s-");
739                                                         }
740                                                 }
741                                         }
742                                         chan->c_private = mdir;
743                                 break;
744                                 
745                                 default:
746                                         log(DEBUG,"Preprocessing custom mode %c",modechar);
747                                         string_list p;
748                                         p.clear();
749                                         if (((!strchr(chan->custom_modes,modechar)) && (!mdir)) || ((strchr(chan->custom_modes,modechar)) && (mdir)))
750                                         {
751                                                 log(DEBUG,"Mode %c isnt set on %s but trying to remove!",modechar,chan->name);
752                                                 break;
753                                         }
754                                         if (ModeDefined(modechar,MT_CHANNEL))
755                                         {
756                                                 log(DEBUG,"A module has claimed this mode");
757                                                 if (param<pcnt)
758                                                 {
759                                                         if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
760                                                         {
761                                                                 p.push_back(parameters[param]);
762                                                         }
763                                                         if ((ModeDefinedOff(modechar,MT_CHANNEL)>0) && (!mdir))
764                                                         {
765                                                                 p.push_back(parameters[param]);
766                                                         }
767                                                 }
768                                                 bool handled = false;
769                                                 if (param>=pcnt)
770                                                 {
771                                                         log(DEBUG,"Not enough parameters for module-mode %c",modechar);
772                                                         // we're supposed to have a parameter, but none was given... so dont handle the mode.
773                                                         if (((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir)) || ((ModeDefinedOff(modechar,MT_CHANNEL)>0) && (!mdir))) 
774                                                         {
775                                                                 handled = true;
776                                                                 param++;
777                                                         }
778                                                 }
779                                                 for (int i = 0; i <= MODCOUNT; i++)
780                                                 {
781                                                         if (!handled)
782                                                         {
783                                                                 if (modules[i]->OnExtendedMode(user,chan,modechar,MT_CHANNEL,mdir,p))
784                                                                 {
785                                                                         log(DEBUG,"OnExtendedMode returned nonzero for a module");
786                                                                         char app[] = {modechar, 0};
787                                                                         if (ptr>0)
788                                                                         {
789                                                                                 if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
790                                                                                 {
791                                                                                         strcat(outlist, app);
792                                                                                 }
793                                                                                 else if (!strchr(outlist,modechar))
794                                                                                 {
795                                                                                         strcat(outlist, app);
796                                                                                 }
797                                                                         }
798                                                                         chan->SetCustomMode(modechar,mdir);
799                                                                         // include parameters in output if mode has them
800                                                                         if ((ModeDefinedOn(modechar,MT_CHANNEL)>0) && (mdir))
801                                                                         {
802                                                                                 chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
803                                                                                 strcpy(outpars[pc++],parameters[param++]);
804                                                                         }
805                                                                         // break, because only one module can handle the mode.
806                                                                         handled = true;
807                                                                 }
808                                                         }
809                                                 }
810                                         }
811                                 break;
812                                 
813                         }
814                 }
815         }
816
817         /* this ensures only the *valid* modes are sent out onto the network */
818         while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+'))
819         {
820                 outlist[strlen(outlist)-1] = '\0';
821         }
822         if (strcmp(outlist,""))
823         {
824                 strcpy(outstr,outlist);
825                 for (ptr = 0; ptr < pc; ptr++)
826                 {
827                         strcat(outstr," ");
828                         strcat(outstr,outpars[ptr]);
829                 }
830                 if (local)
831                 {
832                         log(DEBUG,"Local mode change");
833                         WriteChannelLocal(chan, user, "MODE %s %s",chan->name,outstr);
834                 }
835                 else
836                 {
837                         if (servermode)
838                         {
839                                 if (!silent)
840                                 {
841                                         WriteChannelWithServ(ServerName,chan,user,"MODE %s %s",chan->name,outstr);
842                                         // M token for a usermode must go to all servers
843                                         char buffer[MAXBUF];
844                                         snprintf(buffer,MAXBUF,"M %s %s",chan->name, outstr);
845                                         NetSendToAll(buffer);
846                                 }
847                                         
848                         }
849                         else
850                         {
851                                 if (!silent)
852                                 {
853                                         WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
854                                         // M token for a usermode must go to all servers
855                                         char buffer[MAXBUF];
856                                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick,chan->name, outstr);
857                                         NetSendToAll(buffer);
858                                 }
859                         }
860                 }
861         }
862 }
863
864 // based on sourcemodes, return true or false to determine if umode is a valid mode a user may set on themselves or others.
865
866 bool allowed_umode(char umode, char* sourcemodes,bool adding)
867 {
868         log(DEBUG,"Allowed_umode: %c %s",umode,sourcemodes);
869         // RFC1459 specified modes
870         if ((umode == 'w') || (umode == 's') || (umode == 'i'))
871         {
872                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
873                 return true;
874         }
875         
876         // user may not +o themselves or others, but an oper may de-oper other opers or themselves
877         if ((strchr(sourcemodes,'o')) && (!adding))
878         {
879                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
880                 return true;
881         }
882         else if (umode == 'o')
883         {
884                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
885                 return false;
886         }
887         
888         // process any module-defined modes that need oper
889         if ((ModeDefinedOper(umode,MT_CLIENT)) && (strchr(sourcemodes,'o')))
890         {
891                 log(DEBUG,"umode %c allowed by module handler (oper only mode)",umode);
892                 return true;
893         }
894         else
895         if (ModeDefined(umode,MT_CLIENT))
896         {
897                 // process any module-defined modes that don't need oper
898                 log(DEBUG,"umode %c allowed by module handler (non-oper mode)",umode);
899                 if ((ModeDefinedOper(umode,MT_CLIENT)) && (!strchr(sourcemodes,'o')))
900                 {
901                         // no, this mode needs oper, and this user 'aint got what it takes!
902                         return false;
903                 }
904                 return true;
905         }
906
907         // anything else - return false.
908         log(DEBUG,"umode %c not known by any ruleset",umode);
909         return false;
910 }
911
912 bool process_module_umode(char umode, userrec* source, void* dest, bool adding)
913 {
914         userrec* s2;
915         bool faked = false;
916         if (!source)
917         {
918                 s2 = new userrec;
919                 strncpy(s2->nick,ServerName,NICKMAX);
920                 strcpy(s2->modes,"o");
921                 s2->fd = -1;
922                 source = s2;
923                 faked = true;
924         }
925         string_list p;
926         p.clear();
927         if (ModeDefined(umode,MT_CLIENT))
928         {
929                 for (int i = 0; i <= MODCOUNT; i++)
930                 {
931                         if (modules[i]->OnExtendedMode(source,(void*)dest,umode,MT_CLIENT,adding,p))
932                         {
933                                 log(DEBUG,"Module claims umode %c",umode);
934                                 return true;
935                         }
936                 }
937                 log(DEBUG,"No module claims umode %c",umode);
938                 if (faked)
939                 {
940                         delete s2;
941                         source = NULL;
942                 }
943                 return false;
944         }
945         else
946         {
947                 if (faked)
948                 {
949                         delete s2;
950                         source = NULL;
951                 }
952                 return false;
953         }
954 }
955
956 void handle_mode(char **parameters, int pcnt, userrec *user)
957 {
958         chanrec* Ptr;
959         userrec* dest;
960         int can_change,i;
961         int direction = 1;
962         char outpars[MAXBUF];
963
964         dest = Find(parameters[0]);
965
966         if (!user)
967         {
968                 return;
969         }
970
971         if ((dest) && (pcnt == 1))
972         {
973                 WriteServ(user->fd,"221 %s :+%s",user->nick,user->modes);
974                 return;
975         }
976
977         if ((dest) && (pcnt > 1))
978         {
979                 char dmodes[MAXBUF];
980                 strncpy(dmodes,dest->modes,MAXBUF);
981                 log(DEBUG,"pulled up dest user modes: %s",dmodes);
982         
983                 can_change = 0;
984                 if (user != dest)
985                 {
986                         if (strchr(user->modes,'o'))
987                         {
988                                 can_change = 1;
989                         }
990                 }
991                 else
992                 {
993                         can_change = 1;
994                 }
995                 if (!can_change)
996                 {
997                         WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
998                         return;
999                 }
1000                 
1001                 strcpy(outpars,"+");
1002                 direction = 1;
1003
1004                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1005                         return;
1006
1007                 for (int i = 0; i < strlen(parameters[1]); i++)
1008                 {
1009                         if (parameters[1][i] == '+')
1010                         {
1011                                 if (direction != 1)
1012                                 {
1013                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1014                                         {
1015                                                 outpars[strlen(outpars)-1] = '+';
1016                                         }
1017                                         else
1018                                         {
1019                                                 strcat(outpars,"+");
1020                                         }
1021                                 }
1022                                 direction = 1;
1023                         }
1024                         else
1025                         if (parameters[1][i] == '-')
1026                         {
1027                                 if (direction != 0)
1028                                 {
1029                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1030                                         {
1031                                                 outpars[strlen(outpars)-1] = '-';
1032                                         }
1033                                         else
1034                                         {
1035                                                 strcat(outpars,"-");
1036                                         }
1037                                 }
1038                                 direction = 0;
1039                         }
1040                         else
1041                         {
1042                                 can_change = 0;
1043                                 if (strchr(user->modes,'o'))
1044                                 {
1045                                         can_change = 1;
1046                                 }
1047                                 else
1048                                 {
1049                                         if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's') || (allowed_umode(parameters[1][i],user->modes,direction)))
1050                                         {
1051                                                 can_change = 1;
1052                                         }
1053                                 }
1054                                 if (can_change)
1055                                 {
1056                                         if (direction == 1)
1057                                         {
1058                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1059                                                 {
1060                                                         char umode = parameters[1][i];
1061                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1062                                                         {
1063                                                                 dmodes[strlen(dmodes)+1]='\0';
1064                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1065                                                                 outpars[strlen(outpars)+1]='\0';
1066                                                                 outpars[strlen(outpars)] = parameters[1][i];
1067                                                         }
1068                                                 }
1069                                         }
1070                                         else
1071                                         {
1072                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1073                                                 {
1074                                                         char umode = parameters[1][i];
1075                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1076                                                         {
1077                                                                 int q = 0;
1078                                                                 char temp[MAXBUF];      
1079                                                                 char moo[MAXBUF];       
1080
1081                                                                 outpars[strlen(outpars)+1]='\0';
1082                                                                 outpars[strlen(outpars)] = parameters[1][i];
1083                                                         
1084                                                                 strcpy(temp,"");
1085                                                                 for (q = 0; q < strlen(dmodes); q++)
1086                                                                 {
1087                                                                         if (dmodes[q] != parameters[1][i])
1088                                                                         {
1089                                                                                 moo[0] = dmodes[q];
1090                                                                                 moo[1] = '\0';
1091                                                                                 strcat(temp,moo);
1092                                                                         }
1093                                                                 }
1094                                                                 strcpy(dmodes,temp);
1095                                                         }
1096                                                 }
1097                                         }
1098                                 }
1099                         }
1100                 }
1101                 if (strlen(outpars))
1102                 {
1103                         char b[MAXBUF];
1104                         strcpy(b,"");
1105                         int z = 0;
1106                         int i = 0;
1107                         while (i < strlen (outpars))
1108                         {
1109                                 b[z++] = outpars[i++];
1110                                 b[z] = '\0';
1111                                 if (i<strlen(outpars)-1)
1112                                 {
1113                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1114                                         {
1115                                                 // someones playing silly buggers and trying
1116                                                 // to put a +- or -+ into the line...
1117                                                 i++;
1118                                         }
1119                                 }
1120                                 if (i == strlen(outpars)-1)
1121                                 {
1122                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1123                                         {
1124                                                 i++;
1125                                         }
1126                                 }
1127                         }
1128
1129                         z = strlen(b)-1;
1130                         if ((b[z] == '-') || (b[z] == '+'))
1131                                 b[z] == '\0';
1132
1133                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1134                                 return;
1135
1136                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1137
1138                         // M token for a usermode must go to all servers
1139                         char buffer[MAXBUF];
1140                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick, dest->nick, b);
1141                         NetSendToAll(buffer);
1142
1143                         if (strlen(dmodes)>MAXMODES)
1144                         {
1145                                 dmodes[MAXMODES-1] = '\0';
1146                         }
1147                         log(DEBUG,"Stripped mode line");
1148                         log(DEBUG,"Line dest is now %s",dmodes);
1149                         strncpy(dest->modes,dmodes,MAXMODES);
1150
1151                 }
1152
1153                 return;
1154         }
1155         
1156         Ptr = FindChan(parameters[0]);
1157         if (Ptr)
1158         {
1159                 if (pcnt == 1)
1160                 {
1161                         /* just /modes #channel */
1162                         WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
1163                         WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1164                         return;
1165                 }
1166                 else
1167                 if (pcnt == 2)
1168                 {
1169                         if ((!strcmp(parameters[1],"+b")) || (!strcmp(parameters[1],"b")))
1170                         {
1171
1172                                 for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1173                                 {
1174                                         WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
1175                                 }
1176                                 WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
1177                                 return;
1178                         }
1179                 }
1180
1181                 if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr))
1182                 {
1183                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, Ptr->name);
1184                         return;
1185                 }
1186
1187                 process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,false);
1188         }
1189         else
1190         {
1191                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
1192         }
1193 }
1194
1195
1196
1197
1198 void server_mode(char **parameters, int pcnt, userrec *user)
1199 {
1200         chanrec* Ptr;
1201         userrec* dest;
1202         int can_change,i;
1203         int direction = 1;
1204         char outpars[MAXBUF];
1205
1206         dest = Find(parameters[0]);
1207         
1208         // fix: ChroNiCk found this - we cant use this as debug if its null!
1209         if (dest)
1210         {
1211                 log(DEBUG,"server_mode on %s",dest->nick);
1212         }
1213
1214         if ((dest) && (pcnt > 1))
1215         {
1216                 log(DEBUG,"params > 1");
1217
1218                 char dmodes[MAXBUF];
1219                 strncpy(dmodes,dest->modes,MAXBUF);
1220
1221                 strcpy(outpars,"+");
1222                 direction = 1;
1223
1224                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1225                         return;
1226
1227                 for (int i = 0; i < strlen(parameters[1]); i++)
1228                 {
1229                         if (parameters[1][i] == '+')
1230                         {
1231                                 if (direction != 1)
1232                                 {
1233                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1234                                         {
1235                                                 outpars[strlen(outpars)-1] = '+';
1236                                         }
1237                                         else
1238                                         {
1239                                                 strcat(outpars,"+");
1240                                         }
1241                                 }
1242                                 direction = 1;
1243                         }
1244                         else
1245                         if (parameters[1][i] == '-')
1246                         {
1247                                 if (direction != 0)
1248                                 {
1249                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1250                                         {
1251                                                 outpars[strlen(outpars)-1] = '-';
1252                                         }
1253                                         else
1254                                         {
1255                                                 strcat(outpars,"-");
1256                                         }
1257                                 }
1258                                 direction = 0;
1259                         }
1260                         else
1261                         {
1262                                 log(DEBUG,"begin mode processing entry");
1263                                 can_change = 1;
1264                                 if (can_change)
1265                                 {
1266                                         if (direction == 1)
1267                                         {
1268                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1269                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1270                                                 {
1271                                                         char umode = parameters[1][i];
1272                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1273                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1274                                                         {
1275                                                                 dmodes[strlen(dmodes)+1]='\0';
1276                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1277                                                                 outpars[strlen(outpars)+1]='\0';
1278                                                                 outpars[strlen(outpars)] = parameters[1][i];
1279                                                         }
1280                                                 }
1281                                         }
1282                                         else
1283                                         {
1284                                                 // can only remove a mode they already have
1285                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1286                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1287                                                 {
1288                                                         char umode = parameters[1][i];
1289                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1290                                                         if ((process_module_umode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1291                                                         {
1292                                                                 int q = 0;
1293                                                                 char temp[MAXBUF];
1294                                                                 char moo[MAXBUF];       
1295
1296                                                                 outpars[strlen(outpars)+1]='\0';
1297                                                                 outpars[strlen(outpars)] = parameters[1][i];
1298                                                         
1299                                                                 strcpy(temp,"");
1300                                                                 for (q = 0; q < strlen(dmodes); q++)
1301                                                                 {
1302                                                                         if (dmodes[q] != parameters[1][i])
1303                                                                         {
1304                                                                                 moo[0] = dmodes[q];
1305                                                                                 moo[1] = '\0';
1306                                                                                 strcat(temp,moo);
1307                                                                         }
1308                                                                 }
1309                                                                 strcpy(dmodes,temp);
1310                                                         }
1311                                                 }
1312                                         }
1313                                 }
1314                         }
1315                 }
1316                 if (strlen(outpars))
1317                 {
1318                         char b[MAXBUF];
1319                         strcpy(b,"");
1320                         int z = 0;
1321                         int i = 0;
1322                         while (i < strlen (outpars))
1323                         {
1324                                 b[z++] = outpars[i++];
1325                                 b[z] = '\0';
1326                                 if (i<strlen(outpars)-1)
1327                                 {
1328                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1329                                         {
1330                                                 // someones playing silly buggers and trying
1331                                                 // to put a +- or -+ into the line...
1332                                                 i++;
1333                                         }
1334                                 }
1335                                 if (i == strlen(outpars)-1)
1336                                 {
1337                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1338                                         {
1339                                                 i++;
1340                                         }
1341                                 }
1342                         }
1343
1344                         z = strlen(b)-1;
1345                         if ((b[z] == '-') || (b[z] == '+'))
1346                                 b[z] == '\0';
1347
1348                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1349                                 return;
1350
1351                         WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1352
1353                         // M token for a usermode must go to all servers
1354                         char buffer[MAXBUF];
1355                         snprintf(buffer,MAXBUF,"m %s %s %s",user->nick, dest->nick, b);
1356                         NetSendToAll(buffer);
1357                         
1358                         if (strlen(dmodes)>MAXMODES)
1359                         {
1360                                 dmodes[MAXMODES-1] = '\0';
1361                         }
1362                         log(DEBUG,"Stripped mode line");
1363                         log(DEBUG,"Line dest is now %s",dmodes);
1364                         strncpy(dest->modes,dmodes,MAXMODES);
1365
1366                 }
1367
1368                 return;
1369         }
1370         
1371         Ptr = FindChan(parameters[0]);
1372         if (Ptr)
1373         {
1374                 process_modes(parameters,user,Ptr,STATUS_OP,pcnt,true,false,false);
1375         }
1376         else
1377         {
1378                 WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]);
1379         }
1380 }
1381
1382
1383
1384 void merge_mode(char **parameters, int pcnt)
1385 {
1386         chanrec* Ptr;
1387         userrec* dest;
1388         int can_change,i;
1389         int direction = 1;
1390         char outpars[MAXBUF];
1391
1392         dest = Find(parameters[0]);
1393         
1394         // fix: ChroNiCk found this - we cant use this as debug if its null!
1395         if (dest)
1396         {
1397                 log(DEBUG,"merge_mode on %s",dest->nick);
1398         }
1399
1400         if ((dest) && (pcnt > 1))
1401         {
1402                 log(DEBUG,"params > 1");
1403
1404                 char dmodes[MAXBUF];
1405                 strncpy(dmodes,dest->modes,MAXBUF);
1406
1407                 strcpy(outpars,"+");
1408                 direction = 1;
1409
1410                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1411                         return;
1412
1413                 for (int i = 0; i < strlen(parameters[1]); i++)
1414                 {
1415                         if (parameters[1][i] == '+')
1416                         {
1417                                 if (direction != 1)
1418                                 {
1419                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1420                                         {
1421                                                 outpars[strlen(outpars)-1] = '+';
1422                                         }
1423                                         else
1424                                         {
1425                                                 strcat(outpars,"+");
1426                                         }
1427                                 }
1428                                 direction = 1;
1429                         }
1430                         else
1431                         if (parameters[1][i] == '-')
1432                         {
1433                                 if (direction != 0)
1434                                 {
1435                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1436                                         {
1437                                                 outpars[strlen(outpars)-1] = '-';
1438                                         }
1439                                         else
1440                                         {
1441                                                 strcat(outpars,"-");
1442                                         }
1443                                 }
1444                                 direction = 0;
1445                         }
1446                         else
1447                         {
1448                                 log(DEBUG,"begin mode processing entry");
1449                                 can_change = 1;
1450                                 if (can_change)
1451                                 {
1452                                         if (direction == 1)
1453                                         {
1454                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1455                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],"o",true)))
1456                                                 {
1457                                                         char umode = parameters[1][i];
1458                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1459                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1460                                                         {
1461                                                                 dmodes[strlen(dmodes)+1]='\0';
1462                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1463                                                                 outpars[strlen(outpars)+1]='\0';
1464                                                                 outpars[strlen(outpars)] = parameters[1][i];
1465                                                         }
1466                                                 }
1467                                         }
1468                                         else
1469                                         {
1470                                                 // can only remove a mode they already have
1471                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1472                                                 if ((allowed_umode(parameters[1][i],"o",false)) && (strchr(dmodes,parameters[1][i])))
1473                                                 {
1474                                                         char umode = parameters[1][i];
1475                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1476                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1477                                                         {
1478                                                                 int q = 0;
1479                                                                 char temp[MAXBUF];
1480                                                                 char moo[MAXBUF];       
1481
1482                                                                 outpars[strlen(outpars)+1]='\0';
1483                                                                 outpars[strlen(outpars)] = parameters[1][i];
1484                                                         
1485                                                                 strcpy(temp,"");
1486                                                                 for (q = 0; q < strlen(dmodes); q++)
1487                                                                 {
1488                                                                         if (dmodes[q] != parameters[1][i])
1489                                                                         {
1490                                                                                 moo[0] = dmodes[q];
1491                                                                                 moo[1] = '\0';
1492                                                                                 strcat(temp,moo);
1493                                                                         }
1494                                                                 }
1495                                                                 strcpy(dmodes,temp);
1496                                                         }
1497                                                 }
1498                                         }
1499                                 }
1500                         }
1501                 }
1502                 if (strlen(outpars))
1503                 {
1504                         char b[MAXBUF];
1505                         strcpy(b,"");
1506                         int z = 0;
1507                         int i = 0;
1508                         while (i < strlen (outpars))
1509                         {
1510                                 b[z++] = outpars[i++];
1511                                 b[z] = '\0';
1512                                 if (i<strlen(outpars)-1)
1513                                 {
1514                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1515                                         {
1516                                                 // someones playing silly buggers and trying
1517                                                 // to put a +- or -+ into the line...
1518                                                 i++;
1519                                         }
1520                                 }
1521                                 if (i == strlen(outpars)-1)
1522                                 {
1523                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1524                                         {
1525                                                 i++;
1526                                         }
1527                                 }
1528                         }
1529
1530                         z = strlen(b)-1;
1531                         if ((b[z] == '-') || (b[z] == '+'))
1532                                 b[z] == '\0';
1533
1534                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1535                                 return;
1536
1537                         if (strlen(dmodes)>MAXMODES)
1538                         {
1539                                 dmodes[MAXMODES-1] = '\0';
1540                         }
1541                         log(DEBUG,"Stripped mode line");
1542                         log(DEBUG,"Line dest is now %s",dmodes);
1543                         strncpy(dest->modes,dmodes,MAXMODES);
1544
1545                 }
1546
1547                 return;
1548         }
1549         
1550         Ptr = FindChan(parameters[0]);
1551         if (Ptr)
1552         {
1553                 userrec s2;
1554                 strncpy(s2.nick,ServerName,NICKMAX);
1555                 strcpy(s2.modes,"o");
1556                 s2.fd = -1;
1557                 process_modes(parameters,&s2,Ptr,STATUS_OP,pcnt,true,true,false);
1558         }
1559 }
1560
1561
1562 void merge_mode2(char **parameters, int pcnt, userrec* user)
1563 {
1564         chanrec* Ptr;
1565         userrec* dest;
1566         int can_change,i;
1567         int direction = 1;
1568         char outpars[MAXBUF];
1569
1570         dest = Find(parameters[0]);
1571         
1572         // fix: ChroNiCk found this - we cant use this as debug if its null!
1573         if (dest)
1574         {
1575                 log(DEBUG,"merge_mode on %s",dest->nick);
1576         }
1577
1578         if ((dest) && (pcnt > 1))
1579         {
1580                 log(DEBUG,"params > 1");
1581
1582                 char dmodes[MAXBUF];
1583                 strncpy(dmodes,dest->modes,MAXBUF);
1584
1585                 strcpy(outpars,"+");
1586                 direction = 1;
1587
1588                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1589                         return;
1590
1591                 for (int i = 0; i < strlen(parameters[1]); i++)
1592                 {
1593                         if (parameters[1][i] == '+')
1594                         {
1595                                 if (direction != 1)
1596                                 {
1597                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1598                                         {
1599                                                 outpars[strlen(outpars)-1] = '+';
1600                                         }
1601                                         else
1602                                         {
1603                                                 strcat(outpars,"+");
1604                                         }
1605                                 }
1606                                 direction = 1;
1607                         }
1608                         else
1609                         if (parameters[1][i] == '-')
1610                         {
1611                                 if (direction != 0)
1612                                 {
1613                                         if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-'))
1614                                         {
1615                                                 outpars[strlen(outpars)-1] = '-';
1616                                         }
1617                                         else
1618                                         {
1619                                                 strcat(outpars,"-");
1620                                         }
1621                                 }
1622                                 direction = 0;
1623                         }
1624                         else
1625                         {
1626                                 log(DEBUG,"begin mode processing entry");
1627                                 can_change = 1;
1628                                 if (can_change)
1629                                 {
1630                                         if (direction == 1)
1631                                         {
1632                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1633                                                 if ((!strchr(dmodes,parameters[1][i])) && (allowed_umode(parameters[1][i],user->modes,true)))
1634                                                 {
1635                                                         char umode = parameters[1][i];
1636                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1637                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1638                                                         {
1639                                                                 dmodes[strlen(dmodes)+1]='\0';
1640                                                                 dmodes[strlen(dmodes)] = parameters[1][i];
1641                                                                 outpars[strlen(outpars)+1]='\0';
1642                                                                 outpars[strlen(outpars)] = parameters[1][i];
1643                                                         }
1644                                                 }
1645                                         }
1646                                         else
1647                                         {
1648                                                 // can only remove a mode they already have
1649                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1650                                                 if ((allowed_umode(parameters[1][i],user->modes,false)) && (strchr(dmodes,parameters[1][i])))
1651                                                 {
1652                                                         char umode = parameters[1][i];
1653                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1654                                                         if ((process_module_umode(umode, NULL, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1655                                                         {
1656                                                                 int q = 0;
1657                                                                 char temp[MAXBUF];
1658                                                                 char moo[MAXBUF];       
1659
1660                                                                 outpars[strlen(outpars)+1]='\0';
1661                                                                 outpars[strlen(outpars)] = parameters[1][i];
1662                                                         
1663                                                                 strcpy(temp,"");
1664                                                                 for (q = 0; q < strlen(dmodes); q++)
1665                                                                 {
1666                                                                         if (dmodes[q] != parameters[1][i])
1667                                                                         {
1668                                                                                 moo[0] = dmodes[q];
1669                                                                                 moo[1] = '\0';
1670                                                                                 strcat(temp,moo);
1671                                                                         }
1672                                                                 }
1673                                                                 strcpy(dmodes,temp);
1674                                                         }
1675                                                 }
1676                                         }
1677                                 }
1678                         }
1679                 }
1680                 if (strlen(outpars))
1681                 {
1682                         char b[MAXBUF];
1683                         strcpy(b,"");
1684                         int z = 0;
1685                         int i = 0;
1686                         while (i < strlen (outpars))
1687                         {
1688                                 b[z++] = outpars[i++];
1689                                 b[z] = '\0';
1690                                 if (i<strlen(outpars)-1)
1691                                 {
1692                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1693                                         {
1694                                                 // someones playing silly buggers and trying
1695                                                 // to put a +- or -+ into the line...
1696                                                 i++;
1697                                         }
1698                                 }
1699                                 if (i == strlen(outpars)-1)
1700                                 {
1701                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1702                                         {
1703                                                 i++;
1704                                         }
1705                                 }
1706                         }
1707
1708                         z = strlen(b)-1;
1709                         if ((b[z] == '-') || (b[z] == '+'))
1710                                 b[z] == '\0';
1711
1712                         if ((!strcmp(b,"+")) || (!strcmp(b,"-")))
1713                                 return;
1714
1715                         WriteTo(user,dest,"MODE :%s",b);
1716
1717                         if (strlen(dmodes)>MAXMODES)
1718                         {
1719                                 dmodes[MAXMODES-1] = '\0';
1720                         }
1721                         log(DEBUG,"Stripped mode line");
1722                         log(DEBUG,"Line dest is now %s",dmodes);
1723                         strncpy(dest->modes,dmodes,MAXMODES);
1724
1725                 }
1726
1727                 return;
1728         }
1729         
1730         Ptr = FindChan(parameters[0]);
1731         if (Ptr)
1732         {
1733                 log(DEBUG,"merge_mode2: found channel %s",Ptr->name);
1734                 if (Ptr)
1735                 {
1736                         if ((cstatus(user,Ptr) < STATUS_HOP) && (!is_uline(user->server)))
1737                         {
1738                                 return;
1739                         }
1740                         process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,true);
1741                 }
1742         }
1743 }
1744
1745