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