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(Module* Creator, char modeletter, ParamSpec Params, ModeType type)
53 : m_paramtype(TR_TEXT), parameters_taken(Params), mode(modeletter), prefix(0), oper(false),
54 list(false), m_type(type), count(0), levelrequired(HALFOP_VALUE), creator(Creator)
58 ModeHandler::~ModeHandler()
62 bool ModeHandler::IsListMode()
67 unsigned int ModeHandler::GetPrefixRank()
72 unsigned int ModeHandler::GetCount()
77 void ModeHandler::ChangeCount(int modifier)
80 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
83 int ModeHandler::GetNumParams(bool adding)
85 switch (parameters_taken)
90 return adding ? 1 : 0;
97 char ModeHandler::GetModeChar()
102 std::string ModeHandler::GetUserParameter(User* user)
107 ModResult ModeHandler::AccessCheck(User*, Channel*, std::string &, bool)
109 return MOD_RES_PASSTHRU;
112 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
114 return MODEACTION_DENY;
117 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
121 return std::make_pair(dest->IsModeSet(this->mode), "");
125 return std::make_pair(channel->IsModeSet(this->mode), "");
129 void ModeHandler::DisplayList(User*, Channel*)
133 void ModeHandler::DisplayEmptyList(User*, Channel*)
137 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
141 bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*)
143 return (theirs < ours);
146 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
150 if (!dest->IsModeSet(this->GetModeChar()))
152 dest->SetMode(this->GetModeChar(),true);
153 return MODEACTION_ALLOW;
158 if (dest->IsModeSet(this->GetModeChar()))
160 dest->SetMode(this->GetModeChar(),false);
161 return MODEACTION_ALLOW;
165 return MODEACTION_DENY;
169 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
173 if (!channel->IsModeSet(this->GetModeChar()))
175 channel->SetMode(this->GetModeChar(),true);
176 return MODEACTION_ALLOW;
181 if (channel->IsModeSet(this->GetModeChar()))
183 channel->SetMode(this->GetModeChar(),false);
184 return MODEACTION_ALLOW;
188 return MODEACTION_DENY;
191 ModeWatcher::ModeWatcher(Module* Creator, char modeletter, ModeType type)
192 : mode(modeletter), m_type(type), creator(Creator)
196 ModeWatcher::~ModeWatcher()
200 char ModeWatcher::GetModeChar()
205 ModeType ModeWatcher::GetModeType()
210 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
215 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
219 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
222 if ((!user) || (!dest) || (!chan) || (!*dest))
226 d = ServerInstance->FindNick(dest);
229 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
235 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
239 /* Display channel's current mode string */
240 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
241 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
246 if (targetuser == user || user->HasPrivPermission("users/auspex"))
248 /* Display user's current mode string */
249 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
250 if (IS_OPER(targetuser))
251 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
256 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
262 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
263 std::string ¶meter, bool SkipACL)
265 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
266 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
268 ModeHandler *mh = FindMode(modechar, type);
269 int pcnt = mh->GetNumParams(adding);
271 ModResult MOD_RESULT;
272 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
274 if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
275 return MODEACTION_DENY;
277 if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
279 MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding);
281 if (MOD_RESULT == MOD_RES_DENY)
282 return MODEACTION_DENY;
283 if (MOD_RESULT == MOD_RES_PASSTHRU)
285 unsigned int neededrank = mh->GetLevelRequired();
286 /* Compare our rank on the channel against the rank of the required prefix,
287 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
288 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
289 * first, so we don't need to iterate, we just look up the first instead.
291 unsigned int ourrank = chan->GetPrefixValue(user);
292 if (ourrank < neededrank)
295 // TODO replace with a real search for the proper prefix
296 char needed = neededrank > HALFOP_VALUE ? '@' : '%';
297 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
298 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
299 return MODEACTION_DENY;
304 unsigned char handler_id = (modechar - 'A') | mask;
306 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
308 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
309 return MODEACTION_DENY;
310 /* A module whacked the parameter completely, and there was one. abort. */
311 if (pcnt && parameter.empty())
312 return MODEACTION_DENY;
315 if (IS_LOCAL(user) && !IS_OPER(user))
317 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
318 if (disabled[modechar - 'A'])
320 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
321 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
322 return MODEACTION_DENY;
326 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
328 /* It's an oper only mode, and they don't have access to it. */
331 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
332 user->nick.c_str(), irc::Spacify(user->oper.c_str()), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
336 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
337 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
339 return MODEACTION_DENY;
342 if (mh->GetTranslateType() == TR_NICK && !ServerInstance->FindNick(parameter))
344 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameter.c_str());
345 return MODEACTION_DENY;
348 /* Call the handler for the mode */
349 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
351 if (pcnt && parameter.empty())
352 return MODEACTION_DENY;
354 if (ma != MODEACTION_ALLOW)
357 mh->ChangeCount(adding ? 1 : -1);
359 if (mh->GetPrefixRank() && chan)
361 User* user_to_prefix = ServerInstance->FindNick(parameter);
363 chan->SetPrefix(user_to_prefix, modechar, adding);
366 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
367 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
369 return MODEACTION_ALLOW;
372 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
374 std::string target = parameters[0];
375 Channel* targetchannel = ServerInstance->FindChan(target);
376 User* targetuser = ServerInstance->FindNick(target);
377 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
380 LastParseParams.clear();
381 LastParseTranslate.clear();
383 if (!targetchannel && !targetuser)
385 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
388 if (parameters.size() == 1)
390 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
394 std::string mode_sequence = parameters[1];
396 bool SkipAccessChecks = false;
398 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
400 SkipAccessChecks = true;
404 ModResult MOD_RESULT;
405 FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
406 if (MOD_RESULT == MOD_RES_DENY)
408 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
411 if (targetuser && !SkipAccessChecks && user != targetuser)
413 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
417 std::string output_mode;
418 std::ostringstream output_parameters;
419 LastParseParams.push_back(output_mode);
420 LastParseTranslate.push_back(TR_TEXT);
423 char output_pm = '\0'; // current output state, '+' or '-'
424 unsigned int param_at = 2;
426 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
428 unsigned char modechar = *letter;
429 if (modechar == '+' || modechar == '-')
431 adding = (modechar == '+');
435 ModeHandler *mh = this->FindMode(modechar, type);
438 /* No mode handler? Unknown mode character then. */
439 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
443 std::string parameter = "";
444 int pcnt = mh->GetNumParams(adding);
445 if (pcnt && param_at == parameters.size())
447 /* No parameter, continue to the next mode */
448 mh->OnParameterMissing(user, targetuser, targetchannel);
453 parameter = parameters[param_at++];
454 /* Make sure the user isn't trying to slip in an invalid parameter */
455 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
457 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
459 std::string ours = targetchannel->GetModeParameter(modechar);
460 if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
461 /* we won the mode merge, don't apply this mode */
466 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
468 if (ma != MODEACTION_ALLOW)
471 char needed_pm = adding ? '+' : '-';
472 if (needed_pm != output_pm)
474 output_pm = needed_pm;
475 output_mode.append(1, output_pm);
477 output_mode.append(1, modechar);
481 TranslateType tt = mh->GetTranslateType();
484 User* u = ServerInstance->FindNick(parameter);
488 output_parameters << " " << parameter;
489 LastParseParams.push_back(parameter);
490 LastParseTranslate.push_back(tt);
493 if ( (output_mode.length() + output_parameters.str().length() > 450)
494 || (output_mode.length() > 100)
495 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
497 /* mode sequence is getting too long */
502 LastParseParams[0] = output_mode;
504 if (!output_mode.empty())
506 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
507 LastParse.append(" ");
508 LastParse.append(output_mode);
509 LastParse.append(output_parameters.str());
513 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
514 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
518 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
519 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
522 else if (targetchannel && parameters.size() == 2)
524 /* Special case for displaying the list for listmodes,
525 * e.g. MODE #chan b, or MODE #chan +b without a parameter
527 this->DisplayListModes(user, targetchannel, mode_sequence);
531 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
535 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
537 unsigned char mletter = *letter;
541 /* Ensure the user doesnt request the same mode twice,
542 * so they cant flood themselves off out of idiocy.
544 if (sent[mletter] == seq)
549 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
551 if (!mh || !mh->IsListMode())
554 ModResult MOD_RESULT;
555 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
556 if (MOD_RESULT == MOD_RES_DENY)
560 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
562 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
563 user->nick.c_str(), chan->name.c_str(), mletter);
567 /** See below for a description of what craq this is :D
569 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
571 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
573 std::string dummyparam;
575 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
579 mh->DisplayList(user, chan);
581 mh->DisplayEmptyList(user, chan);
585 const std::string& ModeParser::GetLastParse()
590 void ModeParser::CleanMask(std::string &mask)
592 std::string::size_type pos_of_pling = mask.find_first_of('!');
593 std::string::size_type pos_of_at = mask.find_first_of('@');
594 std::string::size_type pos_of_dot = mask.find_first_of('.');
595 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
597 if (mask.length() >= 2 && mask[1] == ':')
598 return; // if it's an extban, don't even try guess how it needs to be formed.
600 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
602 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
603 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
605 /* It has no '.' in it, it must be a nick. */
610 /* Got a dot in it? Has to be a host */
611 mask = "*!*@" + mask;
614 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
616 /* Has an @ but no !, its a user@host */
619 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
621 /* Has a ! but no @, it must be a nick!ident */
626 bool ModeParser::AddMode(ModeHandler* mh)
628 unsigned char mask = 0;
629 unsigned char pos = 0;
631 /* Yes, i know, this might let people declare modes like '_' or '^'.
632 * If they do that, thats their problem, and if i ever EVER see an
633 * official InspIRCd developer do that, i'll beat them with a paddle!
635 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
638 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
639 * A mode prefix of ':' will fuck up both server to server, and client to server.
640 * A mode prefix of '#' will mess up /whois and /privmsg
642 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
645 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
646 pos = (mh->GetModeChar()-65) | mask;
648 if (modehandlers[pos])
651 modehandlers[pos] = mh;
655 bool ModeParser::DelMode(ModeHandler* mh)
657 unsigned char mask = 0;
658 unsigned char pos = 0;
660 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
663 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
664 pos = (mh->GetModeChar()-65) | mask;
666 if (!modehandlers[pos])
669 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
670 * To stack here we have to make the algorithm slower. Discuss.
672 switch (mh->GetModeType())
675 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
677 mh->RemoveMode(i->second);
680 case MODETYPE_CHANNEL:
681 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
683 mh->RemoveMode(i->second);
688 modehandlers[pos] = NULL;
693 void ModeParser::RemoveModes(Module* mod)
695 for(int i=0; i < 256; i++)
697 ModeHandler* mh = modehandlers[i];
698 if (mh && mh->creator == mod)
700 for(unsigned int j=0; j < modewatchers[i].size(); j++)
702 ModeWatcher* mw = modewatchers[i][j];
703 if (mw && mw->creator == mod)
709 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
711 unsigned char mask = 0;
712 unsigned char pos = 0;
714 if ((modeletter < 'A') || (modeletter > 'z'))
717 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
718 pos = (modeletter-65) | mask;
720 return modehandlers[pos];
723 std::string ModeParser::UserModeList()
728 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
730 unsigned char pos = (mode-65) | MASK_USER;
732 if (modehandlers[pos])
733 modestr[pointer++] = mode;
735 modestr[pointer++] = 0;
739 std::string ModeParser::ChannelModeList()
744 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
746 unsigned char pos = (mode-65) | MASK_CHANNEL;
748 if (modehandlers[pos])
749 modestr[pointer++] = mode;
751 modestr[pointer++] = 0;
755 std::string ModeParser::ParaModeList()
760 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
762 unsigned char pos = (mode-65) | MASK_CHANNEL;
764 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
765 modestr[pointer++] = mode;
767 modestr[pointer++] = 0;
771 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
773 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
775 unsigned char pos = (mode-65) | MASK_CHANNEL;
777 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
779 return modehandlers[pos];
785 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
790 if (!channel || !user)
793 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
795 unsigned char pos = (mode-65) | MASK_CHANNEL;
796 ModeHandler* mh = modehandlers[pos];
797 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
800 ret = mh->ModeSet(NULL, user, channel, user->nick);
801 if ((ret.first) && (ret.second == user->nick))
806 pars.append(user->nick);
808 types.push_back(mh->GetModeChar());
819 std::string ModeParser::GiveModeList(ModeMasks m)
821 std::string type1; /* Listmodes EXCEPT those with a prefix */
822 std::string type2; /* Modes that take a param when adding or removing */
823 std::string type3; /* Modes that only take a param when adding */
824 std::string type4; /* Modes that dont take a param */
826 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
828 unsigned char pos = (mode-65) | m;
829 /* One parameter when adding */
830 if (modehandlers[pos])
832 if (modehandlers[pos]->GetNumParams(true))
834 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
836 type1 += modehandlers[pos]->GetModeChar();
840 /* ... and one parameter when removing */
841 if (modehandlers[pos]->GetNumParams(false))
843 /* But not a list mode */
844 if (!modehandlers[pos]->GetPrefix())
846 type2 += modehandlers[pos]->GetModeChar();
851 /* No parameters when removing */
852 type3 += modehandlers[pos]->GetModeChar();
858 type4 += modehandlers[pos]->GetModeChar();
863 return type1 + "," + type2 + "," + type3 + "," + type4;
866 std::string ModeParser::BuildPrefixes()
868 std::string mletters;
869 std::string mprefixes;
870 std::map<int,std::pair<char,char> > prefixes;
872 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
874 unsigned char pos = (mode-65) | MASK_CHANNEL;
876 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
878 prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
879 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
883 for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
885 mletters = mletters + n->second.first;
886 mprefixes = mprefixes + n->second.second;
889 return "(" + mprefixes + ")" + mletters;
892 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
894 unsigned char mask = 0;
895 unsigned char pos = 0;
900 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
903 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
904 pos = (mw->GetModeChar()-65) | mask;
906 modewatchers[pos].push_back(mw);
911 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
913 unsigned char mask = 0;
914 unsigned char pos = 0;
919 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
922 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
923 pos = (mw->GetModeChar()-65) | mask;
925 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
927 if (a == modewatchers[pos].end())
932 modewatchers[pos].erase(a);
937 /** This default implementation can remove simple user modes
939 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
941 char moderemove[MAXBUF];
942 std::vector<std::string> parameters;
944 if (user->IsModeSet(this->GetModeChar()))
948 stack->Push(this->GetModeChar());
952 sprintf(moderemove,"-%c",this->GetModeChar());
953 parameters.push_back(user->nick);
954 parameters.push_back(moderemove);
955 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
960 /** This default implementation can remove simple channel modes
963 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
965 char moderemove[MAXBUF];
966 std::vector<std::string> parameters;
968 if (channel->IsModeSet(this->GetModeChar()))
972 stack->Push(this->GetModeChar());
976 sprintf(moderemove,"-%c",this->GetModeChar());
977 parameters.push_back(channel->name);
978 parameters.push_back(moderemove);
979 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
984 ModeParser::ModeParser()
986 ModeHandler* modes[] =
988 new ModeChannelSecret,
989 new ModeChannelPrivate,
990 new ModeChannelModerated,
991 new ModeChannelTopicOps,
993 new ModeChannelNoExternal,
994 new ModeChannelInviteOnly,
996 new ModeChannelLimit,
1000 new ModeChannelHalfOp,
1001 new ModeChannelVoice,
1003 new ModeUserWallops,
1004 new ModeUserInvisible,
1005 new ModeUserOperator,
1006 new ModeUserServerNoticeMask,
1007 #define BUILTIN_MODE_COUNT 16
1010 /* Clear mode handler list */
1011 memset(modehandlers, 0, sizeof(modehandlers));
1013 /* Last parse string */
1016 /* Initialise the RFC mode letters */
1017 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1018 this->AddMode(modes[index]);
1021 memset(&sent, 0, sizeof(sent));
1024 ModeParser::~ModeParser()
1027 for(int i=0; i < 256; i++)
1029 ModeHandler* mh = modehandlers[i];
1030 if (mh && mh->creator == NULL)
1036 if (count != BUILTIN_MODE_COUNT)
1037 throw CoreException("Mode handler found non-core modes remaining at deallocation");