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, 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)
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(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
160 return (ours < theirs);
163 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
167 SimpleUserModeHandler::~SimpleUserModeHandler()
171 SimpleChannelModeHandler::~SimpleChannelModeHandler()
175 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
179 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
183 if (!dest->IsModeSet(this->GetModeChar()))
185 dest->SetMode(this->GetModeChar(),true);
186 return MODEACTION_ALLOW;
191 if (dest->IsModeSet(this->GetModeChar()))
193 dest->SetMode(this->GetModeChar(),false);
194 return MODEACTION_ALLOW;
198 return MODEACTION_DENY;
202 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
206 if (!channel->IsModeSet(this->GetModeChar()))
208 channel->SetMode(this->GetModeChar(),true);
209 return MODEACTION_ALLOW;
214 if (channel->IsModeSet(this->GetModeChar()))
216 channel->SetMode(this->GetModeChar(),false);
217 return MODEACTION_ALLOW;
221 return MODEACTION_DENY;
224 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
228 ModeWatcher::~ModeWatcher()
232 char ModeWatcher::GetModeChar()
237 ModeType ModeWatcher::GetModeType()
242 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
247 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
251 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
254 if ((!user) || (!dest) || (!chan) || (!*dest))
258 d = ServerInstance->FindNick(dest);
261 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
267 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
272 UCListIter n = d->chans.find(chan);
273 if (n != d->chans.end())
275 if (n->second & MASK)
279 n->second = n->second | MASK;
283 n->first->AddOppedUser(d);
286 n->first->AddHalfoppedUser(d);
289 n->first->AddVoicedUser(d);
292 return d->nick.c_str();
297 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
302 UCListIter n = d->chans.find(chan);
303 if (n != d->chans.end())
305 if ((n->second & MASK) == 0)
313 n->first->DelOppedUser(d);
316 n->first->DelHalfoppedUser(d);
319 n->first->DelVoicedUser(d);
322 return d->nick.c_str();
327 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
331 /* Display channel's current mode string */
332 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
333 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
338 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
340 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
344 if (targetuser == user || user->HasPrivPermission("users/auspex"))
346 /* Display user's current mode string */
347 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
348 if (IS_OPER(targetuser))
349 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
354 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
360 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
361 std::string ¶meter, bool servermode, bool SkipACL)
363 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
364 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
366 ModeHandler *mh = FindMode(modechar, type);
367 int pcnt = mh->GetNumParams(adding);
370 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, modechar, parameter, adding, pcnt, servermode));
372 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
373 return MODEACTION_DENY;
375 if (chan && !SkipACL && (MOD_RESULT != ACR_ALLOW))
377 char needed = mh->GetNeededPrefix();
378 ModeHandler* prefixmode = FindPrefix(needed);
380 /* If the mode defined by the handler is not '\0', but the handler for it
381 * cannot be found, they probably dont have the right module loaded to implement
382 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
383 * Revert to checking against the minimum core prefix, '%'.
385 if (needed && !prefixmode)
387 needed = ServerInstance->Config->AllowHalfop ? '%' : '@';
388 prefixmode = FindPrefix(needed);
393 unsigned int neededrank = prefixmode->GetPrefixRank();
394 /* Compare our rank on the channel against the rank of the required prefix,
395 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
396 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
397 * first, so we don't need to iterate, we just look up the first instead.
399 std::string modestring = chan->GetAllPrefixChars(user);
400 char ml = (modestring.empty() ? '\0' : modestring[0]);
401 ModeHandler* ourmode = FindPrefix(ml);
402 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
405 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
406 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
407 return MODEACTION_DENY;
412 unsigned char handler_id = (modechar - 'A') | mask;
414 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
416 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type, servermode) == false)
417 return MODEACTION_DENY;
418 /* A module whacked the parameter completely, and there was one. abort. */
419 if (pcnt && parameter.empty())
420 return MODEACTION_DENY;
423 if (IS_LOCAL(user) && !IS_OPER(user))
425 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
426 if (disabled[modechar - 'A'])
428 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
429 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
430 return MODEACTION_DENY;
434 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
436 /* It's an oper only mode, and they don't have access to it. */
439 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
440 user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
444 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
445 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
447 return MODEACTION_DENY;
450 /* Call the handler for the mode */
451 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding, servermode);
453 if (pcnt && parameter.empty())
454 return MODEACTION_DENY;
456 if (ma != MODEACTION_ALLOW)
459 mh->ChangeCount(adding ? 1 : -1);
461 if (mh->GetPrefix() && chan)
463 User* user_to_prefix = ServerInstance->FindNick(parameter);
465 chan->SetPrefix(user_to_prefix, mh->GetPrefix(), mh->GetPrefixRank(), adding);
468 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
469 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type, servermode);
471 return MODEACTION_ALLOW;
474 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
476 std::string target = parameters[0];
477 Channel* targetchannel = ServerInstance->FindChan(target);
478 User* targetuser = ServerInstance->FindNick(target);
479 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
482 LastParseParams.clear();
483 LastParseTranslate.clear();
485 if (!targetchannel && !targetuser)
487 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
490 if (parameters.size() == 1)
492 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
496 std::string mode_sequence = parameters[1];
498 bool SkipAccessChecks = false;
500 if (servermode || !IS_LOCAL(user) || ServerInstance->ULine(user->server))
502 SkipAccessChecks = true;
504 else if (targetchannel)
506 /* Overall access control hook for mode change */
507 LastParse = mode_sequence;
509 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
511 if (MOD_RESULT == ACR_DENY)
513 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
517 if (user != targetuser)
519 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
525 std::string output_mode;
526 std::ostringstream output_parameters;
527 LastParseParams.push_back(output_mode);
528 LastParseTranslate.push_back(TR_TEXT);
531 char output_pm = '\0'; // current output state, '+' or '-'
532 unsigned int param_at = 2;
534 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
536 unsigned char modechar = *letter;
537 if (modechar == '+' || modechar == '-')
539 adding = (modechar == '+');
543 ModeHandler *mh = this->FindMode(modechar, type);
546 /* No mode handler? Unknown mode character then. */
547 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
551 std::string parameter = "";
552 int pcnt = mh->GetNumParams(adding);
553 if (pcnt && param_at == parameters.size())
555 /* No parameter, continue to the next mode */
556 mh->OnParameterMissing(user, targetuser, targetchannel);
561 parameter = parameters[param_at++];
562 /* Make sure the user isn't trying to slip in an invalid parameter */
563 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
567 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, servermode, SkipAccessChecks);
569 if (ma != MODEACTION_ALLOW)
572 char needed_pm = adding ? '+' : '-';
573 if (needed_pm != output_pm)
575 output_pm = needed_pm;
576 output_mode.append(1, output_pm);
578 output_mode.append(1, modechar);
582 output_parameters << " " << parameter;
583 LastParseParams.push_back(parameter);
584 LastParseTranslate.push_back(mh->GetTranslateType());
587 if ( (output_mode.length() + output_parameters.str().length() > 450)
588 || (output_mode.length() > 100)
589 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
591 /* mode sequence is getting too long */
596 LastParseParams[0] = output_mode;
598 if (!output_mode.empty())
600 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
601 LastParse.append(" ");
602 LastParse.append(output_mode);
603 LastParse.append(output_parameters.str());
605 if (!user && targetchannel)
606 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s", LastParse.c_str());
607 else if (!user && targetuser)
608 targetuser->WriteServ("MODE %s", LastParse.c_str());
609 else if (targetchannel)
611 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
612 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
616 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
617 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
620 else if (targetchannel && parameters.size() == 2)
622 /* Special case for displaying the list for listmodes,
623 * e.g. MODE #chan b, or MODE #chan +b without a parameter
625 this->DisplayListModes(user, targetchannel, mode_sequence);
629 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
633 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
635 unsigned char mletter = *letter;
639 /* Ensure the user doesnt request the same mode twice,
640 * so they cant flood themselves off out of idiocy.
642 if (sent[mletter] == seq)
647 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
649 if (!mh || !mh->IsListMode())
653 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, mletter, "", true, 0));
654 if (MOD_RESULT == ACR_DENY)
658 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
660 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
661 user->nick.c_str(), chan->name.c_str(), mletter);
665 /** See below for a description of what craq this is :D
667 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
669 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
671 std::string dummyparam;
673 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
677 mh->DisplayList(user, chan);
679 mh->DisplayEmptyList(user, chan);
683 const std::string& ModeParser::GetLastParse()
688 void ModeParser::CleanMask(std::string &mask)
690 std::string::size_type pos_of_pling = mask.find_first_of('!');
691 std::string::size_type pos_of_at = mask.find_first_of('@');
692 std::string::size_type pos_of_dot = mask.find_first_of('.');
693 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
695 if (mask.length() >= 2 && mask[1] == ':')
696 return; // if it's an extban, don't even try guess how it needs to be formed.
698 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
700 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
701 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
703 /* It has no '.' in it, it must be a nick. */
708 /* Got a dot in it? Has to be a host */
709 mask = "*!*@" + mask;
712 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
714 /* Has an @ but no !, its a user@host */
717 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
719 /* Has a ! but no @, it must be a nick!ident */
724 bool ModeParser::AddMode(ModeHandler* mh)
726 unsigned char mask = 0;
727 unsigned char pos = 0;
729 /* Yes, i know, this might let people declare modes like '_' or '^'.
730 * If they do that, thats their problem, and if i ever EVER see an
731 * official InspIRCd developer do that, i'll beat them with a paddle!
733 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
736 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
737 * A mode prefix of ':' will fuck up both server to server, and client to server.
738 * A mode prefix of '#' will mess up /whois and /privmsg
740 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
743 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
744 pos = (mh->GetModeChar()-65) | mask;
746 if (modehandlers[pos])
749 modehandlers[pos] = mh;
753 bool ModeParser::DelMode(ModeHandler* mh)
755 unsigned char mask = 0;
756 unsigned char pos = 0;
758 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
761 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
762 pos = (mh->GetModeChar()-65) | mask;
764 if (!modehandlers[pos])
767 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
768 * To stack here we have to make the algorithm slower. Discuss.
770 switch (mh->GetModeType())
773 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
775 mh->RemoveMode(i->second);
778 case MODETYPE_CHANNEL:
779 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
781 mh->RemoveMode(i->second);
786 modehandlers[pos] = NULL;
791 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
793 unsigned char mask = 0;
794 unsigned char pos = 0;
796 if ((modeletter < 'A') || (modeletter > 'z'))
799 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
800 pos = (modeletter-65) | mask;
802 return modehandlers[pos];
805 std::string ModeParser::UserModeList()
810 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
812 unsigned char pos = (mode-65) | MASK_USER;
814 if (modehandlers[pos])
815 modestr[pointer++] = mode;
817 modestr[pointer++] = 0;
821 std::string ModeParser::ChannelModeList()
826 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
828 unsigned char pos = (mode-65) | MASK_CHANNEL;
830 if (modehandlers[pos])
831 modestr[pointer++] = mode;
833 modestr[pointer++] = 0;
837 std::string ModeParser::ParaModeList()
842 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
844 unsigned char pos = (mode-65) | MASK_CHANNEL;
846 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
847 modestr[pointer++] = mode;
849 modestr[pointer++] = 0;
853 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
855 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
857 unsigned char pos = (mode-65) | MASK_CHANNEL;
859 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
861 return modehandlers[pos];
867 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
872 if (!channel || !user)
875 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
877 unsigned char pos = (mode-65) | MASK_CHANNEL;
878 ModeHandler* mh = modehandlers[pos];
879 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
882 ret = mh->ModeSet(NULL, user, channel, user->nick);
883 if ((ret.first) && (ret.second == user->nick))
888 pars.append(user->nick);
890 types.push_back(mh->GetModeChar());
901 std::string ModeParser::GiveModeList(ModeMasks m)
903 std::string type1; /* Listmodes EXCEPT those with a prefix */
904 std::string type2; /* Modes that take a param when adding or removing */
905 std::string type3; /* Modes that only take a param when adding */
906 std::string type4; /* Modes that dont take a param */
908 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
910 unsigned char pos = (mode-65) | m;
911 /* One parameter when adding */
912 if (modehandlers[pos])
914 if (modehandlers[pos]->GetNumParams(true))
916 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
918 type1 += modehandlers[pos]->GetModeChar();
922 /* ... and one parameter when removing */
923 if (modehandlers[pos]->GetNumParams(false))
925 /* But not a list mode */
926 if (!modehandlers[pos]->GetPrefix())
928 type2 += modehandlers[pos]->GetModeChar();
933 /* No parameters when removing */
934 type3 += modehandlers[pos]->GetModeChar();
940 type4 += modehandlers[pos]->GetModeChar();
945 return type1 + "," + type2 + "," + type3 + "," + type4;
948 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
950 return one.second > two.second;
953 std::string ModeParser::BuildPrefixes()
955 std::string mletters;
956 std::string mprefixes;
958 std::map<char,char> prefix_to_mode;
960 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
962 unsigned char pos = (mode-65) | MASK_CHANNEL;
964 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
966 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
967 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
971 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
973 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
975 mletters = mletters + n->first;
976 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
979 return "(" + mprefixes + ")" + mletters;
982 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
984 unsigned char mask = 0;
985 unsigned char pos = 0;
990 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
993 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
994 pos = (mw->GetModeChar()-65) | mask;
996 modewatchers[pos].push_back(mw);
1001 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1003 unsigned char mask = 0;
1004 unsigned char pos = 0;
1009 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1012 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1013 pos = (mw->GetModeChar()-65) | mask;
1015 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1017 if (a == modewatchers[pos].end())
1022 modewatchers[pos].erase(a);
1027 /** This default implementation can remove simple user modes
1029 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1031 char moderemove[MAXBUF];
1032 std::vector<std::string> parameters;
1034 if (user->IsModeSet(this->GetModeChar()))
1038 stack->Push(this->GetModeChar());
1042 sprintf(moderemove,"-%c",this->GetModeChar());
1043 parameters.push_back(user->nick);
1044 parameters.push_back(moderemove);
1045 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1050 /** This default implementation can remove simple channel modes
1053 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1055 char moderemove[MAXBUF];
1056 std::vector<std::string> parameters;
1058 if (channel->IsModeSet(this->GetModeChar()))
1062 stack->Push(this->GetModeChar());
1066 sprintf(moderemove,"-%c",this->GetModeChar());
1067 parameters.push_back(channel->name);
1068 parameters.push_back(moderemove);
1069 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1074 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1076 ModeHandler* modes[] =
1078 new ModeChannelSecret(Instance),
1079 new ModeChannelPrivate(Instance),
1080 new ModeChannelModerated(Instance),
1081 new ModeChannelTopicOps(Instance),
1082 new ModeChannelNoExternal(Instance),
1083 new ModeChannelInviteOnly(Instance),
1084 new ModeChannelKey(Instance),
1085 new ModeChannelLimit(Instance),
1086 new ModeChannelBan(Instance),
1087 new ModeChannelOp(Instance),
1088 new ModeChannelHalfOp(Instance),
1089 new ModeChannelVoice(Instance),
1090 new ModeUserWallops(Instance),
1091 new ModeUserInvisible(Instance),
1092 new ModeUserOperator(Instance),
1093 new ModeUserServerNoticeMask(Instance),
1097 /* Clear mode handler list */
1098 memset(modehandlers, 0, sizeof(modehandlers));
1100 /* Last parse string */
1103 /* Initialise the RFC mode letters */
1104 for (int index = 0; modes[index]; index++)
1105 this->AddMode(modes[index]);
1108 memset(&sent, 0, sizeof(sent));