]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
16d7322ecaf289716dd7d8b46eafd5ceea36ec3c
[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         strlcpy(b.data,dest,MAXBUF);
432         strlcpy(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 (char* f = parameters[param]; *f; f++)
801                                                 {
802                                                         if ((*f < '0') || (*f > '9'))
803                                                         {
804                                                                 invalid = true;
805                                                         }
806                                                 }
807                                                 /* If the limit is < 1, or the new limit is the current limit, dont allow */
808                                                 if ((atoi(parameters[param]) < 1) || ((chan->limit > 0) && (atoi(parameters[param]) == chan->limit)))
809                                                 {
810                                                         invalid = true;
811                                                 }
812
813                                                 if (invalid)
814                                                         break;
815
816                                                 MOD_RESULT = 0;
817                                                 FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'l', parameters[param], true, 1));
818                                                 if (!MOD_RESULT)
819                                                 {
820         
821                                                         chan->limit = atoi(parameters[param]);
822                                                         
823                                                         // reported by mech: large values cause underflow
824                                                         if (chan->limit < 0)
825                                                                 chan->limit = 0x7FFF;
826                                                 }
827                                                         
828                                                 if (chan->limit)
829                                                 {
830                                                         strlcat(outlist,"l",MAXBUF);
831                                                         strlcpy(outpars[pc++],parameters[param++],MAXBUF);
832                                                         l_set = true;
833                                                 }
834                                         }
835                                 break;
836                                 
837                                 case 'i':
838                                         MOD_RESULT = 0;
839                                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'i', "", mdir, 0));
840                                         if (!MOD_RESULT)
841                                         {
842                                                 if (mdir)
843                                                 {
844                                                         if (!(chan->binarymodes & CM_INVITEONLY)) strlcat(outlist,"i",MAXBUF);
845                                                         chan->binarymodes |= CM_INVITEONLY;
846                                                 }
847                                                 else
848                                                 {
849                                                         if (chan->binarymodes & CM_INVITEONLY) strlcat(outlist,"i",MAXBUF);
850                                                         chan->binarymodes &= ~CM_INVITEONLY;
851                                                 }
852                                         }
853                                 break;
854                                 
855                                 case 't':
856                                         MOD_RESULT = 0;
857                                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 't', "", mdir, 0));
858                                         if (!MOD_RESULT)
859                                         {
860                                                 if (mdir)
861                                                 {
862                                                         if (!(chan->binarymodes & CM_TOPICLOCK)) strlcat(outlist,"t",MAXBUF);
863                                                         chan->binarymodes |= CM_TOPICLOCK;
864                                                 }
865                                                 else
866                                                 {
867                                                         if (chan->binarymodes & CM_NOEXTERNAL) strlcat(outlist,"t",MAXBUF);
868                                                         chan->binarymodes &= ~CM_TOPICLOCK;
869                                                 }
870                                         }
871                                 break;
872                                 
873                                 case 'n':
874                                         MOD_RESULT = 0;
875                                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'n', "", mdir, 0));
876                                         if (!MOD_RESULT)
877                                         {
878                                                 if (mdir)
879                                                 {
880                                                         if (!(chan->binarymodes & CM_NOEXTERNAL)) strlcat(outlist,"n",MAXBUF);
881                                                         chan->binarymodes |= CM_NOEXTERNAL;
882                                                 }
883                                                 else
884                                                 {
885                                                         if (chan->binarymodes & CM_NOEXTERNAL) strlcat(outlist,"n",MAXBUF);
886                                                         chan->binarymodes &= ~CM_NOEXTERNAL;
887                                                 }
888                                         }
889                                 break;
890                                 
891                                 case 'm':
892                                         MOD_RESULT = 0;
893                                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'm', "", mdir, 0));
894                                         if (!MOD_RESULT)
895                                         {
896                                                 if (mdir)
897                                                 {
898                                                         if (!(chan->binarymodes & CM_MODERATED)) strlcat(outlist,"m",MAXBUF);
899                                                         chan->binarymodes |= CM_MODERATED;
900                                                 }
901                                                 else
902                                                 {
903                                                         if (chan->binarymodes & CM_MODERATED) strlcat(outlist,"m",MAXBUF);
904                                                         chan->binarymodes &= ~CM_MODERATED;
905                                                 }
906                                         }
907                                 break;
908                                 
909                                 case 's':
910                                         MOD_RESULT = 0;
911                                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 's', "", mdir, 0));
912                                         if (!MOD_RESULT)
913                                         {
914                                                 if (mdir)
915                                                 {
916                                                         if (!(chan->binarymodes & CM_SECRET)) strlcat(outlist,"s",MAXBUF);
917                                                         chan->binarymodes |= CM_SECRET;
918                                                         if (chan->binarymodes & CM_PRIVATE)
919                                                         {
920                                                                 chan->binarymodes &= ~CM_PRIVATE;
921                                                                 if (mdir)
922                                                                 {
923                                                                         strlcat(outlist,"-p+",MAXBUF);
924                                                                 }
925                                                         }
926                                                 }
927                                                 else
928                                                 {
929                                                         if (chan->binarymodes & CM_SECRET) strlcat(outlist,"s",MAXBUF);
930                                                         chan->binarymodes &= ~CM_SECRET;
931                                                 }
932                                         }
933                                 break;
934                                 
935                                 case 'p':
936                                         MOD_RESULT = 0;
937                                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, 'p', "", mdir, 0));
938                                         if (!MOD_RESULT)
939                                         {
940                                                 if (mdir)
941                                                 {
942                                                         if (!(chan->binarymodes & CM_PRIVATE)) strlcat(outlist,"p",MAXBUF);
943                                                         chan->binarymodes |= CM_PRIVATE;
944                                                         if (chan->binarymodes & CM_SECRET)
945                                                         {
946                                                                 chan->binarymodes &= ~CM_SECRET;
947                                                                 if (mdir)
948                                                                 {
949                                                                         strlcat(outlist,"-s+",MAXBUF);
950                                                                 }
951                                                         }
952                                                 }
953                                                 else
954                                                 {
955                                                         if (chan->binarymodes & CM_PRIVATE) strlcat(outlist,"p",MAXBUF);
956                                                         chan->binarymodes &= ~CM_PRIVATE;
957                                                 }
958                                         }
959                                 break;
960                                 
961                                 default:
962                                         log(DEBUG,"Preprocessing custom mode %c: modelist: %s",*modechar,chan->custom_modes);
963                                         string_list p;
964                                         p.clear();
965                                         if (((!strchr(chan->custom_modes,*modechar)) && (!mdir)) || ((strchr(chan->custom_modes,*modechar)) && (mdir)))
966                                         {
967                                                 if (!ModeIsListMode(*modechar,MT_CHANNEL))
968                                                 {
969                                                         log(DEBUG,"Mode %c isnt set on %s but trying to remove!",*modechar,chan->name);
970                                                         break;
971                                                 }
972                                         }
973                                         if (ModeDefined(*modechar,MT_CHANNEL))
974                                         {
975                                                 log(DEBUG,"A module has claimed this mode");
976                                                 if (param<pcnt)
977                                                 {
978                                                         if ((ModeDefinedOn(*modechar,MT_CHANNEL)>0) && (mdir))
979                                                         {
980                                                                 p.push_back(parameters[param]);
981                                                         }
982                                                         if ((ModeDefinedOff(*modechar,MT_CHANNEL)>0) && (!mdir))
983                                                         {
984                                                                 p.push_back(parameters[param]);
985                                                         }
986                                                 }
987                                                 bool handled = false;
988                                                 if (param>=pcnt)
989                                                 {
990                                                         // we're supposed to have a parameter, but none was given... so dont handle the mode.
991                                                         if (((ModeDefinedOn(*modechar,MT_CHANNEL)>0) && (mdir)) || ((ModeDefinedOff(*modechar,MT_CHANNEL)>0) && (!mdir)))       
992                                                         {
993                                                                 log(DEBUG,"Not enough parameters for module-mode %c",*modechar);
994                                                                 handled = true;
995                                                                 param++;
996                                                         }
997                                                 }
998
999                                                 // BIG ASS IDIOTIC CODER WARNING!
1000                                                 // Using OnRawMode on another modules mode's behavour 
1001                                                 // will confuse the crap out of admins! just because you CAN
1002                                                 // do it, doesnt mean you SHOULD!
1003                                                 MOD_RESULT = 0;
1004                                                 std::string para = "";
1005                                                 if (p.size())
1006                                                         para = p[0];
1007                                                 FOREACH_RESULT(I_OnRawMode,OnRawMode(user, chan, *modechar, para, mdir, pcnt));
1008                                                 if (!MOD_RESULT)
1009                                                 {
1010                                                         for (int i = 0; i <= MODCOUNT; i++)
1011                                                         {
1012                                                                 if (!handled)
1013                                                                 {
1014                                                                         int t = modules[i]->OnExtendedMode(user,chan,*modechar,MT_CHANNEL,mdir,p);
1015                                                                         if (t != 0)
1016                                                                         {
1017                                                                                 log(DEBUG,"OnExtendedMode returned nonzero for a module");
1018                                                                                 char app[] = {*modechar, 0};
1019                                                                                 if (ModeIsListMode(*modechar,MT_CHANNEL))
1020                                                                                 {
1021                                                                                         if (t == -1)
1022                                                                                         {
1023                                                                                                 //pc++;
1024                                                                                                 param++;
1025                                                                                         }
1026                                                                                         else
1027                                                                                         {
1028                                                                                                 if (ptr>0)
1029                                                                                                 {
1030                                                                                                         strlcat(outlist, app,MAXBUF);
1031                                                                                                 }
1032                                                                                                 strlcpy(outpars[pc++],parameters[param++],MAXBUF);
1033                                                                                         }
1034                                                                                 }
1035                                                                                 else
1036                                                                                 {
1037                                                                                         if (ptr>0)
1038                                                                                         {
1039                                                                                                 if ((modelist[ptr-1] == '+') || (modelist[ptr-1] == '-'))
1040                                                                                                 {
1041                                                                                                         strlcat(outlist, app,MAXBUF);
1042                                                                                                 }
1043                                                                                                 else if (!strchr(outlist,*modechar))
1044                                                                                                 {
1045                                                                                                         strlcat(outlist, app,MAXBUF);
1046                                                                                                 }
1047                                                                                         }
1048                                                                                         chan->SetCustomMode(*modechar,mdir);
1049                                                                                         // include parameters in output if mode has them
1050                                                                                         if ((ModeDefinedOn(*modechar,MT_CHANNEL)>0) && (mdir))
1051                                                                                         {
1052                                                                                                 chan->SetCustomModeParam(modelist[ptr],parameters[param],mdir);
1053                                                                                                 strlcpy(outpars[pc++],parameters[param++],MAXBUF);
1054                                                                                         }
1055                                                                                 }
1056                                                                                 // break, because only one module can handle the mode.
1057                                                                                 handled = true;
1058                                                                         }
1059                                                                 }
1060                                                         }
1061                                                 }
1062                                         }
1063                                         else
1064                                         {
1065                                                 WriteServ(user->fd,"472 %s %c :is unknown mode char to me",user->nick,*modechar);
1066                                         }
1067                                 break;
1068                                 
1069                         }
1070                 }
1071         }
1072
1073         /* this ensures only the *valid* modes are sent out onto the network */
1074         int xt = strlen(outlist)-1;
1075         while ((outlist[xt] == '-') || (outlist[xt] == '+'))
1076         {
1077                 outlist[xt] = '\0';
1078                 xt = strlen(outlist)-1;
1079         }
1080         if (outlist[0])
1081         {
1082                 strlcpy(outstr,outlist,MAXBUF);
1083                 for (ptr = 0; ptr < pc; ptr++)
1084                 {
1085                         strlcat(outstr," ",MAXBUF);
1086                         strlcat(outstr,outpars[ptr],MAXBUF);
1087                 }
1088                 if (local)
1089                 {
1090                         log(DEBUG,"Local mode change");
1091                         WriteChannelLocal(chan, user, "MODE %s %s",chan->name,outstr);
1092                         FOREACH_MOD(I_OnMode,OnMode(user, chan, TYPE_CHANNEL, outstr));
1093                 }
1094                 else
1095                 {
1096                         if (servermode)
1097                         {
1098                                 if (!silent)
1099                                 {
1100                                         WriteChannelWithServ(Config->ServerName,chan,"MODE %s %s",chan->name,outstr);
1101                                 }
1102                                         
1103                         }
1104                         else
1105                         {
1106                                 if (!silent)
1107                                 {
1108                                         WriteChannel(chan,user,"MODE %s %s",chan->name,outstr);
1109                                         FOREACH_MOD(I_OnMode,OnMode(user, chan, TYPE_CHANNEL, outstr));
1110                                 }
1111                         }
1112                 }
1113         }
1114 }
1115
1116 // based on sourcemodes, return true or false to determine if umode is a valid mode a user may set on themselves or others.
1117
1118 bool ModeParser::AllowedUmode(char umode, char* sourcemodes,bool adding,bool serveroverride)
1119 {
1120         log(DEBUG,"Allowed_umode: %c %s",umode,sourcemodes);
1121         // Servers can +o and -o arbitrarily
1122         if ((serveroverride == true) && (umode == 'o'))
1123         {
1124                 return true;
1125         }
1126         // RFC1459 specified modes
1127         if ((umode == 'w') || (umode == 's') || (umode == 'i'))
1128         {
1129                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
1130                 return true;
1131         }
1132         
1133         // user may not +o themselves or others, but an oper may de-oper other opers or themselves
1134         if ((strchr(sourcemodes,'o')) && (!adding))
1135         {
1136                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
1137                 return true;
1138         }
1139         else if (umode == 'o')
1140         {
1141                 log(DEBUG,"umode %c allowed by RFC1459 scemantics",umode);
1142                 return false;
1143         }
1144         
1145         // process any module-defined modes that need oper
1146         if ((ModeDefinedOper(umode,MT_CLIENT)) && (strchr(sourcemodes,'o')))
1147         {
1148                 log(DEBUG,"umode %c allowed by module handler (oper only mode)",umode);
1149                 return true;
1150         }
1151         else
1152         if (ModeDefined(umode,MT_CLIENT))
1153         {
1154                 // process any module-defined modes that don't need oper
1155                 log(DEBUG,"umode %c allowed by module handler (non-oper mode)",umode);
1156                 if ((ModeDefinedOper(umode,MT_CLIENT)) && (!strchr(sourcemodes,'o')))
1157                 {
1158                         // no, this mode needs oper, and this user 'aint got what it takes!
1159                         return false;
1160                 }
1161                 return true;
1162         }
1163
1164         // anything else - return false.
1165         log(DEBUG,"umode %c not known by any ruleset",umode);
1166         return false;
1167 }
1168
1169 bool ModeParser::ProcessModuleUmode(char umode, userrec* source, void* dest, bool adding)
1170 {
1171         userrec* s2;
1172         bool faked = false;
1173         if (!source)
1174         {
1175                 s2 = new userrec;
1176                 strlcpy(s2->nick,Config->ServerName,NICKMAX);
1177                 strlcpy(s2->modes,"o",52);
1178                 s2->fd = -1;
1179                 source = s2;
1180                 faked = true;
1181         }
1182         string_list p;
1183         p.clear();
1184         if (ModeDefined(umode,MT_CLIENT))
1185         {
1186                 for (int i = 0; i <= MODCOUNT; i++)
1187                 {
1188                         if (modules[i]->OnExtendedMode(source,(void*)dest,umode,MT_CLIENT,adding,p))
1189                         {
1190                                 log(DEBUG,"Module %s claims umode %c",Config->module_names[i].c_str(),umode);
1191                                 return true;
1192                         }
1193                 }
1194                 log(DEBUG,"No module claims umode %c",umode);
1195                 if (faked)
1196                 {
1197                         delete s2;
1198                         source = NULL;
1199                 }
1200                 return false;
1201         }
1202         else
1203         {
1204                 if (faked)
1205                 {
1206                         delete s2;
1207                         source = NULL;
1208                 }
1209                 return false;
1210         }
1211 }
1212
1213 void cmd_mode::Handle (char **parameters, int pcnt, userrec *user)
1214 {
1215         chanrec* Ptr;
1216         userrec* dest;
1217         int can_change;
1218         int direction = 1;
1219         char outpars[MAXBUF];
1220
1221         dest = Find(parameters[0]);
1222
1223         if (!user)
1224         {
1225                 return;
1226         }
1227
1228         if ((dest) && (pcnt == 1))
1229         {
1230                 WriteServ(user->fd,"221 %s :+%s",dest->nick,dest->modes);
1231                 return;
1232         }
1233
1234         if ((dest) && (pcnt > 1))
1235         {
1236                 std::string tidied = ServerInstance->ModeGrok->CompressModes(parameters[1],false);
1237                 parameters[1] = (char*)tidied.c_str();
1238
1239                 char dmodes[MAXBUF];
1240                 strlcpy(dmodes,dest->modes,52);
1241                 log(DEBUG,"pulled up dest user modes: %s",dmodes);
1242
1243                 can_change = 0;
1244                 if (user != dest)
1245                 {
1246                         if ((strchr(user->modes,'o')) || (is_uline(user->server)))
1247                         {
1248                                 can_change = 1;
1249                         }
1250                 }
1251                 else
1252                 {
1253                         can_change = 1;
1254                 }
1255                 if (!can_change)
1256                 {
1257                         WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick);
1258                         return;
1259                 }
1260                 
1261                 outpars[0] = '+';
1262                 outpars[1] = 0;
1263                 direction = 1;
1264
1265                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1266                         return;
1267
1268                 for (unsigned int i = 0; i < strlen(parameters[1]); i++)
1269                 {
1270                         if (parameters[1][i] == ' ')
1271                                 continue;
1272                         if (parameters[1][i] == '+')
1273                         {
1274                                 if (direction != 1)
1275                                 {
1276                                         int t = strlen(outpars)-1;
1277                                         if ((outpars[t] == '+') || (outpars[t] == '-'))
1278                                         {
1279                                                 outpars[t] = '+';
1280                                         }
1281                                         else
1282                                         {
1283                                                 strcat(outpars,"+");
1284                                         }
1285                                 }
1286                                 direction = 1;
1287                         }
1288                         else
1289                         if (parameters[1][i] == '-')
1290                         {
1291                                 if (direction != 0)
1292                                 {
1293                                         int t = strlen(outpars)-1;
1294                                         if ((outpars[t] == '+') || (outpars[t] == '-'))
1295                                         {
1296                                                 outpars[t] = '-';
1297                                         }
1298                                         else
1299                                         {
1300                                                 strcat(outpars,"-");
1301                                         }
1302                                 }
1303                                 direction = 0;
1304                         }
1305                         else
1306                         {
1307                                 can_change = 0;
1308                                 if (strchr(user->modes,'o'))
1309                                 {
1310                                         can_change = 1;
1311                                 }
1312                                 else
1313                                 {
1314                                         if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's') || (ServerInstance->ModeGrok->AllowedUmode(parameters[1][i],user->modes,direction,false)))
1315                                         {
1316                                                 can_change = 1;
1317                                         }
1318                                 }
1319                                 if (can_change)
1320                                 {
1321                                         if (direction == 1)
1322                                         {
1323                                                 if ((!strchr(dmodes,parameters[1][i])) && (ServerInstance->ModeGrok->AllowedUmode(parameters[1][i],user->modes,true,false)))
1324                                                 {
1325                                                         char umode = parameters[1][i];
1326                                                         if ((ServerInstance->ModeGrok->ProcessModuleUmode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1327                                                         {
1328                                                                 int q = strlen(dmodes);
1329                                                                 int r = strlen(outpars);
1330                                                                 dmodes[q+1]='\0';
1331                                                                 dmodes[q] = parameters[1][i];
1332                                                                 outpars[r+1]='\0';
1333                                                                 outpars[r] = parameters[1][i];
1334                                                                 if (parameters[1][i] == 'o')
1335                                                                 {
1336                                                                         FOREACH_MOD(I_OnGlobalOper,OnGlobalOper(dest));
1337                                                                 }
1338                                                         }
1339                                                 }
1340                                         }
1341                                         else
1342                                         {
1343                                                 if ((ServerInstance->ModeGrok->AllowedUmode(parameters[1][i],user->modes,false,false)) && (strchr(dmodes,parameters[1][i])))
1344                                                 {
1345                                                         char umode = parameters[1][i];
1346                                                         if ((ServerInstance->ModeGrok->ProcessModuleUmode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1347                                                         {
1348                                                                 unsigned int q = 0;
1349                                                                 char temp[MAXBUF];      
1350                                                                 char moo[MAXBUF];       
1351
1352                                                                 unsigned int r = strlen(outpars);
1353                                                                 outpars[r+1]='\0';
1354                                                                 outpars[r] = parameters[1][i];
1355                                                         
1356                                                                 *temp = 0;
1357                                                                 for (q = 0; q < strlen(dmodes); q++)
1358                                                                 {
1359                                                                         if (dmodes[q] != parameters[1][i])
1360                                                                         {
1361                                                                                 moo[0] = dmodes[q];
1362                                                                                 moo[1] = '\0';
1363                                                                                 strlcat(temp,moo,MAXBUF);
1364                                                                         }
1365                                                                 }
1366                                                                 strlcpy(dmodes,temp,52);
1367
1368                                                                 if (umode == 'o')
1369                                                                 {
1370                                                                         *dest->oper = 0;
1371                                                                         DeleteOper(dest);
1372                                                                 }
1373                                                         }
1374                                                 }
1375                                         }
1376                                 }
1377                         }
1378                 }
1379                 if (outpars[0])
1380                 {
1381                         char b[MAXBUF];
1382                         strlcpy(b,"",MAXBUF);
1383                         unsigned int z = 0;
1384                         unsigned int i = 0;
1385                         while (i < strlen (outpars))
1386                         {
1387                                 b[z++] = outpars[i++];
1388                                 b[z] = '\0';
1389                                 if (i<strlen(outpars)-1)
1390                                 {
1391                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1392                                         {
1393                                                 // someones playing silly buggers and trying
1394                                                 // to put a +- or -+ into the line...
1395                                                 i++;
1396                                         }
1397                                 }
1398                                 if (i == strlen(outpars)-1)
1399                                 {
1400                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1401                                         {
1402                                                 i++;
1403                                         }
1404                                 }
1405                         }
1406
1407                         z = strlen(b)-1;
1408                         if ((b[z] == '-') || (b[z] == '+'))
1409                                 b[z] = '\0';
1410
1411                         if ((!b[0]) || (!strcmp(b,"+")) || (!strcmp(b,"-")))
1412                                 return;
1413
1414                         if (strcmp(b,""))
1415                         {
1416                                 WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1417                                 FOREACH_MOD(I_OnMode,OnMode(user, dest, TYPE_USER, b));
1418                         }
1419
1420                         if (strlen(dmodes)>MAXMODES)
1421                         {
1422                                 dmodes[MAXMODES-1] = '\0';
1423                         }
1424                         log(DEBUG,"Stripped mode line");
1425                         log(DEBUG,"Line dest is now %s",dmodes);
1426                         strlcpy(dest->modes,dmodes,52);
1427
1428                 }
1429
1430                 return;
1431         }
1432         
1433         Ptr = FindChan(parameters[0]);
1434         if (Ptr)
1435         {
1436                 if (pcnt == 1)
1437                 {
1438                         /* just /modes #channel */
1439                         WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr));
1440                         WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created);
1441                         return;
1442                 }
1443                 else
1444                 if (pcnt == 2)
1445                 {
1446                         char* mode = parameters[1];
1447                         if (*mode == '+')
1448                                 mode++;
1449                         int MOD_RESULT = 0;
1450                         FOREACH_RESULT(I_OnRawMode,OnRawMode(user, Ptr, *mode, "", false, 0));
1451                         if (!MOD_RESULT)
1452                         {
1453                                 if (*mode == 'b')
1454                                 {
1455
1456                                         for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++)
1457                                         {
1458                                                 WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time);
1459                                         }
1460                                         WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name);
1461                                         return;
1462                                 }
1463                                 if ((ModeDefined(*mode,MT_CHANNEL)) && (ModeIsListMode(*mode,MT_CHANNEL)))
1464                                 {
1465                                         // list of items for an extmode
1466                                         log(DEBUG,"Calling OnSendList for all modules, list output for mode %c",*mode);
1467                                         FOREACH_MOD(I_OnSendList,OnSendList(user,Ptr,*mode));
1468                                         return;
1469                                 }
1470                         }
1471                 }
1472
1473                 if (((Ptr) && (!has_channel(user,Ptr))) && (!is_uline(user->server)))
1474                 {
1475                         WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, Ptr->name);
1476                         return;
1477                 }
1478
1479                 if (Ptr)
1480                 {
1481                         int MOD_RESULT = 0;
1482                         FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user,NULL,Ptr,AC_GENERAL_MODE));
1483                         
1484                         if (MOD_RESULT == ACR_DENY)
1485                                 return;
1486                         if (MOD_RESULT == ACR_DEFAULT)
1487                         {
1488                                 if (cstatus(user,Ptr) < STATUS_HOP)
1489                                 {
1490                                         WriteServ(user->fd,"482 %s %s :You must be at least a half-operator to change modes on this channel",user->nick, Ptr->name);
1491                                         return;
1492                                 }
1493                         }
1494
1495                         ServerInstance->ModeGrok->ProcessModes(parameters,user,Ptr,cstatus(user,Ptr),pcnt,false,false,false);
1496                 }
1497         }
1498         else
1499         {
1500                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
1501         }
1502 }
1503
1504
1505
1506
1507 void ModeParser::ServerMode(char **parameters, int pcnt, userrec *user)
1508 {
1509         chanrec* Ptr;
1510         userrec* dest;
1511         int can_change;
1512         int direction = 1;
1513         char outpars[MAXBUF];
1514
1515         dest = Find(parameters[0]);
1516         
1517         // fix: ChroNiCk found this - we cant use this as debug if its null!
1518         if (dest)
1519         {
1520                 log(DEBUG,"server_mode on %s",dest->nick);
1521         }
1522
1523         if ((dest) && (pcnt > 1))
1524         {
1525                 std::string tidied = ServerInstance->ModeGrok->CompressModes(parameters[1],false);
1526                 parameters[1] = (char*)tidied.c_str();
1527
1528                 char dmodes[MAXBUF];
1529                 strlcpy(dmodes,dest->modes,52);
1530
1531                 outpars[0] = '+';
1532                 outpars[1] = 0;
1533                 direction = 1;
1534
1535                 if ((parameters[1][0] != '+') && (parameters[1][0] != '-'))
1536                         return;
1537
1538                 for (unsigned int i = 0; i < strlen(parameters[1]); i++)
1539                 {
1540                         if (parameters[1][i] == ' ')
1541                                 continue;
1542                         if (parameters[1][i] == '+')
1543                         {
1544                                 if (direction != 1)
1545                                 {
1546                                         int t = strlen(outpars)-1;
1547                                         if ((outpars[t] == '+') || (outpars[t] == '-'))
1548                                         {
1549                                                 outpars[t] = '+';
1550                                         }
1551                                         else
1552                                         {
1553                                                 strcat(outpars,"+");
1554                                         }
1555                                 }
1556                                 direction = 1;
1557                         }
1558                         else
1559                         if (parameters[1][i] == '-')
1560                         {
1561                                 if (direction != 0)
1562                                 {
1563                                         int t = strlen(outpars)-1;
1564                                         if ((outpars[t] == '+') || (outpars[t] == '-'))
1565                                         {
1566                                                 outpars[t] = '-';
1567                                         }
1568                                         else
1569                                         {
1570                                                 strcat(outpars,"-");
1571                                         }
1572                                 }
1573                                 direction = 0;
1574                         }
1575                         else
1576                         {
1577                                 log(DEBUG,"begin mode processing entry");
1578                                 can_change = 1;
1579                                 if (can_change)
1580                                 {
1581                                         if (direction == 1)
1582                                         {
1583                                                 log(DEBUG,"umode %c being added",parameters[1][i]);
1584                                                 if ((!strchr(dmodes,parameters[1][i])) && (ServerInstance->ModeGrok->AllowedUmode(parameters[1][i],user->modes,true,true)))
1585                                                 {
1586                                                         char umode = parameters[1][i];
1587                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1588                                                         if ((ServerInstance->ModeGrok->ProcessModuleUmode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1589                                                         {
1590                                                                 int v1 = strlen(dmodes);
1591                                                                 int v2 = strlen(outpars);
1592                                                                 dmodes[v1+1]='\0';
1593                                                                 dmodes[v1] = parameters[1][i];
1594                                                                 outpars[v2+1]='\0';
1595                                                                 outpars[v2] = parameters[1][i];
1596                                                         }
1597                                                 }
1598                                         }
1599                                         else
1600                                         {
1601                                                 // can only remove a mode they already have
1602                                                 log(DEBUG,"umode %c being removed",parameters[1][i]);
1603                                                 if ((ServerInstance->ModeGrok->AllowedUmode(parameters[1][i],user->modes,false,true)) && (strchr(dmodes,parameters[1][i])))
1604                                                 {
1605                                                         char umode = parameters[1][i];
1606                                                         log(DEBUG,"umode %c is an allowed umode",umode);
1607                                                         if ((ServerInstance->ModeGrok->ProcessModuleUmode(umode, user, dest, direction)) || (umode == 'i') || (umode == 's') || (umode == 'w') || (umode == 'o'))
1608                                                         {
1609                                                                 unsigned int q = 0;
1610                                                                 char temp[MAXBUF];
1611                                                                 char moo[MAXBUF];       
1612
1613                                                                 unsigned int v1 = strlen(outpars);
1614                                                                 outpars[v1+1]='\0';
1615                                                                 outpars[v1] = parameters[1][i];
1616                                                                 *temp = 0;
1617                                                                 for (q = 0; q < strlen(dmodes); q++)
1618                                                                 {
1619                                                                         if (dmodes[q] != parameters[1][i])
1620                                                                         {
1621                                                                                 moo[0] = dmodes[q];
1622                                                                                 moo[1] = '\0';
1623                                                                                 strlcat(temp,moo,MAXBUF);
1624                                                                         }
1625                                                                 }
1626                                                                 strlcpy(dmodes,temp,52);
1627                                                         }
1628                                                 }
1629                                         }
1630                                 }
1631                         }
1632                 }
1633                 if (outpars[0])
1634                 {
1635                         char b[MAXBUF];
1636                         strlcpy(b,"",MAXBUF);
1637                         unsigned int z = 0;
1638                         unsigned int i = 0;
1639                         while (i < strlen (outpars))
1640                         {
1641                                 b[z++] = outpars[i++];
1642                                 b[z] = '\0';
1643                                 if (i<strlen(outpars)-1)
1644                                 {
1645                                         if (((outpars[i] == '-') || (outpars[i] == '+')) && ((outpars[i+1] == '-') || (outpars[i+1] == '+')))
1646                                         {
1647                                                 // someones playing silly buggers and trying
1648                                                 // to put a +- or -+ into the line...
1649                                                 i++;
1650                                         }
1651                                 }
1652                                 if (i == strlen(outpars)-1)
1653                                 {
1654                                         if ((outpars[i] == '-') || (outpars[i] == '+'))
1655                                         {
1656                                                 i++;
1657                                         }
1658                                 }
1659                         }
1660
1661                         z = strlen(b)-1;
1662                         if ((b[z] == '-') || (b[z] == '+'))
1663                                 b[z] = '\0';
1664
1665                         if ((!b[0]) || (!strcmp(b,"+")) || (!strcmp(b,"-")))
1666                                 return;
1667
1668                         if (strcmp(b,""))
1669                         {
1670                                 WriteTo(user, dest, "MODE %s :%s", dest->nick, b);
1671                                 FOREACH_MOD(I_OnMode,OnMode(user, dest, TYPE_USER, b));
1672                         }
1673                         
1674                         if (strlen(dmodes)>MAXMODES)
1675                         {
1676                                 dmodes[MAXMODES-1] = '\0';
1677                         }
1678                         log(DEBUG,"Stripped mode line");
1679                         log(DEBUG,"Line dest is now %s",dmodes);
1680                         strlcpy(dest->modes,dmodes,MAXMODES);
1681
1682                 }
1683
1684                 return;
1685         }
1686         
1687         Ptr = FindChan(parameters[0]);
1688         if (Ptr)
1689         {
1690                 ServerInstance->ModeGrok->ProcessModes(parameters,user,Ptr,STATUS_OP,pcnt,true,false,false);
1691         }
1692         else
1693         {
1694                 WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]);
1695         }
1696 }