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