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