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 /* Call the handler for the mode */
343 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
345 if (pcnt && parameter.empty())
346 return MODEACTION_DENY;
348 if (ma != MODEACTION_ALLOW)
351 mh->ChangeCount(adding ? 1 : -1);
353 if (mh->GetPrefixRank() && chan)
355 User* user_to_prefix = ServerInstance->FindNick(parameter);
357 chan->SetPrefix(user_to_prefix, modechar, adding);
360 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
361 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
363 return MODEACTION_ALLOW;
366 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
368 std::string target = parameters[0];
369 Channel* targetchannel = ServerInstance->FindChan(target);
370 User* targetuser = ServerInstance->FindNick(target);
371 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
374 LastParseParams.clear();
375 LastParseTranslate.clear();
377 if (!targetchannel && !targetuser)
379 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
382 if (parameters.size() == 1)
384 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
388 std::string mode_sequence = parameters[1];
390 bool SkipAccessChecks = false;
392 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
394 SkipAccessChecks = true;
398 ModResult MOD_RESULT;
399 FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
400 if (MOD_RESULT == MOD_RES_DENY)
402 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
405 if (targetuser && !SkipAccessChecks && user != targetuser)
407 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
411 std::string output_mode;
412 std::ostringstream output_parameters;
413 LastParseParams.push_back(output_mode);
414 LastParseTranslate.push_back(TR_TEXT);
417 char output_pm = '\0'; // current output state, '+' or '-'
418 unsigned int param_at = 2;
420 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
422 unsigned char modechar = *letter;
423 if (modechar == '+' || modechar == '-')
425 adding = (modechar == '+');
429 ModeHandler *mh = this->FindMode(modechar, type);
432 /* No mode handler? Unknown mode character then. */
433 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
437 std::string parameter = "";
438 int pcnt = mh->GetNumParams(adding);
439 if (pcnt && param_at == parameters.size())
441 /* No parameter, continue to the next mode */
442 mh->OnParameterMissing(user, targetuser, targetchannel);
447 parameter = parameters[param_at++];
448 /* Make sure the user isn't trying to slip in an invalid parameter */
449 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
451 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
453 std::string ours = targetchannel->GetModeParameter(modechar);
454 if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
455 /* we won the mode merge, don't apply this mode */
460 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
462 if (ma != MODEACTION_ALLOW)
465 char needed_pm = adding ? '+' : '-';
466 if (needed_pm != output_pm)
468 output_pm = needed_pm;
469 output_mode.append(1, output_pm);
471 output_mode.append(1, modechar);
475 TranslateType tt = mh->GetTranslateType();
478 User* u = ServerInstance->FindNick(parameter);
482 output_parameters << " " << parameter;
483 LastParseParams.push_back(parameter);
484 LastParseTranslate.push_back(tt);
487 if ( (output_mode.length() + output_parameters.str().length() > 450)
488 || (output_mode.length() > 100)
489 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
491 /* mode sequence is getting too long */
496 LastParseParams[0] = output_mode;
498 if (!output_mode.empty())
500 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
501 LastParse.append(" ");
502 LastParse.append(output_mode);
503 LastParse.append(output_parameters.str());
507 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
508 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
512 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
513 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
516 else if (targetchannel && parameters.size() == 2)
518 /* Special case for displaying the list for listmodes,
519 * e.g. MODE #chan b, or MODE #chan +b without a parameter
521 this->DisplayListModes(user, targetchannel, mode_sequence);
525 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
529 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
531 unsigned char mletter = *letter;
535 /* Ensure the user doesnt request the same mode twice,
536 * so they cant flood themselves off out of idiocy.
538 if (sent[mletter] == seq)
543 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
545 if (!mh || !mh->IsListMode())
548 ModResult MOD_RESULT;
549 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
550 if (MOD_RESULT == MOD_RES_DENY)
554 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
556 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
557 user->nick.c_str(), chan->name.c_str(), mletter);
561 /** See below for a description of what craq this is :D
563 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
565 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
567 std::string dummyparam;
569 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
573 mh->DisplayList(user, chan);
575 mh->DisplayEmptyList(user, chan);
579 const std::string& ModeParser::GetLastParse()
584 void ModeParser::CleanMask(std::string &mask)
586 std::string::size_type pos_of_pling = mask.find_first_of('!');
587 std::string::size_type pos_of_at = mask.find_first_of('@');
588 std::string::size_type pos_of_dot = mask.find_first_of('.');
589 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
591 if (mask.length() >= 2 && mask[1] == ':')
592 return; // if it's an extban, don't even try guess how it needs to be formed.
594 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
596 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
597 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
599 /* It has no '.' in it, it must be a nick. */
604 /* Got a dot in it? Has to be a host */
605 mask = "*!*@" + mask;
608 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
610 /* Has an @ but no !, its a user@host */
613 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
615 /* Has a ! but no @, it must be a nick!ident */
620 bool ModeParser::AddMode(ModeHandler* mh)
622 unsigned char mask = 0;
623 unsigned char pos = 0;
625 /* Yes, i know, this might let people declare modes like '_' or '^'.
626 * If they do that, thats their problem, and if i ever EVER see an
627 * official InspIRCd developer do that, i'll beat them with a paddle!
629 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
632 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
633 * A mode prefix of ':' will fuck up both server to server, and client to server.
634 * A mode prefix of '#' will mess up /whois and /privmsg
636 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
639 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
640 pos = (mh->GetModeChar()-65) | mask;
642 if (modehandlers[pos])
645 modehandlers[pos] = mh;
649 bool ModeParser::DelMode(ModeHandler* mh)
651 unsigned char mask = 0;
652 unsigned char pos = 0;
654 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
657 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
658 pos = (mh->GetModeChar()-65) | mask;
660 if (!modehandlers[pos])
663 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
664 * To stack here we have to make the algorithm slower. Discuss.
666 switch (mh->GetModeType())
669 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
671 mh->RemoveMode(i->second);
674 case MODETYPE_CHANNEL:
675 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
677 mh->RemoveMode(i->second);
682 modehandlers[pos] = NULL;
687 void ModeParser::RemoveModes(Module* mod)
689 for(int i=0; i < 256; i++)
691 ModeHandler* mh = modehandlers[i];
692 if (mh && mh->creator == mod)
694 for(unsigned int j=0; j < modewatchers[i].size(); j++)
696 ModeWatcher* mw = modewatchers[i][j];
697 if (mw && mw->creator == mod)
703 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
705 unsigned char mask = 0;
706 unsigned char pos = 0;
708 if ((modeletter < 'A') || (modeletter > 'z'))
711 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
712 pos = (modeletter-65) | mask;
714 return modehandlers[pos];
717 std::string ModeParser::UserModeList()
722 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
724 unsigned char pos = (mode-65) | MASK_USER;
726 if (modehandlers[pos])
727 modestr[pointer++] = mode;
729 modestr[pointer++] = 0;
733 std::string ModeParser::ChannelModeList()
738 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
740 unsigned char pos = (mode-65) | MASK_CHANNEL;
742 if (modehandlers[pos])
743 modestr[pointer++] = mode;
745 modestr[pointer++] = 0;
749 std::string ModeParser::ParaModeList()
754 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
756 unsigned char pos = (mode-65) | MASK_CHANNEL;
758 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
759 modestr[pointer++] = mode;
761 modestr[pointer++] = 0;
765 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
767 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
769 unsigned char pos = (mode-65) | MASK_CHANNEL;
771 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
773 return modehandlers[pos];
779 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
784 if (!channel || !user)
787 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
789 unsigned char pos = (mode-65) | MASK_CHANNEL;
790 ModeHandler* mh = modehandlers[pos];
791 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
794 ret = mh->ModeSet(NULL, user, channel, user->nick);
795 if ((ret.first) && (ret.second == user->nick))
800 pars.append(user->nick);
802 types.push_back(mh->GetModeChar());
813 std::string ModeParser::GiveModeList(ModeMasks m)
815 std::string type1; /* Listmodes EXCEPT those with a prefix */
816 std::string type2; /* Modes that take a param when adding or removing */
817 std::string type3; /* Modes that only take a param when adding */
818 std::string type4; /* Modes that dont take a param */
820 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
822 unsigned char pos = (mode-65) | m;
823 /* One parameter when adding */
824 if (modehandlers[pos])
826 if (modehandlers[pos]->GetNumParams(true))
828 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
830 type1 += modehandlers[pos]->GetModeChar();
834 /* ... and one parameter when removing */
835 if (modehandlers[pos]->GetNumParams(false))
837 /* But not a list mode */
838 if (!modehandlers[pos]->GetPrefix())
840 type2 += modehandlers[pos]->GetModeChar();
845 /* No parameters when removing */
846 type3 += modehandlers[pos]->GetModeChar();
852 type4 += modehandlers[pos]->GetModeChar();
857 return type1 + "," + type2 + "," + type3 + "," + type4;
860 std::string ModeParser::BuildPrefixes()
862 std::string mletters;
863 std::string mprefixes;
864 std::map<int,std::pair<char,char> > prefixes;
866 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
868 unsigned char pos = (mode-65) | MASK_CHANNEL;
870 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
872 prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
873 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
877 for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
879 mletters = mletters + n->second.first;
880 mprefixes = mprefixes + n->second.second;
883 return "(" + mprefixes + ")" + mletters;
886 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
888 unsigned char mask = 0;
889 unsigned char pos = 0;
894 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
897 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
898 pos = (mw->GetModeChar()-65) | mask;
900 modewatchers[pos].push_back(mw);
905 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
907 unsigned char mask = 0;
908 unsigned char pos = 0;
913 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
916 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
917 pos = (mw->GetModeChar()-65) | mask;
919 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
921 if (a == modewatchers[pos].end())
926 modewatchers[pos].erase(a);
931 /** This default implementation can remove simple user modes
933 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
935 char moderemove[MAXBUF];
936 std::vector<std::string> parameters;
938 if (user->IsModeSet(this->GetModeChar()))
942 stack->Push(this->GetModeChar());
946 sprintf(moderemove,"-%c",this->GetModeChar());
947 parameters.push_back(user->nick);
948 parameters.push_back(moderemove);
949 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
954 /** This default implementation can remove simple channel modes
957 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
959 char moderemove[MAXBUF];
960 std::vector<std::string> parameters;
962 if (channel->IsModeSet(this->GetModeChar()))
966 stack->Push(this->GetModeChar());
970 sprintf(moderemove,"-%c",this->GetModeChar());
971 parameters.push_back(channel->name);
972 parameters.push_back(moderemove);
973 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
978 ModeParser::ModeParser()
980 ModeHandler* modes[] =
982 new ModeChannelSecret,
983 new ModeChannelPrivate,
984 new ModeChannelModerated,
985 new ModeChannelTopicOps,
987 new ModeChannelNoExternal,
988 new ModeChannelInviteOnly,
990 new ModeChannelLimit,
994 new ModeChannelHalfOp,
995 new ModeChannelVoice,
998 new ModeUserInvisible,
999 new ModeUserOperator,
1000 new ModeUserServerNoticeMask,
1001 #define BUILTIN_MODE_COUNT 16
1004 /* Clear mode handler list */
1005 memset(modehandlers, 0, sizeof(modehandlers));
1007 /* Last parse string */
1010 /* Initialise the RFC mode letters */
1011 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1012 this->AddMode(modes[index]);
1015 memset(&sent, 0, sizeof(sent));
1018 ModeParser::~ModeParser()
1021 for(int i=0; i < 256; i++)
1023 ModeHandler* mh = modehandlers[i];
1024 if (mh && mh->creator == NULL)
1030 if (count != BUILTIN_MODE_COUNT)
1031 throw CoreException("Mode handler found non-core modes remaining at deallocation");