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