1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
17 #include "inspstring.h"
20 #include "modes/cmode_s.h"
22 #include "modes/cmode_p.h"
24 #include "modes/cmode_b.h"
26 #include "modes/cmode_m.h"
27 /* +t (only (half) ops can change topic) */
28 #include "modes/cmode_t.h"
29 /* +n (no external messages) */
30 #include "modes/cmode_n.h"
31 /* +i (invite only) */
32 #include "modes/cmode_i.h"
33 /* +k (keyed channel) */
34 #include "modes/cmode_k.h"
35 /* +l (channel user limit) */
36 #include "modes/cmode_l.h"
38 #include "modes/cmode_o.h"
39 /* +h (channel halfop) */
40 #include "modes/cmode_h.h"
41 /* +v (channel voice) */
42 #include "modes/cmode_v.h"
43 /* +w (see wallops) */
44 #include "modes/umode_w.h"
46 #include "modes/umode_i.h"
48 #include "modes/umode_o.h"
49 /* +s (server notice masks) */
50 #include "modes/umode_s.h"
52 ModeHandler::ModeHandler(InspIRCd* Instance, Module* Creator, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
53 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), m_paramtype(translate), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired), creator(Creator)
57 ModeHandler::~ModeHandler()
61 bool ModeHandler::IsListMode()
66 char ModeHandler::GetNeededPrefix()
68 if (prefixneeded == '%' && !ServerInstance->Config->AllowHalfop)
73 void ModeHandler::SetNeededPrefix(char needsprefix)
75 prefixneeded = needsprefix;
78 unsigned int ModeHandler::GetPrefixRank()
83 unsigned int ModeHandler::GetCount()
88 void ModeHandler::ChangeCount(int modifier)
91 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
94 ModeType ModeHandler::GetModeType()
99 TranslateType ModeHandler::GetTranslateType()
104 bool ModeHandler::NeedsOper()
109 char ModeHandler::GetPrefix()
114 int ModeHandler::GetNumParams(bool adding)
116 return adding ? n_params_on : n_params_off;
119 char ModeHandler::GetModeChar()
124 std::string ModeHandler::GetUserParameter(User* user)
129 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
131 return MODEACTION_DENY;
134 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
138 return std::make_pair(dest->IsModeSet(this->mode), "");
142 return std::make_pair(channel->IsModeSet(this->mode), "");
146 void ModeHandler::DisplayList(User*, Channel*)
150 void ModeHandler::DisplayEmptyList(User*, Channel*)
154 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
158 bool ModeHandler::CheckTimeStamp(std::string& theirs, const std::string& ours, Channel*)
160 return (theirs < ours);
163 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
167 if (!dest->IsModeSet(this->GetModeChar()))
169 dest->SetMode(this->GetModeChar(),true);
170 return MODEACTION_ALLOW;
175 if (dest->IsModeSet(this->GetModeChar()))
177 dest->SetMode(this->GetModeChar(),false);
178 return MODEACTION_ALLOW;
182 return MODEACTION_DENY;
186 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
190 if (!channel->IsModeSet(this->GetModeChar()))
192 channel->SetMode(this->GetModeChar(),true);
193 return MODEACTION_ALLOW;
198 if (channel->IsModeSet(this->GetModeChar()))
200 channel->SetMode(this->GetModeChar(),false);
201 return MODEACTION_ALLOW;
205 return MODEACTION_DENY;
208 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
212 ModeWatcher::~ModeWatcher()
216 char ModeWatcher::GetModeChar()
221 ModeType ModeWatcher::GetModeType()
226 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
231 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
235 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
238 if ((!user) || (!dest) || (!chan) || (!*dest))
242 d = ServerInstance->FindNick(dest);
245 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
251 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
256 UCListIter n = d->chans.find(chan);
257 if (n != d->chans.end())
259 if (n->second & MASK)
263 n->second = n->second | MASK;
267 n->first->AddOppedUser(d);
270 n->first->AddHalfoppedUser(d);
273 n->first->AddVoicedUser(d);
276 return d->nick.c_str();
281 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
286 UCListIter n = d->chans.find(chan);
287 if (n != d->chans.end())
289 if ((n->second & MASK) == 0)
297 n->first->DelOppedUser(d);
300 n->first->DelHalfoppedUser(d);
303 n->first->DelVoicedUser(d);
306 return d->nick.c_str();
311 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
315 /* Display channel's current mode string */
316 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
317 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
322 if (targetuser == user || user->HasPrivPermission("users/auspex"))
324 /* Display user's current mode string */
325 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
326 if (IS_OPER(targetuser))
327 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
332 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
338 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
339 std::string ¶meter, bool SkipACL)
341 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
342 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
344 ModeHandler *mh = FindMode(modechar, type);
345 int pcnt = mh->GetNumParams(adding);
347 ModResult MOD_RESULT;
348 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
350 if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
351 return MODEACTION_DENY;
353 if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
355 char needed = mh->GetNeededPrefix();
356 ModeHandler* prefixmode = FindPrefix(needed);
358 /* If the mode defined by the handler is not '\0', but the handler for it
359 * cannot be found, they probably dont have the right module loaded to implement
360 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
361 * Revert to checking against the minimum core prefix, '%'.
363 if (needed && !prefixmode)
365 needed = ServerInstance->Config->AllowHalfop ? '%' : '@';
366 prefixmode = FindPrefix(needed);
371 unsigned int neededrank = prefixmode->GetPrefixRank();
372 /* Compare our rank on the channel against the rank of the required prefix,
373 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
374 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
375 * first, so we don't need to iterate, we just look up the first instead.
377 std::string modestring = chan->GetAllPrefixChars(user);
378 char ml = (modestring.empty() ? '\0' : modestring[0]);
379 ModeHandler* ourmode = FindPrefix(ml);
380 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
383 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
384 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
385 return MODEACTION_DENY;
390 unsigned char handler_id = (modechar - 'A') | mask;
392 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
394 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
395 return MODEACTION_DENY;
396 /* A module whacked the parameter completely, and there was one. abort. */
397 if (pcnt && parameter.empty())
398 return MODEACTION_DENY;
401 if (IS_LOCAL(user) && !IS_OPER(user))
403 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
404 if (disabled[modechar - 'A'])
406 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
407 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
408 return MODEACTION_DENY;
412 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
414 /* It's an oper only mode, and they don't have access to it. */
417 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
418 user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
422 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
423 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
425 return MODEACTION_DENY;
428 /* Call the handler for the mode */
429 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
431 if (pcnt && parameter.empty())
432 return MODEACTION_DENY;
434 if (ma != MODEACTION_ALLOW)
437 mh->ChangeCount(adding ? 1 : -1);
439 if (mh->GetPrefix() && chan)
441 User* user_to_prefix = ServerInstance->FindNick(parameter);
443 chan->SetPrefix(user_to_prefix, mh->GetPrefix(), mh->GetPrefixRank(), adding);
446 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
447 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
449 return MODEACTION_ALLOW;
452 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
454 std::string target = parameters[0];
455 Channel* targetchannel = ServerInstance->FindChan(target);
456 User* targetuser = ServerInstance->FindNick(target);
457 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
460 LastParseParams.clear();
461 LastParseTranslate.clear();
463 if (!targetchannel && !targetuser)
465 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
468 if (parameters.size() == 1)
470 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
474 std::string mode_sequence = parameters[1];
476 bool SkipAccessChecks = false;
478 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
480 SkipAccessChecks = true;
484 /* Overall access control hook for mode change */
485 int hook = targetchannel ? AC_GENERAL_MODE : AC_GENERAL_UMODE;
487 LastParse = mode_sequence;
488 ModResult MOD_RESULT;
489 FIRST_MOD_RESULT(ServerInstance, OnAccessCheck, MOD_RESULT, (user, targetuser, targetchannel, hook));
491 if (MOD_RESULT == MOD_RES_DENY)
493 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
496 if (targetuser && !SkipAccessChecks && user != targetuser)
498 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
502 std::string output_mode;
503 std::ostringstream output_parameters;
504 LastParseParams.push_back(output_mode);
505 LastParseTranslate.push_back(TR_TEXT);
508 char output_pm = '\0'; // current output state, '+' or '-'
509 unsigned int param_at = 2;
511 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
513 unsigned char modechar = *letter;
514 if (modechar == '+' || modechar == '-')
516 adding = (modechar == '+');
520 ModeHandler *mh = this->FindMode(modechar, type);
523 /* No mode handler? Unknown mode character then. */
524 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
528 std::string parameter = "";
529 int pcnt = mh->GetNumParams(adding);
530 if (pcnt && param_at == parameters.size())
532 /* No parameter, continue to the next mode */
533 mh->OnParameterMissing(user, targetuser, targetchannel);
538 parameter = parameters[param_at++];
539 /* Make sure the user isn't trying to slip in an invalid parameter */
540 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
542 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
544 std::string ours = targetchannel->GetModeParameter(modechar);
545 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
546 /* we won the mode merge, don't apply this mode */
551 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
553 if (ma != MODEACTION_ALLOW)
556 char needed_pm = adding ? '+' : '-';
557 if (needed_pm != output_pm)
559 output_pm = needed_pm;
560 output_mode.append(1, output_pm);
562 output_mode.append(1, modechar);
566 output_parameters << " " << parameter;
567 LastParseParams.push_back(parameter);
568 LastParseTranslate.push_back(mh->GetTranslateType());
571 if ( (output_mode.length() + output_parameters.str().length() > 450)
572 || (output_mode.length() > 100)
573 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
575 /* mode sequence is getting too long */
580 LastParseParams[0] = output_mode;
582 if (!output_mode.empty())
584 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
585 LastParse.append(" ");
586 LastParse.append(output_mode);
587 LastParse.append(output_parameters.str());
591 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
592 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
596 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
597 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
600 else if (targetchannel && parameters.size() == 2)
602 /* Special case for displaying the list for listmodes,
603 * e.g. MODE #chan b, or MODE #chan +b without a parameter
605 this->DisplayListModes(user, targetchannel, mode_sequence);
609 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
613 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
615 unsigned char mletter = *letter;
619 /* Ensure the user doesnt request the same mode twice,
620 * so they cant flood themselves off out of idiocy.
622 if (sent[mletter] == seq)
627 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
629 if (!mh || !mh->IsListMode())
632 ModResult MOD_RESULT;
633 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
634 if (MOD_RESULT == MOD_RES_DENY)
638 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
640 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
641 user->nick.c_str(), chan->name.c_str(), mletter);
645 /** See below for a description of what craq this is :D
647 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
649 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
651 std::string dummyparam;
653 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
657 mh->DisplayList(user, chan);
659 mh->DisplayEmptyList(user, chan);
663 const std::string& ModeParser::GetLastParse()
668 void ModeParser::CleanMask(std::string &mask)
670 std::string::size_type pos_of_pling = mask.find_first_of('!');
671 std::string::size_type pos_of_at = mask.find_first_of('@');
672 std::string::size_type pos_of_dot = mask.find_first_of('.');
673 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
675 if (mask.length() >= 2 && mask[1] == ':')
676 return; // if it's an extban, don't even try guess how it needs to be formed.
678 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
680 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
681 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
683 /* It has no '.' in it, it must be a nick. */
688 /* Got a dot in it? Has to be a host */
689 mask = "*!*@" + mask;
692 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
694 /* Has an @ but no !, its a user@host */
697 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
699 /* Has a ! but no @, it must be a nick!ident */
704 bool ModeParser::AddMode(ModeHandler* mh)
706 unsigned char mask = 0;
707 unsigned char pos = 0;
709 /* Yes, i know, this might let people declare modes like '_' or '^'.
710 * If they do that, thats their problem, and if i ever EVER see an
711 * official InspIRCd developer do that, i'll beat them with a paddle!
713 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
716 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
717 * A mode prefix of ':' will fuck up both server to server, and client to server.
718 * A mode prefix of '#' will mess up /whois and /privmsg
720 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
723 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
724 pos = (mh->GetModeChar()-65) | mask;
726 if (modehandlers[pos])
729 modehandlers[pos] = mh;
733 bool ModeParser::DelMode(ModeHandler* mh)
735 unsigned char mask = 0;
736 unsigned char pos = 0;
738 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
741 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
742 pos = (mh->GetModeChar()-65) | mask;
744 if (!modehandlers[pos])
747 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
748 * To stack here we have to make the algorithm slower. Discuss.
750 switch (mh->GetModeType())
753 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
755 mh->RemoveMode(i->second);
758 case MODETYPE_CHANNEL:
759 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
761 mh->RemoveMode(i->second);
766 modehandlers[pos] = NULL;
771 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
773 unsigned char mask = 0;
774 unsigned char pos = 0;
776 if ((modeletter < 'A') || (modeletter > 'z'))
779 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
780 pos = (modeletter-65) | mask;
782 return modehandlers[pos];
785 std::string ModeParser::UserModeList()
790 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
792 unsigned char pos = (mode-65) | MASK_USER;
794 if (modehandlers[pos])
795 modestr[pointer++] = mode;
797 modestr[pointer++] = 0;
801 std::string ModeParser::ChannelModeList()
806 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
808 unsigned char pos = (mode-65) | MASK_CHANNEL;
810 if (modehandlers[pos])
811 modestr[pointer++] = mode;
813 modestr[pointer++] = 0;
817 std::string ModeParser::ParaModeList()
822 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
824 unsigned char pos = (mode-65) | MASK_CHANNEL;
826 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
827 modestr[pointer++] = mode;
829 modestr[pointer++] = 0;
833 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
835 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
837 unsigned char pos = (mode-65) | MASK_CHANNEL;
839 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
841 return modehandlers[pos];
847 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
852 if (!channel || !user)
855 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
857 unsigned char pos = (mode-65) | MASK_CHANNEL;
858 ModeHandler* mh = modehandlers[pos];
859 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
862 ret = mh->ModeSet(NULL, user, channel, user->nick);
863 if ((ret.first) && (ret.second == user->nick))
868 pars.append(user->nick);
870 types.push_back(mh->GetModeChar());
881 std::string ModeParser::GiveModeList(ModeMasks m)
883 std::string type1; /* Listmodes EXCEPT those with a prefix */
884 std::string type2; /* Modes that take a param when adding or removing */
885 std::string type3; /* Modes that only take a param when adding */
886 std::string type4; /* Modes that dont take a param */
888 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
890 unsigned char pos = (mode-65) | m;
891 /* One parameter when adding */
892 if (modehandlers[pos])
894 if (modehandlers[pos]->GetNumParams(true))
896 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
898 type1 += modehandlers[pos]->GetModeChar();
902 /* ... and one parameter when removing */
903 if (modehandlers[pos]->GetNumParams(false))
905 /* But not a list mode */
906 if (!modehandlers[pos]->GetPrefix())
908 type2 += modehandlers[pos]->GetModeChar();
913 /* No parameters when removing */
914 type3 += modehandlers[pos]->GetModeChar();
920 type4 += modehandlers[pos]->GetModeChar();
925 return type1 + "," + type2 + "," + type3 + "," + type4;
928 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
930 return one.second > two.second;
933 std::string ModeParser::BuildPrefixes()
935 std::string mletters;
936 std::string mprefixes;
938 std::map<char,char> prefix_to_mode;
940 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
942 unsigned char pos = (mode-65) | MASK_CHANNEL;
944 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
946 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
947 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
951 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
953 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
955 mletters = mletters + n->first;
956 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
959 return "(" + mprefixes + ")" + mletters;
962 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
964 unsigned char mask = 0;
965 unsigned char pos = 0;
970 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
973 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
974 pos = (mw->GetModeChar()-65) | mask;
976 modewatchers[pos].push_back(mw);
981 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
983 unsigned char mask = 0;
984 unsigned char pos = 0;
989 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
992 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
993 pos = (mw->GetModeChar()-65) | mask;
995 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
997 if (a == modewatchers[pos].end())
1002 modewatchers[pos].erase(a);
1007 /** This default implementation can remove simple user modes
1009 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1011 char moderemove[MAXBUF];
1012 std::vector<std::string> parameters;
1014 if (user->IsModeSet(this->GetModeChar()))
1018 stack->Push(this->GetModeChar());
1022 sprintf(moderemove,"-%c",this->GetModeChar());
1023 parameters.push_back(user->nick);
1024 parameters.push_back(moderemove);
1025 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
1030 /** This default implementation can remove simple channel modes
1033 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1035 char moderemove[MAXBUF];
1036 std::vector<std::string> parameters;
1038 if (channel->IsModeSet(this->GetModeChar()))
1042 stack->Push(this->GetModeChar());
1046 sprintf(moderemove,"-%c",this->GetModeChar());
1047 parameters.push_back(channel->name);
1048 parameters.push_back(moderemove);
1049 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1054 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1056 ModeHandler* modes[] =
1058 new ModeChannelSecret(Instance),
1059 new ModeChannelPrivate(Instance),
1060 new ModeChannelModerated(Instance),
1061 new ModeChannelTopicOps(Instance),
1063 new ModeChannelNoExternal(Instance),
1064 new ModeChannelInviteOnly(Instance),
1065 new ModeChannelKey(Instance),
1066 new ModeChannelLimit(Instance),
1068 new ModeChannelBan(Instance),
1069 new ModeChannelOp(Instance),
1070 new ModeChannelHalfOp(Instance),
1071 new ModeChannelVoice(Instance),
1073 new ModeUserWallops(Instance),
1074 new ModeUserInvisible(Instance),
1075 new ModeUserOperator(Instance),
1076 new ModeUserServerNoticeMask(Instance),
1077 #define BUILTIN_MODE_COUNT 16
1080 /* Clear mode handler list */
1081 memset(modehandlers, 0, sizeof(modehandlers));
1083 /* Last parse string */
1086 /* Initialise the RFC mode letters */
1087 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1088 this->AddMode(modes[index]);
1091 memset(&sent, 0, sizeof(sent));
1094 ModeParser::~ModeParser()
1097 for(int i=0; i < 256; i++)
1099 ModeHandler* mh = modehandlers[i];
1106 if (count != BUILTIN_MODE_COUNT)
1107 throw CoreException("Mode handler found non-core modes remaining at deallocation");