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, 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, bool servermode)
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, bool servermode)
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, bool)
231 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
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 servermode, 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);
354 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, modechar, parameter, adding, pcnt, servermode));
356 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
357 return MODEACTION_DENY;
359 if (chan && !SkipACL && (MOD_RESULT != ACR_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, servermode) == 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, servermode);
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, servermode);
455 return MODEACTION_ALLOW;
458 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode, 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 (servermode || !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;
493 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
495 if (MOD_RESULT == ACR_DENY)
497 SkipAccessChecks = (MOD_RESULT == ACR_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, servermode, 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());
596 if (!user && targetchannel)
597 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s", LastParse.c_str());
598 else if (!user && targetuser)
599 targetuser->WriteServ("MODE %s", LastParse.c_str());
600 else if (targetchannel)
602 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
603 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
607 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
608 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
611 else if (targetchannel && parameters.size() == 2)
613 /* Special case for displaying the list for listmodes,
614 * e.g. MODE #chan b, or MODE #chan +b without a parameter
616 this->DisplayListModes(user, targetchannel, mode_sequence);
620 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
624 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
626 unsigned char mletter = *letter;
630 /* Ensure the user doesnt request the same mode twice,
631 * so they cant flood themselves off out of idiocy.
633 if (sent[mletter] == seq)
638 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
640 if (!mh || !mh->IsListMode())
644 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, mletter, "", true, 0));
645 if (MOD_RESULT == ACR_DENY)
649 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
651 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
652 user->nick.c_str(), chan->name.c_str(), mletter);
656 /** See below for a description of what craq this is :D
658 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
660 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
662 std::string dummyparam;
664 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
668 mh->DisplayList(user, chan);
670 mh->DisplayEmptyList(user, chan);
674 const std::string& ModeParser::GetLastParse()
679 void ModeParser::CleanMask(std::string &mask)
681 std::string::size_type pos_of_pling = mask.find_first_of('!');
682 std::string::size_type pos_of_at = mask.find_first_of('@');
683 std::string::size_type pos_of_dot = mask.find_first_of('.');
684 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
686 if (mask.length() >= 2 && mask[1] == ':')
687 return; // if it's an extban, don't even try guess how it needs to be formed.
689 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
691 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
692 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
694 /* It has no '.' in it, it must be a nick. */
699 /* Got a dot in it? Has to be a host */
700 mask = "*!*@" + mask;
703 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
705 /* Has an @ but no !, its a user@host */
708 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
710 /* Has a ! but no @, it must be a nick!ident */
715 bool ModeParser::AddMode(ModeHandler* mh)
717 unsigned char mask = 0;
718 unsigned char pos = 0;
720 /* Yes, i know, this might let people declare modes like '_' or '^'.
721 * If they do that, thats their problem, and if i ever EVER see an
722 * official InspIRCd developer do that, i'll beat them with a paddle!
724 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
727 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
728 * A mode prefix of ':' will fuck up both server to server, and client to server.
729 * A mode prefix of '#' will mess up /whois and /privmsg
731 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
734 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
735 pos = (mh->GetModeChar()-65) | mask;
737 if (modehandlers[pos])
740 modehandlers[pos] = mh;
744 bool ModeParser::DelMode(ModeHandler* mh)
746 unsigned char mask = 0;
747 unsigned char pos = 0;
749 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
752 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
753 pos = (mh->GetModeChar()-65) | mask;
755 if (!modehandlers[pos])
758 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
759 * To stack here we have to make the algorithm slower. Discuss.
761 switch (mh->GetModeType())
764 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
766 mh->RemoveMode(i->second);
769 case MODETYPE_CHANNEL:
770 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
772 mh->RemoveMode(i->second);
777 modehandlers[pos] = NULL;
782 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
784 unsigned char mask = 0;
785 unsigned char pos = 0;
787 if ((modeletter < 'A') || (modeletter > 'z'))
790 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
791 pos = (modeletter-65) | mask;
793 return modehandlers[pos];
796 std::string ModeParser::UserModeList()
801 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
803 unsigned char pos = (mode-65) | MASK_USER;
805 if (modehandlers[pos])
806 modestr[pointer++] = mode;
808 modestr[pointer++] = 0;
812 std::string ModeParser::ChannelModeList()
817 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
819 unsigned char pos = (mode-65) | MASK_CHANNEL;
821 if (modehandlers[pos])
822 modestr[pointer++] = mode;
824 modestr[pointer++] = 0;
828 std::string ModeParser::ParaModeList()
833 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
835 unsigned char pos = (mode-65) | MASK_CHANNEL;
837 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
838 modestr[pointer++] = mode;
840 modestr[pointer++] = 0;
844 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
846 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
848 unsigned char pos = (mode-65) | MASK_CHANNEL;
850 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
852 return modehandlers[pos];
858 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
863 if (!channel || !user)
866 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
868 unsigned char pos = (mode-65) | MASK_CHANNEL;
869 ModeHandler* mh = modehandlers[pos];
870 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
873 ret = mh->ModeSet(NULL, user, channel, user->nick);
874 if ((ret.first) && (ret.second == user->nick))
879 pars.append(user->nick);
881 types.push_back(mh->GetModeChar());
892 std::string ModeParser::GiveModeList(ModeMasks m)
894 std::string type1; /* Listmodes EXCEPT those with a prefix */
895 std::string type2; /* Modes that take a param when adding or removing */
896 std::string type3; /* Modes that only take a param when adding */
897 std::string type4; /* Modes that dont take a param */
899 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
901 unsigned char pos = (mode-65) | m;
902 /* One parameter when adding */
903 if (modehandlers[pos])
905 if (modehandlers[pos]->GetNumParams(true))
907 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
909 type1 += modehandlers[pos]->GetModeChar();
913 /* ... and one parameter when removing */
914 if (modehandlers[pos]->GetNumParams(false))
916 /* But not a list mode */
917 if (!modehandlers[pos]->GetPrefix())
919 type2 += modehandlers[pos]->GetModeChar();
924 /* No parameters when removing */
925 type3 += modehandlers[pos]->GetModeChar();
931 type4 += modehandlers[pos]->GetModeChar();
936 return type1 + "," + type2 + "," + type3 + "," + type4;
939 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
941 return one.second > two.second;
944 std::string ModeParser::BuildPrefixes()
946 std::string mletters;
947 std::string mprefixes;
949 std::map<char,char> prefix_to_mode;
951 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
953 unsigned char pos = (mode-65) | MASK_CHANNEL;
955 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
957 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
958 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
962 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
964 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
966 mletters = mletters + n->first;
967 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
970 return "(" + mprefixes + ")" + mletters;
973 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
975 unsigned char mask = 0;
976 unsigned char pos = 0;
981 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
984 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
985 pos = (mw->GetModeChar()-65) | mask;
987 modewatchers[pos].push_back(mw);
992 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
994 unsigned char mask = 0;
995 unsigned char pos = 0;
1000 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1003 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1004 pos = (mw->GetModeChar()-65) | mask;
1006 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1008 if (a == modewatchers[pos].end())
1013 modewatchers[pos].erase(a);
1018 /** This default implementation can remove simple user modes
1020 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1022 char moderemove[MAXBUF];
1023 std::vector<std::string> parameters;
1025 if (user->IsModeSet(this->GetModeChar()))
1029 stack->Push(this->GetModeChar());
1033 sprintf(moderemove,"-%c",this->GetModeChar());
1034 parameters.push_back(user->nick);
1035 parameters.push_back(moderemove);
1036 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1041 /** This default implementation can remove simple channel modes
1044 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1046 char moderemove[MAXBUF];
1047 std::vector<std::string> parameters;
1049 if (channel->IsModeSet(this->GetModeChar()))
1053 stack->Push(this->GetModeChar());
1057 sprintf(moderemove,"-%c",this->GetModeChar());
1058 parameters.push_back(channel->name);
1059 parameters.push_back(moderemove);
1060 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1065 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1067 ModeHandler* modes[] =
1069 new ModeChannelSecret(Instance),
1070 new ModeChannelPrivate(Instance),
1071 new ModeChannelModerated(Instance),
1072 new ModeChannelTopicOps(Instance),
1074 new ModeChannelNoExternal(Instance),
1075 new ModeChannelInviteOnly(Instance),
1076 new ModeChannelKey(Instance),
1077 new ModeChannelLimit(Instance),
1079 new ModeChannelBan(Instance),
1080 new ModeChannelOp(Instance),
1081 new ModeChannelHalfOp(Instance),
1082 new ModeChannelVoice(Instance),
1084 new ModeUserWallops(Instance),
1085 new ModeUserInvisible(Instance),
1086 new ModeUserOperator(Instance),
1087 new ModeUserServerNoticeMask(Instance),
1088 #define BUILTIN_MODE_COUNT 16
1091 /* Clear mode handler list */
1092 memset(modehandlers, 0, sizeof(modehandlers));
1094 /* Last parse string */
1097 /* Initialise the RFC mode letters */
1098 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1099 this->AddMode(modes[index]);
1102 memset(&sent, 0, sizeof(sent));
1105 ModeParser::~ModeParser()
1108 for(int i=0; i < 256; i++)
1110 ModeHandler* mh = modehandlers[i];
1117 if (count != BUILTIN_MODE_COUNT)
1118 throw CoreException("Mode handler found non-core modes remaining at deallocation");