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