]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Fix a cosmetic issue: 'oper type does not have access'
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDmode */
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
18
19 #include "inspircd.h"
20 #include "inspstring.h"
21
22 /* +s (secret) */
23 #include "modes/cmode_s.h"
24 /* +p (private) */
25 #include "modes/cmode_p.h"
26 /* +b (bans) */
27 #include "modes/cmode_b.h"
28 /* +m (moderated) */
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
40 /* +o (channel op) */
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +s (server notices) */
47 #include "modes/umode_s.h"
48 /* +w (see wallops) */
49 #include "modes/umode_w.h"
50 /* +i (invisible) */
51 #include "modes/umode_i.h"
52 /* +o (operator) */
53 #include "modes/umode_o.h"
54 /* +n (notice mask - our implementation of snomasks) */
55 #include "modes/umode_n.h"
56
57 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
58         : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
59 {
60 }
61
62 ModeHandler::~ModeHandler()
63 {
64 }
65
66 bool ModeHandler::IsListMode()
67 {
68         return list;
69 }
70
71 char ModeHandler::GetNeededPrefix()
72 {
73         return prefixneeded;
74 }
75
76 void ModeHandler::SetNeededPrefix(char needsprefix)
77 {
78         prefixneeded = needsprefix;
79 }
80
81 unsigned int ModeHandler::GetPrefixRank()
82 {
83         return 0;
84 }
85
86 unsigned int ModeHandler::GetCount()
87 {
88         return 0;
89 }
90
91 void ModeHandler::ChangeCount(int modifier)
92 {
93         count += modifier;
94         ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
95 }
96
97 ModeType ModeHandler::GetModeType()
98 {
99         return m_type;
100 }
101
102 bool ModeHandler::NeedsOper()
103 {
104         return oper;
105 }
106
107 char ModeHandler::GetPrefix()
108 {
109         return prefix;
110 }
111
112 int ModeHandler::GetNumParams(bool adding)
113 {
114         return adding ? n_params_on : n_params_off;
115 }
116
117 char ModeHandler::GetModeChar()
118 {
119         return mode;
120 }
121
122 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
123 {
124         return MODEACTION_DENY;
125 }
126
127 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
128 {
129         if (dest)
130         {
131                 return std::make_pair(dest->IsModeSet(this->mode), "");
132         }
133         else
134         {
135                 return std::make_pair(channel->IsModeSet(this->mode), "");
136         }
137 }
138
139 void ModeHandler::DisplayList(User*, Channel*)
140 {
141 }
142
143 void ModeHandler::DisplayEmptyList(User*, Channel*)
144 {
145 }
146
147 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
148 {
149         return (ours < theirs);
150 }
151
152 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
153 {
154 }
155
156 ModeWatcher::~ModeWatcher()
157 {
158 }
159
160 char ModeWatcher::GetModeChar()
161 {
162         return mode;
163 }
164
165 ModeType ModeWatcher::GetModeType()
166 {
167         return m_type;
168 }
169
170 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
171 {
172         return true;
173 }
174
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
176 {
177 }
178
179 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
180 {
181         User *d;
182         if ((!user) || (!dest) || (!chan) || (!*dest))
183         {
184                 return NULL;
185         }
186         d = ServerInstance->FindNick(dest);
187         if (!d)
188         {
189                 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, dest);
190                 return NULL;
191         }
192         return d;
193 }
194
195 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
196 {
197         if (!chan)
198                 return "";
199
200         UCListIter n = d->chans.find(chan);
201         if (n != d->chans.end())
202         {
203                 if (n->second & MASK)
204                 {
205                         return "";
206                 }
207                 n->second = n->second | MASK;
208                 switch (MASK)
209                 {
210                         case UCMODE_OP:
211                                 n->first->AddOppedUser(d);
212                         break;
213                         case UCMODE_HOP:
214                                 n->first->AddHalfoppedUser(d);
215                         break;
216                         case UCMODE_VOICE:
217                                 n->first->AddVoicedUser(d);
218                         break;
219                 }
220                 return d->nick;
221         }
222         return "";
223 }
224
225 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
226 {
227         if (!chan)
228                 return "";
229
230         UCListIter n = d->chans.find(chan);
231         if (n != d->chans.end())
232         {
233                 if ((n->second & MASK) == 0)
234                 {
235                         return "";
236                 }
237                 n->second ^= MASK;
238                 switch (MASK)
239                 {
240                         case UCMODE_OP:
241                                 n->first->DelOppedUser(d);
242                         break;
243                         case UCMODE_HOP:
244                                 n->first->DelHalfoppedUser(d);
245                         break;
246                         case UCMODE_VOICE:
247                                 n->first->DelVoicedUser(d);
248                         break;
249                 }
250                 return d->nick;
251         }
252         return "";
253 }
254
255 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
256 {
257         if (targetchannel)
258         {
259                 /* Display channel's current mode string */
260                 user->WriteNumeric(324, "%s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261                 user->WriteNumeric(329, "%s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
262                 return;
263         }
264         else if (targetuser)
265         {
266                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
267                 {
268                         user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, text);
269                         return;
270                 }
271
272                 if ((targetuser == user) || (IS_OPER(user)))
273                 {
274                         /* Display user's current mode string */
275                         user->WriteNumeric(221, "%s :+%s",targetuser->nick,targetuser->FormatModes());
276                         if (IS_OPER(targetuser))
277                                 user->WriteNumeric(8, "%s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
278                         return;
279                 }
280                 else
281                 {
282                         user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
283                         return;
284                 }
285         }
286
287         /* No such nick/channel */
288         user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, text);
289         return;
290 }
291
292 void ModeParser::Process(const char* const* parameters, int pcnt, User *user, bool servermode)
293 {
294         std::string target = parameters[0];
295         ModeType type = MODETYPE_USER;
296         unsigned char mask = 0;
297         Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
298         User* targetuser  = ServerInstance->FindNick(parameters[0]);
299
300         LastParse.clear();
301
302         /* Special case for displaying the list for listmodes,
303          * e.g. MODE #chan b, or MODE #chan +b without a parameter
304          */
305         if ((targetchannel) && (pcnt == 2))
306         {
307                 const char* mode = parameters[1];
308                 int nonlistmodes_found = 0;
309                 bool sent[256];
310
311                 mask = MASK_CHANNEL;
312
313                 memset(&sent, 0, 256);
314                 
315                 while (mode && *mode)
316                 {
317                         unsigned char mletter = *mode;
318
319                         if (*mode == '+')
320                         {
321                                 mode++;
322                                 continue;
323                         }
324                         
325                         /* Ensure the user doesnt request the same mode twice,
326                          * so they cant flood themselves off out of idiocy.
327                          */
328                         if (!sent[mletter])
329                         {
330                                 sent[mletter] = true;
331                         }
332                         else
333                         {
334                                 mode++;
335                                 continue;
336                         }
337
338                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
339                         bool display = true;
340
341                         if ((mh) && (mh->IsListMode()))
342                         {
343                                 int MOD_RESULT = 0;
344                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
345                                 if (MOD_RESULT == ACR_DENY)
346                                 {
347                                         mode++;
348                                         continue;
349                                 }
350
351                                 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
352                                 {
353                                         user->WriteNumeric(482, "%s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
354                                         mh->DisplayEmptyList(user, targetchannel);
355                                         continue;
356                                 }
357
358                                 /** See below for a description of what craq this is :D
359                                  */
360                                 unsigned char handler_id = (*mode - 65) | mask;
361
362                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
363                                 {
364                                         std::string dummyparam;
365                                         
366                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
367                                                 display = false;
368                                 }
369
370                                 if (display)
371                                         mh->DisplayList(user, targetchannel);
372                         }
373                         else
374                                 nonlistmodes_found++;
375
376                         mode++;
377                 }
378
379                 /* We didnt have any modes that were non-list, we can return here */
380                 if (!nonlistmodes_found)
381                         return;
382         }
383
384         if (pcnt == 1)
385         {
386                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
387         }
388         else if (pcnt > 1)
389         {
390                 bool SkipAccessChecks = false;
391
392                 if (targetchannel)
393                 {
394                         type = MODETYPE_CHANNEL;
395                         mask = MASK_CHANNEL;
396
397                         /* Extra security checks on channel modes
398                          * (e.g. are they a (half)op?
399                          */
400
401                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
402                         {
403                                 /* We don't have halfop */
404                                 int MOD_RESULT = 0;
405                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
406                                 if (MOD_RESULT == ACR_DENY)
407                                         return;
408                                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
409                         }
410                 }
411                 else if (targetuser)
412                 {
413                         type = MODETYPE_USER;
414                         mask = MASK_USER;
415                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
416                         {
417                                 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
418                                 return;
419                         }
420                 }
421                 else
422                 {
423                         /* No such nick/channel */
424                         user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, parameters[0]);
425                         return;
426                 }
427
428                 std::string mode_sequence = parameters[1];
429                 std::string parameter;
430                 std::ostringstream parameter_list;
431                 std::string output_sequence;
432                 bool adding = true, state_change = false;
433                 unsigned char handler_id = 0;
434                 int parameter_counter = 2; /* Index of first parameter */
435                 int parameter_count = 0;
436                 bool last_successful_state_change = false;
437
438                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
439                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
440                         mode_sequence.insert(0, "+");
441
442                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
443                 {
444                         unsigned char modechar = *letter;
445
446                         switch (modechar)
447                         {
448                                 /* NB:
449                                  * For + and - mode characters, we don't just stick the character into the output sequence.
450                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
451                                  * appearing in the output sequence, we store a flag which says there was a state change,
452                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
453                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
454                                  */
455                                 case '+':
456                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
457                                          * however, will allow the + if it is the first item in the sequence, regardless.
458                                          */
459                                         if ((!adding) || (!output_sequence.length()))
460                                                 state_change = true;
461                                         adding = true;
462                                         if (!output_sequence.length())
463                                                 last_successful_state_change = false;
464                                         continue;
465                                 break;
466                                 case '-':
467                                         if ((adding) || (!output_sequence.length()))
468                                                 state_change = true;
469                                         adding = false;
470                                         if (!output_sequence.length())
471                                                 last_successful_state_change = true;
472                                         continue;
473                                 break;
474                                 default:
475
476                                         /**
477                                          * Watch carefully for the sleight of hand trick.
478                                          * 65 is the ascii value of 'A'. We take this from
479                                          * the char we're looking at to get a number between
480                                          * 1 and 127. We then logic-or it to get the hashed
481                                          * position, dependent on wether its a channel or
482                                          * a user mode. This is a little stranger, but a lot
483                                          * faster, than using a map of pairs.
484                                          */
485                                         handler_id = (modechar - 65) | mask;
486
487                                         if (modehandlers[handler_id])
488                                         {
489                                                 bool abort = false;
490
491                                                 if (modehandlers[handler_id]->GetModeType() == type)
492                                                 {
493                                                         int MOD_RESULT = 0;
494
495                                                         if (modehandlers[handler_id]->GetNumParams(adding))
496                                                         {
497                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
498                                                                 if (parameter_counter < pcnt)
499                                                                 {
500                                                                         parameter = parameters[parameter_counter++];
501
502                                                                         /* Yerk, invalid! */
503                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
504                                                                                 parameter.clear();
505                                                                 }
506                                                                 else
507                                                                 {
508                                                                         /* No parameter, continue to the next mode */
509                                                                         continue;
510                                                                 }
511
512                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
513                                                         }
514                                                         else
515                                                         {
516                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
517                                                         }
518
519                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
520                                                                 continue;
521
522                                                         if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
523                                                         {
524                                                                 /* Check access to this mode character */
525                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
526                                                                 {
527                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
528                                                                         ModeHandler* prefixmode = FindPrefix(needed);
529
530                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
531                                                                          * cannot be found, they probably dont have the right module loaded to implement
532                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
533                                                                          * Revert to checking against the minimum core prefix, '%'.
534                                                                          */
535                                                                         if (needed && !prefixmode)
536                                                                                 prefixmode = FindPrefix('%');
537                                                 
538                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
539                                                                         /* Compare our rank on the channel against the rank of the required prefix,
540                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
541                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
542                                                                          * first, so we don't need to iterate, we just look up the first instead.
543                                                                          */
544                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
545                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
546                                                                         ModeHandler* ourmode = FindPrefix(ml);
547                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
548                                                                         {
549                                                                                 /* Bog off */
550                                                                                 user->WriteNumeric(482, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
551                                                                                                 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
552                                                                                 continue;
553                                                                         }
554                                                                 }
555                                                         }
556
557                                                         bool had_parameter = !parameter.empty();
558                                                                 
559                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
560                                                         {
561                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
562                                                                 {
563                                                                         abort = true;
564                                                                         break;
565                                                                 }
566                                                                 /* A module whacked the parameter completely, and there was one. abort. */
567                                                                 if ((had_parameter) && (parameter.empty()))
568                                                                 {
569                                                                         abort = true;
570                                                                         break;
571                                                                 }
572                                                         }
573
574                                                         if (abort)
575                                                                 continue;
576
577                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
578                                                          * eat any parameter that  came with the mode, and continue to next
579                                                          */
580                                                         if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
581                                                         {
582                                                                 if (IS_OPER(user))
583                                                                 {
584                                                                         user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to %sset %s mode %c",
585                                                                                         user->nick,
586                                                                                         user->oper,
587                                                                                         adding ? "" : "un",
588                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
589                                                                                         modehandlers[handler_id]->GetModeChar());
590                                                                 }
591                                                                 else
592                                                                 {
593                                                                         user->WriteNumeric(481, "%s :Permission Denied - Only operators may %sset %s mode %c",
594                                                                                         user->nick,
595                                                                                         adding ? "" : "un",
596                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
597                                                                                         modehandlers[handler_id]->GetModeChar());
598                                                                 }
599                                                                 continue;
600                                                         }
601
602                                                         /* Call the handler for the mode */
603                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
604
605                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
606                                                         {
607                                                                 /* The handler nuked the parameter and they are supposed to have one.
608                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
609                                                                  * so we bail to the next mode character.
610                                                                  */
611                                                                 continue;
612                                                         }
613
614                                                         if (ma == MODEACTION_ALLOW)
615                                                         {
616                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
617                                                                 if (state_change)
618                                                                 {
619                                                                         if (adding != last_successful_state_change)
620                                                                                 output_sequence.append(adding ? "+" : "-");
621                                                                         last_successful_state_change = adding;
622                                                                 }
623                                                                 
624                                                                 /* Add the mode letter */
625                                                                 output_sequence.push_back(modechar);
626
627                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
628
629                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
630                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
631                                                                 {
632                                                                         parameter_list << " " << parameter;
633                                                                         parameter_count++;
634                                                                         /* Does this mode have a prefix? */
635                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
636                                                                         {
637                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
638                                                                                 if (user_to_prefix)
639                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
640                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
641                                                                         }
642                                                                 }
643
644                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
645                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
646                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
647
648                                                                 /* Reset the state change flag */
649                                                                 state_change = false;
650
651                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
652                                                                                 || (parameter_count > MAXMODES))
653                                                                 {
654                                                                         /* We cant have a mode sequence this long */
655                                                                         letter = mode_sequence.end() - 1;
656                                                                         continue;
657                                                                 }
658                                                         }
659                                                 }
660                                         }
661                                         else
662                                         {
663                                                 /* No mode handler? Unknown mode character then. */
664                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
665                                         }
666                                 break;
667                         }
668                 }
669
670                 /* Was there at least one valid mode in the sequence? */
671                 if (!output_sequence.empty())
672                 {
673                         if (servermode)
674                         {
675                                 if (type == MODETYPE_CHANNEL)
676                                 {
677                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
678                                         this->LastParse = targetchannel->name;
679                                 }
680                                 else
681                                 {
682                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
683                                         this->LastParse = targetuser->nick;
684                                 }
685                         }
686                         else
687                         {
688                                 if (type == MODETYPE_CHANNEL)
689                                 {
690                                         targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
691                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
692                                         this->LastParse = targetchannel->name;
693                                 }
694                                 else
695                                 {
696                                         user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
697                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
698                                         this->LastParse = targetuser->nick;
699                                 }
700                         }
701
702                         LastParse.append(" ");
703                         LastParse.append(output_sequence);
704                         LastParse.append(parameter_list.str());
705                 }
706         }
707 }
708
709 const std::string& ModeParser::GetLastParse()
710 {
711         return LastParse;
712 }
713
714 void ModeParser::CleanMask(std::string &mask)
715 {
716         std::string::size_type pos_of_pling = mask.find_first_of('!');
717         std::string::size_type pos_of_at = mask.find_first_of('@');
718         std::string::size_type pos_of_dot = mask.find_first_of('.');
719         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
720
721         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
722         {
723                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
724                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
725                 {
726                         /* It has no '.' in it, it must be a nick. */
727                         mask.append("!*@*");
728                 }
729                 else
730                 {
731                         /* Got a dot in it? Has to be a host */
732                         mask = "*!*@" + mask;
733                 }
734         }
735         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
736         {
737                 /* Has an @ but no !, its a user@host */
738                  mask = "*!" + mask;
739         }
740         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
741         {
742                 /* Has a ! but no @, it must be a nick!ident */
743                 mask.append("@*");
744         }
745 }
746
747 bool ModeParser::AddMode(ModeHandler* mh)
748 {
749         unsigned char mask = 0;
750         unsigned char pos = 0;
751
752         /* Yes, i know, this might let people declare modes like '_' or '^'.
753          * If they do that, thats their problem, and if i ever EVER see an
754          * official InspIRCd developer do that, i'll beat them with a paddle!
755          */
756         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
757                 return false;
758
759         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
760          * A mode prefix of ':' will fuck up both server to server, and client to server.
761          * A mode prefix of '#' will mess up /whois and /privmsg
762          */
763         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
764                 return false;
765
766         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
767         pos = (mh->GetModeChar()-65) | mask;
768
769         if (modehandlers[pos])
770                 return false;
771
772         modehandlers[pos] = mh;
773         return true;
774 }
775
776 bool ModeParser::DelMode(ModeHandler* mh)
777 {
778         unsigned char mask = 0;
779         unsigned char pos = 0;
780
781         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
782                 return false;
783
784         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
785         pos = (mh->GetModeChar()-65) | mask;
786
787         if (!modehandlers[pos])
788                 return false;
789
790         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
791          * To stack here we have to make the algorithm slower. Discuss.
792          */
793         switch (mh->GetModeType())
794         {
795                 case MODETYPE_USER:
796                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
797                         {
798                                 mh->RemoveMode(i->second);
799                         }
800                 break;
801                 case MODETYPE_CHANNEL:
802                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
803                         {
804                                 mh->RemoveMode(i->second);
805                         }
806                 break;
807         }
808
809         modehandlers[pos] = NULL;
810
811         return true;
812 }
813
814 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
815 {
816         unsigned char mask = 0;
817         unsigned char pos = 0;
818
819         if ((modeletter < 'A') || (modeletter > 'z'))
820                 return NULL;
821
822         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
823         pos = (modeletter-65) | mask;
824
825         return modehandlers[pos];
826 }
827
828 std::string ModeParser::UserModeList()
829 {
830         char modestr[256];
831         int pointer = 0;
832
833         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
834         {
835                 unsigned char pos = (mode-65) | MASK_USER;
836
837                 if (modehandlers[pos])
838                         modestr[pointer++] = mode;
839         }
840         modestr[pointer++] = 0;
841         return modestr;
842 }
843
844 std::string ModeParser::ChannelModeList()
845 {
846         char modestr[256];
847         int pointer = 0;
848
849         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
850         {
851                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
852                         continue;
853
854                 unsigned char pos = (mode-65) | MASK_CHANNEL;
855
856                 if (modehandlers[pos])
857                         modestr[pointer++] = mode;
858         }
859         modestr[pointer++] = 0;
860         return modestr;
861 }
862
863 std::string ModeParser::ParaModeList()
864 {
865         char modestr[256];
866         int pointer = 0;
867
868         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
869         {
870                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
871                         continue;
872
873                 unsigned char pos = (mode-65) | MASK_CHANNEL;
874
875                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
876                         modestr[pointer++] = mode;
877         }
878         modestr[pointer++] = 0;
879         return modestr;
880 }
881
882 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
883 {
884         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
885         {
886                 unsigned char pos = (mode-65) | MASK_CHANNEL;
887
888                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
889                 {
890                         return modehandlers[pos];
891                 }
892         }
893         return NULL;
894 }
895
896 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
897 {
898         std::string types;
899         std::string pars;
900
901         if (!channel || !user)
902                 return "";
903
904         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
905         {
906                 unsigned char pos = (mode-65) | MASK_CHANNEL;
907                 ModeHandler* mh = modehandlers[pos];
908                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
909                 {
910                         ModePair ret;
911                         ret = mh->ModeSet(NULL, user, channel, user->nick);
912                         if ((ret.first) && (ret.second == user->nick))
913                         {
914                                 if (nick_suffix)
915                                 {
916                                         pars.append(" ");
917                                         pars.append(user->nick);
918                                 }
919                                 types.push_back(mh->GetModeChar());
920                         }
921                 }
922         }
923
924         if (nick_suffix)
925                 return types+pars;
926         else
927                 return types;
928 }
929
930 std::string ModeParser::ChanModes()
931 {
932         std::string type1;      /* Listmodes EXCEPT those with a prefix */
933         std::string type2;      /* Modes that take a param when adding or removing */
934         std::string type3;      /* Modes that only take a param when adding */
935         std::string type4;      /* Modes that dont take a param */
936
937         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
938         {
939                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
940                         continue;
941
942                 unsigned char pos = (mode-65) | MASK_CHANNEL;
943                  /* One parameter when adding */
944                 if (modehandlers[pos])
945                 {       
946                         if (modehandlers[pos]->GetNumParams(true))
947                         {
948                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
949                                 {
950                                         type1 += modehandlers[pos]->GetModeChar();
951                                 }
952                                 else
953                                 {
954                                         /* ... and one parameter when removing */
955                                         if (modehandlers[pos]->GetNumParams(false))
956                                         {
957                                                 /* But not a list mode */
958                                                 if (!modehandlers[pos]->GetPrefix())
959                                                 {
960                                                         type2 += modehandlers[pos]->GetModeChar();
961                                                 }
962                                         }
963                                         else
964                                         {
965                                                 /* No parameters when removing */
966                                                 type3 += modehandlers[pos]->GetModeChar();
967                                         }
968                                 }
969                         }
970                         else
971                         {
972                                 type4 += modehandlers[pos]->GetModeChar();
973                         }
974                 }
975                          
976         }
977
978         return type1 + "," + type2 + "," + type3 + "," + type4;
979 }
980
981 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
982 {       
983         return one.second > two.second;
984 }
985
986 std::string ModeParser::BuildPrefixes()
987 {
988         std::string mletters;
989         std::string mprefixes;
990         pfxcontainer pfx;
991         std::map<char,char> prefix_to_mode;
992
993         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
994         {
995                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
996                         continue;
997
998                 unsigned char pos = (mode-65) | MASK_CHANNEL;
999
1000                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1001                 {
1002                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1003                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1004                 }
1005         }
1006
1007         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1008
1009         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1010         {
1011                 mletters = mletters + n->first;
1012                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1013         }
1014
1015         return "(" + mprefixes + ")" + mletters;
1016 }
1017
1018 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1019 {
1020         unsigned char mask = 0;
1021         unsigned char pos = 0;
1022
1023         if (!mw)
1024                 return false;
1025
1026         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1027                 return false;
1028
1029         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1030         pos = (mw->GetModeChar()-65) | mask;
1031
1032         modewatchers[pos].push_back(mw);
1033
1034         return true;
1035 }
1036
1037 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1038 {
1039         unsigned char mask = 0;
1040         unsigned char pos = 0;
1041
1042         if (!mw)
1043                 return false;
1044
1045         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1046                 return false;
1047
1048         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1049         pos = (mw->GetModeChar()-65) | mask;
1050
1051         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1052
1053         if (a == modewatchers[pos].end())
1054         {
1055                 return false;
1056         }
1057
1058         modewatchers[pos].erase(a);
1059
1060         return true;
1061 }
1062
1063 /** This default implementation can remove simple user modes
1064  */
1065 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1066 {
1067         char moderemove[MAXBUF];
1068         const char* parameters[] = { user->nick, moderemove };
1069
1070         if (user->IsModeSet(this->GetModeChar()))
1071         {
1072                 if (stack)
1073                 {
1074                         stack->Push(this->GetModeChar());
1075                 }
1076                 else
1077                 {
1078                         sprintf(moderemove,"-%c",this->GetModeChar());
1079                         ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1080                 }
1081         }
1082 }
1083
1084 /** This default implementation can remove simple channel modes
1085  * (no parameters)
1086  */
1087 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1088 {
1089         char moderemove[MAXBUF];
1090         const char* parameters[] = { channel->name, moderemove };
1091
1092         if (channel->IsModeSet(this->GetModeChar()))
1093         {
1094                 if (stack)
1095                 {
1096                         stack->Push(this->GetModeChar());
1097                 }
1098                 else
1099                 {
1100                         sprintf(moderemove,"-%c",this->GetModeChar());
1101                         ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1102                 }
1103         }
1104 }
1105
1106 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1107 {
1108         ModeHandler* modes[] =
1109         {
1110                 new ModeChannelSecret(Instance),
1111                 new ModeChannelPrivate(Instance),
1112                 new ModeChannelModerated(Instance),
1113                 new ModeChannelTopicOps(Instance),
1114                 new ModeChannelNoExternal(Instance),
1115                 new ModeChannelInviteOnly(Instance),
1116                 new ModeChannelKey(Instance),
1117                 new ModeChannelLimit(Instance),
1118                 new ModeChannelBan(Instance),
1119                 new ModeChannelOp(Instance),
1120                 new ModeChannelHalfOp(Instance),
1121                 new ModeChannelVoice(Instance),
1122                 new ModeUserServerNotice(Instance),
1123                 new ModeUserWallops(Instance),
1124                 new ModeUserInvisible(Instance),
1125                 new ModeUserOperator(Instance),
1126                 new ModeUserServerNoticeMask(Instance),
1127                 NULL
1128         };
1129
1130         /* Clear mode list */
1131         memset(modehandlers, 0, sizeof(modehandlers));
1132         memset(modewatchers, 0, sizeof(modewatchers));
1133
1134         /* Last parse string */
1135         LastParse.clear();
1136
1137         /* Initialise the RFC mode letters */
1138         for (int index = 0; modes[index]; index++)
1139                 this->AddMode(modes[index]);
1140 }