1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
17 #include "inspstring.h"
20 #include "modes/cmode_s.h"
22 #include "modes/cmode_p.h"
24 #include "modes/cmode_b.h"
26 #include "modes/cmode_m.h"
27 /* +t (only (half) ops can change topic) */
28 #include "modes/cmode_t.h"
29 /* +n (no external messages) */
30 #include "modes/cmode_n.h"
31 /* +i (invite only) */
32 #include "modes/cmode_i.h"
33 /* +k (keyed channel) */
34 #include "modes/cmode_k.h"
35 /* +l (channel user limit) */
36 #include "modes/cmode_l.h"
38 #include "modes/cmode_o.h"
39 /* +h (channel halfop) */
40 #include "modes/cmode_h.h"
41 /* +v (channel voice) */
42 #include "modes/cmode_v.h"
43 /* +w (see wallops) */
44 #include "modes/umode_w.h"
46 #include "modes/umode_i.h"
48 #include "modes/umode_o.h"
49 /* +s (server notice masks) */
50 #include "modes/umode_s.h"
52 ModeHandler::ModeHandler(InspIRCd* Instance, Module* Creator, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
53 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), m_paramtype(translate), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired), creator(Creator)
57 ModeHandler::~ModeHandler()
61 bool ModeHandler::IsListMode()
66 char ModeHandler::GetNeededPrefix()
68 if (prefixneeded == '%' && !ServerInstance->Config->AllowHalfop)
73 void ModeHandler::SetNeededPrefix(char needsprefix)
75 prefixneeded = needsprefix;
78 unsigned int ModeHandler::GetPrefixRank()
83 unsigned int ModeHandler::GetCount()
88 void ModeHandler::ChangeCount(int modifier)
91 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
94 ModeType ModeHandler::GetModeType()
99 TranslateType ModeHandler::GetTranslateType()
104 bool ModeHandler::NeedsOper()
109 char ModeHandler::GetPrefix()
114 int ModeHandler::GetNumParams(bool adding)
116 return adding ? n_params_on : n_params_off;
119 char ModeHandler::GetModeChar()
124 std::string ModeHandler::GetUserParameter(User* user)
129 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
131 return MODEACTION_DENY;
134 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
138 return std::make_pair(dest->IsModeSet(this->mode), "");
142 return std::make_pair(channel->IsModeSet(this->mode), "");
146 void ModeHandler::DisplayList(User*, Channel*)
150 void ModeHandler::DisplayEmptyList(User*, Channel*)
154 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
158 bool ModeHandler::CheckTimeStamp(std::string& theirs, const std::string& ours, Channel*)
160 return (theirs < ours);
163 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
167 if (!dest->IsModeSet(this->GetModeChar()))
169 dest->SetMode(this->GetModeChar(),true);
170 return MODEACTION_ALLOW;
175 if (dest->IsModeSet(this->GetModeChar()))
177 dest->SetMode(this->GetModeChar(),false);
178 return MODEACTION_ALLOW;
182 return MODEACTION_DENY;
186 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
190 if (!channel->IsModeSet(this->GetModeChar()))
192 channel->SetMode(this->GetModeChar(),true);
193 return MODEACTION_ALLOW;
198 if (channel->IsModeSet(this->GetModeChar()))
200 channel->SetMode(this->GetModeChar(),false);
201 return MODEACTION_ALLOW;
205 return MODEACTION_DENY;
208 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
212 ModeWatcher::~ModeWatcher()
216 char ModeWatcher::GetModeChar()
221 ModeType ModeWatcher::GetModeType()
226 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
231 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
235 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
238 if ((!user) || (!dest) || (!chan) || (!*dest))
242 d = ServerInstance->FindNick(dest);
245 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
251 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
256 UCListIter n = d->chans.find(chan);
257 if (n != d->chans.end())
259 if (n->second & MASK)
263 n->second = n->second | MASK;
267 n->first->AddOppedUser(d);
270 n->first->AddHalfoppedUser(d);
273 n->first->AddVoicedUser(d);
276 return d->nick.c_str();
281 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
286 UCListIter n = d->chans.find(chan);
287 if (n != d->chans.end())
289 if ((n->second & MASK) == 0)
297 n->first->DelOppedUser(d);
300 n->first->DelHalfoppedUser(d);
303 n->first->DelVoicedUser(d);
306 return d->nick.c_str();
311 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
315 /* Display channel's current mode string */
316 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
317 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
322 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
324 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
328 if (targetuser == user || user->HasPrivPermission("users/auspex"))
330 /* Display user's current mode string */
331 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
332 if (IS_OPER(targetuser))
333 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
338 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
344 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
345 std::string ¶meter, bool SkipACL)
347 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
348 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
350 ModeHandler *mh = FindMode(modechar, type);
351 int pcnt = mh->GetNumParams(adding);
353 ModResult MOD_RESULT;
354 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
356 if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
357 return MODEACTION_DENY;
359 if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
361 char needed = mh->GetNeededPrefix();
362 ModeHandler* prefixmode = FindPrefix(needed);
364 /* If the mode defined by the handler is not '\0', but the handler for it
365 * cannot be found, they probably dont have the right module loaded to implement
366 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
367 * Revert to checking against the minimum core prefix, '%'.
369 if (needed && !prefixmode)
371 needed = ServerInstance->Config->AllowHalfop ? '%' : '@';
372 prefixmode = FindPrefix(needed);
377 unsigned int neededrank = prefixmode->GetPrefixRank();
378 /* Compare our rank on the channel against the rank of the required prefix,
379 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
380 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
381 * first, so we don't need to iterate, we just look up the first instead.
383 std::string modestring = chan->GetAllPrefixChars(user);
384 char ml = (modestring.empty() ? '\0' : modestring[0]);
385 ModeHandler* ourmode = FindPrefix(ml);
386 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
389 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
390 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
391 return MODEACTION_DENY;
396 unsigned char handler_id = (modechar - 'A') | mask;
398 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
400 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
401 return MODEACTION_DENY;
402 /* A module whacked the parameter completely, and there was one. abort. */
403 if (pcnt && parameter.empty())
404 return MODEACTION_DENY;
407 if (IS_LOCAL(user) && !IS_OPER(user))
409 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
410 if (disabled[modechar - 'A'])
412 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
413 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
414 return MODEACTION_DENY;
418 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
420 /* It's an oper only mode, and they don't have access to it. */
423 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
424 user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
428 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
429 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
431 return MODEACTION_DENY;
434 /* Call the handler for the mode */
435 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
437 if (pcnt && parameter.empty())
438 return MODEACTION_DENY;
440 if (ma != MODEACTION_ALLOW)
443 mh->ChangeCount(adding ? 1 : -1);
445 if (mh->GetPrefix() && chan)
447 User* user_to_prefix = ServerInstance->FindNick(parameter);
449 chan->SetPrefix(user_to_prefix, mh->GetPrefix(), mh->GetPrefixRank(), adding);
452 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
453 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
455 return MODEACTION_ALLOW;
458 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
460 std::string target = parameters[0];
461 Channel* targetchannel = ServerInstance->FindChan(target);
462 User* targetuser = ServerInstance->FindNick(target);
463 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
466 LastParseParams.clear();
467 LastParseTranslate.clear();
469 if (!targetchannel && !targetuser)
471 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
474 if (parameters.size() == 1)
476 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
480 std::string mode_sequence = parameters[1];
482 bool SkipAccessChecks = false;
484 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
486 SkipAccessChecks = true;
488 else if (targetchannel)
490 /* Overall access control hook for mode change */
491 LastParse = mode_sequence;
492 ModResult MOD_RESULT;
493 FIRST_MOD_RESULT(ServerInstance, OnAccessCheck, MOD_RESULT, (user, NULL, targetchannel, AC_GENERAL_MODE));
495 if (MOD_RESULT == MOD_RES_DENY)
497 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
501 if (user != targetuser)
503 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
509 std::string output_mode;
510 std::ostringstream output_parameters;
511 LastParseParams.push_back(output_mode);
512 LastParseTranslate.push_back(TR_TEXT);
515 char output_pm = '\0'; // current output state, '+' or '-'
516 unsigned int param_at = 2;
518 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
520 unsigned char modechar = *letter;
521 if (modechar == '+' || modechar == '-')
523 adding = (modechar == '+');
527 ModeHandler *mh = this->FindMode(modechar, type);
530 /* No mode handler? Unknown mode character then. */
531 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
535 std::string parameter = "";
536 int pcnt = mh->GetNumParams(adding);
537 if (pcnt && param_at == parameters.size())
539 /* No parameter, continue to the next mode */
540 mh->OnParameterMissing(user, targetuser, targetchannel);
545 parameter = parameters[param_at++];
546 /* Make sure the user isn't trying to slip in an invalid parameter */
547 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
549 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
551 std::string ours = targetchannel->GetModeParameter(modechar);
552 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
553 /* we won the mode merge, don't apply this mode */
558 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
560 if (ma != MODEACTION_ALLOW)
563 char needed_pm = adding ? '+' : '-';
564 if (needed_pm != output_pm)
566 output_pm = needed_pm;
567 output_mode.append(1, output_pm);
569 output_mode.append(1, modechar);
573 output_parameters << " " << parameter;
574 LastParseParams.push_back(parameter);
575 LastParseTranslate.push_back(mh->GetTranslateType());
578 if ( (output_mode.length() + output_parameters.str().length() > 450)
579 || (output_mode.length() > 100)
580 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
582 /* mode sequence is getting too long */
587 LastParseParams[0] = output_mode;
589 if (!output_mode.empty())
591 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
592 LastParse.append(" ");
593 LastParse.append(output_mode);
594 LastParse.append(output_parameters.str());
598 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
599 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
603 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
604 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
607 else if (targetchannel && parameters.size() == 2)
609 /* Special case for displaying the list for listmodes,
610 * e.g. MODE #chan b, or MODE #chan +b without a parameter
612 this->DisplayListModes(user, targetchannel, mode_sequence);
616 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
620 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
622 unsigned char mletter = *letter;
626 /* Ensure the user doesnt request the same mode twice,
627 * so they cant flood themselves off out of idiocy.
629 if (sent[mletter] == seq)
634 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
636 if (!mh || !mh->IsListMode())
639 ModResult MOD_RESULT;
640 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
641 if (MOD_RESULT == MOD_RES_DENY)
645 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
647 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
648 user->nick.c_str(), chan->name.c_str(), mletter);
652 /** See below for a description of what craq this is :D
654 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
656 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
658 std::string dummyparam;
660 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
664 mh->DisplayList(user, chan);
666 mh->DisplayEmptyList(user, chan);
670 const std::string& ModeParser::GetLastParse()
675 void ModeParser::CleanMask(std::string &mask)
677 std::string::size_type pos_of_pling = mask.find_first_of('!');
678 std::string::size_type pos_of_at = mask.find_first_of('@');
679 std::string::size_type pos_of_dot = mask.find_first_of('.');
680 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
682 if (mask.length() >= 2 && mask[1] == ':')
683 return; // if it's an extban, don't even try guess how it needs to be formed.
685 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
687 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
688 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
690 /* It has no '.' in it, it must be a nick. */
695 /* Got a dot in it? Has to be a host */
696 mask = "*!*@" + mask;
699 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
701 /* Has an @ but no !, its a user@host */
704 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
706 /* Has a ! but no @, it must be a nick!ident */
711 bool ModeParser::AddMode(ModeHandler* mh)
713 unsigned char mask = 0;
714 unsigned char pos = 0;
716 /* Yes, i know, this might let people declare modes like '_' or '^'.
717 * If they do that, thats their problem, and if i ever EVER see an
718 * official InspIRCd developer do that, i'll beat them with a paddle!
720 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
723 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
724 * A mode prefix of ':' will fuck up both server to server, and client to server.
725 * A mode prefix of '#' will mess up /whois and /privmsg
727 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
730 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
731 pos = (mh->GetModeChar()-65) | mask;
733 if (modehandlers[pos])
736 modehandlers[pos] = mh;
740 bool ModeParser::DelMode(ModeHandler* mh)
742 unsigned char mask = 0;
743 unsigned char pos = 0;
745 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
748 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
749 pos = (mh->GetModeChar()-65) | mask;
751 if (!modehandlers[pos])
754 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
755 * To stack here we have to make the algorithm slower. Discuss.
757 switch (mh->GetModeType())
760 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
762 mh->RemoveMode(i->second);
765 case MODETYPE_CHANNEL:
766 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
768 mh->RemoveMode(i->second);
773 modehandlers[pos] = NULL;
778 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
780 unsigned char mask = 0;
781 unsigned char pos = 0;
783 if ((modeletter < 'A') || (modeletter > 'z'))
786 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
787 pos = (modeletter-65) | mask;
789 return modehandlers[pos];
792 std::string ModeParser::UserModeList()
797 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
799 unsigned char pos = (mode-65) | MASK_USER;
801 if (modehandlers[pos])
802 modestr[pointer++] = mode;
804 modestr[pointer++] = 0;
808 std::string ModeParser::ChannelModeList()
813 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
815 unsigned char pos = (mode-65) | MASK_CHANNEL;
817 if (modehandlers[pos])
818 modestr[pointer++] = mode;
820 modestr[pointer++] = 0;
824 std::string ModeParser::ParaModeList()
829 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
831 unsigned char pos = (mode-65) | MASK_CHANNEL;
833 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
834 modestr[pointer++] = mode;
836 modestr[pointer++] = 0;
840 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
842 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
844 unsigned char pos = (mode-65) | MASK_CHANNEL;
846 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
848 return modehandlers[pos];
854 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
859 if (!channel || !user)
862 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
864 unsigned char pos = (mode-65) | MASK_CHANNEL;
865 ModeHandler* mh = modehandlers[pos];
866 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
869 ret = mh->ModeSet(NULL, user, channel, user->nick);
870 if ((ret.first) && (ret.second == user->nick))
875 pars.append(user->nick);
877 types.push_back(mh->GetModeChar());
888 std::string ModeParser::GiveModeList(ModeMasks m)
890 std::string type1; /* Listmodes EXCEPT those with a prefix */
891 std::string type2; /* Modes that take a param when adding or removing */
892 std::string type3; /* Modes that only take a param when adding */
893 std::string type4; /* Modes that dont take a param */
895 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
897 unsigned char pos = (mode-65) | m;
898 /* One parameter when adding */
899 if (modehandlers[pos])
901 if (modehandlers[pos]->GetNumParams(true))
903 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
905 type1 += modehandlers[pos]->GetModeChar();
909 /* ... and one parameter when removing */
910 if (modehandlers[pos]->GetNumParams(false))
912 /* But not a list mode */
913 if (!modehandlers[pos]->GetPrefix())
915 type2 += modehandlers[pos]->GetModeChar();
920 /* No parameters when removing */
921 type3 += modehandlers[pos]->GetModeChar();
927 type4 += modehandlers[pos]->GetModeChar();
932 return type1 + "," + type2 + "," + type3 + "," + type4;
935 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
937 return one.second > two.second;
940 std::string ModeParser::BuildPrefixes()
942 std::string mletters;
943 std::string mprefixes;
945 std::map<char,char> prefix_to_mode;
947 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
949 unsigned char pos = (mode-65) | MASK_CHANNEL;
951 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
953 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
954 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
958 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
960 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
962 mletters = mletters + n->first;
963 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
966 return "(" + mprefixes + ")" + mletters;
969 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
971 unsigned char mask = 0;
972 unsigned char pos = 0;
977 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
980 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
981 pos = (mw->GetModeChar()-65) | mask;
983 modewatchers[pos].push_back(mw);
988 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
990 unsigned char mask = 0;
991 unsigned char pos = 0;
996 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
999 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1000 pos = (mw->GetModeChar()-65) | mask;
1002 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1004 if (a == modewatchers[pos].end())
1009 modewatchers[pos].erase(a);
1014 /** This default implementation can remove simple user modes
1016 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1018 char moderemove[MAXBUF];
1019 std::vector<std::string> parameters;
1021 if (user->IsModeSet(this->GetModeChar()))
1025 stack->Push(this->GetModeChar());
1029 sprintf(moderemove,"-%c",this->GetModeChar());
1030 parameters.push_back(user->nick);
1031 parameters.push_back(moderemove);
1032 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
1037 /** This default implementation can remove simple channel modes
1040 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1042 char moderemove[MAXBUF];
1043 std::vector<std::string> parameters;
1045 if (channel->IsModeSet(this->GetModeChar()))
1049 stack->Push(this->GetModeChar());
1053 sprintf(moderemove,"-%c",this->GetModeChar());
1054 parameters.push_back(channel->name);
1055 parameters.push_back(moderemove);
1056 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1061 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1063 ModeHandler* modes[] =
1065 new ModeChannelSecret(Instance),
1066 new ModeChannelPrivate(Instance),
1067 new ModeChannelModerated(Instance),
1068 new ModeChannelTopicOps(Instance),
1070 new ModeChannelNoExternal(Instance),
1071 new ModeChannelInviteOnly(Instance),
1072 new ModeChannelKey(Instance),
1073 new ModeChannelLimit(Instance),
1075 new ModeChannelBan(Instance),
1076 new ModeChannelOp(Instance),
1077 new ModeChannelHalfOp(Instance),
1078 new ModeChannelVoice(Instance),
1080 new ModeUserWallops(Instance),
1081 new ModeUserInvisible(Instance),
1082 new ModeUserOperator(Instance),
1083 new ModeUserServerNoticeMask(Instance),
1084 #define BUILTIN_MODE_COUNT 16
1087 /* Clear mode handler list */
1088 memset(modehandlers, 0, sizeof(modehandlers));
1090 /* Last parse string */
1093 /* Initialise the RFC mode letters */
1094 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1095 this->AddMode(modes[index]);
1098 memset(&sent, 0, sizeof(sent));
1101 ModeParser::~ModeParser()
1104 for(int i=0; i < 256; i++)
1106 ModeHandler* mh = modehandlers[i];
1113 if (count != BUILTIN_MODE_COUNT)
1114 throw CoreException("Mode handler found non-core modes remaining at deallocation");