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