1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2008 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
14 /* $Core: libIRCDmode */
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
20 #include "inspstring.h"
23 #include "modes/cmode_s.h"
25 #include "modes/cmode_p.h"
27 #include "modes/cmode_b.h"
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +s (server notices) */
47 #include "modes/umode_s.h"
48 /* +w (see wallops) */
49 #include "modes/umode_w.h"
51 #include "modes/umode_i.h"
53 #include "modes/umode_o.h"
54 /* +n (notice mask - our implementation of snomasks) */
55 #include "modes/umode_n.h"
57 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
58 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
62 ModeHandler::~ModeHandler()
66 bool ModeHandler::IsListMode()
71 char ModeHandler::GetNeededPrefix()
76 void ModeHandler::SetNeededPrefix(char needsprefix)
78 prefixneeded = needsprefix;
81 unsigned int ModeHandler::GetPrefixRank()
86 unsigned int ModeHandler::GetCount()
91 void ModeHandler::ChangeCount(int modifier)
94 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
97 ModeType ModeHandler::GetModeType()
102 bool ModeHandler::NeedsOper()
107 char ModeHandler::GetPrefix()
112 int ModeHandler::GetNumParams(bool adding)
114 return adding ? n_params_on : n_params_off;
117 char ModeHandler::GetModeChar()
122 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
124 return MODEACTION_DENY;
127 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
131 return std::make_pair(dest->IsModeSet(this->mode), "");
135 return std::make_pair(channel->IsModeSet(this->mode), "");
139 void ModeHandler::DisplayList(User*, Channel*)
143 void ModeHandler::DisplayEmptyList(User*, Channel*)
147 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
149 return (ours < theirs);
152 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
156 SimpleUserModeHandler::~SimpleUserModeHandler()
160 SimpleChannelModeHandler::~SimpleChannelModeHandler()
164 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
168 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
170 /* Only opers can change other users modes */
172 return MODEACTION_DENY;
176 if (!dest->IsModeSet(this->GetModeChar()))
178 dest->SetMode(this->GetModeChar(),true);
179 return MODEACTION_ALLOW;
184 if (dest->IsModeSet(this->GetModeChar()))
186 dest->SetMode(this->GetModeChar(),false);
187 return MODEACTION_ALLOW;
191 return MODEACTION_DENY;
195 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
199 if (!channel->IsModeSet(this->GetModeChar()))
201 channel->SetMode(this->GetModeChar(),true);
202 return MODEACTION_ALLOW;
207 if (channel->IsModeSet(this->GetModeChar()))
209 channel->SetMode(this->GetModeChar(),false);
210 return MODEACTION_ALLOW;
214 return MODEACTION_DENY;
217 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
221 ModeWatcher::~ModeWatcher()
225 char ModeWatcher::GetModeChar()
230 ModeType ModeWatcher::GetModeType()
235 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
240 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
244 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
247 if ((!user) || (!dest) || (!chan) || (!*dest))
251 d = ServerInstance->FindNick(dest);
254 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), dest);
260 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
265 UCListIter n = d->chans.find(chan);
266 if (n != d->chans.end())
268 if (n->second & MASK)
272 n->second = n->second | MASK;
276 n->first->AddOppedUser(d);
279 n->first->AddHalfoppedUser(d);
282 n->first->AddVoicedUser(d);
285 return d->nick.c_str();
290 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
295 UCListIter n = d->chans.find(chan);
296 if (n != d->chans.end())
298 if ((n->second & MASK) == 0)
306 n->first->DelOppedUser(d);
309 n->first->DelHalfoppedUser(d);
312 n->first->DelVoicedUser(d);
315 return d->nick.c_str();
320 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
324 /* Display channel's current mode string */
325 user->WriteNumeric(324, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
326 user->WriteNumeric(329, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
331 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
333 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), text);
337 if ((targetuser == user) || (IS_OPER(user)))
339 /* Display user's current mode string */
340 user->WriteNumeric(221, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
341 if (IS_OPER(targetuser))
342 user->WriteNumeric(8, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
347 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick.c_str());
352 /* No such nick/channel */
353 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), text);
357 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
359 std::string target = parameters[0];
360 ModeType type = MODETYPE_USER;
361 unsigned char mask = 0;
362 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
363 User* targetuser = ServerInstance->FindNick(parameters[0]);
367 /* Special case for displaying the list for listmodes,
368 * e.g. MODE #chan b, or MODE #chan +b without a parameter
370 if ((targetchannel) && (parameters.size() == 2))
372 const char* mode = parameters[1].c_str();
373 int nonlistmodes_found = 0;
379 while (mode && *mode)
381 unsigned char mletter = *mode;
389 /* Ensure the user doesnt request the same mode twice,
390 * so they cant flood themselves off out of idiocy.
392 if (sent[mletter] != seq)
402 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
405 if ((mh) && (mh->IsListMode()))
408 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
409 if (MOD_RESULT == ACR_DENY)
415 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
417 user->WriteNumeric(482, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
418 mh->DisplayEmptyList(user, targetchannel);
422 /** See below for a description of what craq this is :D
424 unsigned char handler_id = (*mode - 65) | mask;
426 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
428 std::string dummyparam;
430 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
435 mh->DisplayList(user, targetchannel);
438 nonlistmodes_found++;
443 /* We didnt have any modes that were non-list, we can return here */
444 if (!nonlistmodes_found)
448 if (parameters.size() == 1)
450 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
452 else if (parameters.size() > 1)
454 bool SkipAccessChecks = false;
458 type = MODETYPE_CHANNEL;
461 /* Extra security checks on channel modes
462 * (e.g. are they a (half)op?
465 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
467 /* We don't have halfop */
469 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
470 if (MOD_RESULT == ACR_DENY)
472 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
477 type = MODETYPE_USER;
479 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
481 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick.c_str());
487 /* No such nick/channel */
488 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
492 std::string mode_sequence = parameters[1];
493 std::string parameter;
494 std::ostringstream parameter_list;
495 std::string output_sequence;
496 bool adding = true, state_change = false;
497 unsigned char handler_id = 0;
498 unsigned int parameter_counter = 2; /* Index of first parameter */
499 unsigned int parameter_count = 0;
500 bool last_successful_state_change = false;
502 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
503 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
504 mode_sequence.insert(0, "+");
506 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
508 unsigned char modechar = *letter;
513 * For + and - mode characters, we don't just stick the character into the output sequence.
514 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
515 * appearing in the output sequence, we store a flag which says there was a state change,
516 * which is set on any + or -, however, the + or - that we finish on is only appended to
517 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
520 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
521 * however, will allow the + if it is the first item in the sequence, regardless.
523 if ((!adding) || (!output_sequence.length()))
526 if (!output_sequence.length())
527 last_successful_state_change = false;
531 if ((adding) || (!output_sequence.length()))
534 if (!output_sequence.length())
535 last_successful_state_change = true;
541 * Watch carefully for the sleight of hand trick.
542 * 65 is the ascii value of 'A'. We take this from
543 * the char we're looking at to get a number between
544 * 1 and 127. We then logic-or it to get the hashed
545 * position, dependent on wether its a channel or
546 * a user mode. This is a little stranger, but a lot
547 * faster, than using a map of pairs.
549 handler_id = (modechar - 65) | mask;
551 if (modehandlers[handler_id])
555 if (modehandlers[handler_id]->GetModeType() == type)
559 if (modehandlers[handler_id]->GetNumParams(adding))
561 /* This mode expects a parameter, do we have any parameters left in our list to use? */
562 if (parameter_counter < parameters.size())
564 parameter = parameters[parameter_counter++];
567 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
572 /* No parameter, continue to the next mode */
576 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
580 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
583 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
586 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
588 /* Check access to this mode character */
589 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
591 char needed = modehandlers[handler_id]->GetNeededPrefix();
592 ModeHandler* prefixmode = FindPrefix(needed);
594 /* If the mode defined by the handler is not '\0', but the handler for it
595 * cannot be found, they probably dont have the right module loaded to implement
596 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
597 * Revert to checking against the minimum core prefix, '%'.
599 if (needed && !prefixmode)
600 prefixmode = FindPrefix('%');
602 unsigned int neededrank = prefixmode->GetPrefixRank();
603 /* Compare our rank on the channel against the rank of the required prefix,
604 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
605 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
606 * first, so we don't need to iterate, we just look up the first instead.
608 std::string modestring = targetchannel->GetAllPrefixChars(user);
609 char ml = (modestring.empty() ? '\0' : modestring[0]);
610 ModeHandler* ourmode = FindPrefix(ml);
611 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
614 user->WriteNumeric(482, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
615 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
621 bool had_parameter = !parameter.empty();
623 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
625 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
630 /* A module whacked the parameter completely, and there was one. abort. */
631 if ((had_parameter) && (parameter.empty()))
641 /* It's an oper only mode, check if theyre an oper. If they arent,
642 * eat any parameter that came with the mode, and continue to next
644 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
648 user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
651 type == MODETYPE_CHANNEL ? "channel" : "user",
652 modehandlers[handler_id]->GetModeChar());
656 user->WriteNumeric(481, "%s :Permission Denied - Only operators may set %s mode %c",
658 type == MODETYPE_CHANNEL ? "channel" : "user",
659 modehandlers[handler_id]->GetModeChar());
664 /* Call the handler for the mode */
665 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
667 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
669 /* The handler nuked the parameter and they are supposed to have one.
670 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
671 * so we bail to the next mode character.
676 if (ma == MODEACTION_ALLOW)
678 /* We're about to output a valid mode letter - was there previously a pending state-change? */
681 if (adding != last_successful_state_change)
682 output_sequence.append(adding ? "+" : "-");
683 last_successful_state_change = adding;
686 /* Add the mode letter */
687 output_sequence.push_back(modechar);
689 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
691 /* Is there a valid parameter for this mode? If so add it to the parameter list */
692 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
694 parameter_list << " " << parameter;
696 /* Does this mode have a prefix? */
697 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
699 User* user_to_prefix = ServerInstance->FindNick(parameter);
701 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
702 modehandlers[handler_id]->GetPrefixRank(), adding);
706 /* Call all the AfterMode events in the mode watchers for this mode */
707 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
708 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
710 /* Reset the state change flag */
711 state_change = false;
713 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
714 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
716 /* We cant have a mode sequence this long */
717 letter = mode_sequence.end() - 1;
725 /* No mode handler? Unknown mode character then. */
726 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
732 /* Was there at least one valid mode in the sequence? */
733 if (!output_sequence.empty())
737 if (type == MODETYPE_CHANNEL)
739 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
740 this->LastParse = targetchannel->name;
744 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
745 this->LastParse = targetuser->nick;
750 if (type == MODETYPE_CHANNEL)
752 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
753 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
754 this->LastParse = targetchannel->name;
758 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
759 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
760 this->LastParse = targetuser->nick;
764 LastParse.append(" ");
765 LastParse.append(output_sequence);
766 LastParse.append(parameter_list.str());
771 const std::string& ModeParser::GetLastParse()
776 void ModeParser::CleanMask(std::string &mask)
778 std::string::size_type pos_of_pling = mask.find_first_of('!');
779 std::string::size_type pos_of_at = mask.find_first_of('@');
780 std::string::size_type pos_of_dot = mask.find_first_of('.');
781 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
783 if (mask.length() >= 2 && mask[1] == ':')
784 return; // if it's an extban, don't even try guess how it needs to be formed.
786 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
788 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
789 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
791 /* It has no '.' in it, it must be a nick. */
796 /* Got a dot in it? Has to be a host */
797 mask = "*!*@" + mask;
800 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
802 /* Has an @ but no !, its a user@host */
805 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
807 /* Has a ! but no @, it must be a nick!ident */
812 bool ModeParser::AddMode(ModeHandler* mh)
814 unsigned char mask = 0;
815 unsigned char pos = 0;
817 /* Yes, i know, this might let people declare modes like '_' or '^'.
818 * If they do that, thats their problem, and if i ever EVER see an
819 * official InspIRCd developer do that, i'll beat them with a paddle!
821 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
824 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
825 * A mode prefix of ':' will fuck up both server to server, and client to server.
826 * A mode prefix of '#' will mess up /whois and /privmsg
828 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
831 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
832 pos = (mh->GetModeChar()-65) | mask;
834 if (modehandlers[pos])
837 modehandlers[pos] = mh;
841 bool ModeParser::DelMode(ModeHandler* mh)
843 unsigned char mask = 0;
844 unsigned char pos = 0;
846 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
849 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
850 pos = (mh->GetModeChar()-65) | mask;
852 if (!modehandlers[pos])
855 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
856 * To stack here we have to make the algorithm slower. Discuss.
858 switch (mh->GetModeType())
861 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
863 mh->RemoveMode(i->second);
866 case MODETYPE_CHANNEL:
867 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
869 mh->RemoveMode(i->second);
874 modehandlers[pos] = NULL;
879 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
881 unsigned char mask = 0;
882 unsigned char pos = 0;
884 if ((modeletter < 'A') || (modeletter > 'z'))
887 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
888 pos = (modeletter-65) | mask;
890 return modehandlers[pos];
893 std::string ModeParser::UserModeList()
898 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
900 unsigned char pos = (mode-65) | MASK_USER;
902 if (modehandlers[pos])
903 modestr[pointer++] = mode;
905 modestr[pointer++] = 0;
909 std::string ModeParser::ChannelModeList()
914 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
916 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
919 unsigned char pos = (mode-65) | MASK_CHANNEL;
921 if (modehandlers[pos])
922 modestr[pointer++] = mode;
924 modestr[pointer++] = 0;
928 std::string ModeParser::ParaModeList()
933 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
935 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
938 unsigned char pos = (mode-65) | MASK_CHANNEL;
940 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
941 modestr[pointer++] = mode;
943 modestr[pointer++] = 0;
947 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
949 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
951 unsigned char pos = (mode-65) | MASK_CHANNEL;
953 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
955 return modehandlers[pos];
961 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
966 if (!channel || !user)
969 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
971 unsigned char pos = (mode-65) | MASK_CHANNEL;
972 ModeHandler* mh = modehandlers[pos];
973 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
976 ret = mh->ModeSet(NULL, user, channel, user->nick);
977 if ((ret.first) && (ret.second == user->nick))
982 pars.append(user->nick);
984 types.push_back(mh->GetModeChar());
995 std::string ModeParser::ChanModes()
997 std::string type1; /* Listmodes EXCEPT those with a prefix */
998 std::string type2; /* Modes that take a param when adding or removing */
999 std::string type3; /* Modes that only take a param when adding */
1000 std::string type4; /* Modes that dont take a param */
1002 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1004 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1007 unsigned char pos = (mode-65) | MASK_CHANNEL;
1008 /* One parameter when adding */
1009 if (modehandlers[pos])
1011 if (modehandlers[pos]->GetNumParams(true))
1013 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1015 type1 += modehandlers[pos]->GetModeChar();
1019 /* ... and one parameter when removing */
1020 if (modehandlers[pos]->GetNumParams(false))
1022 /* But not a list mode */
1023 if (!modehandlers[pos]->GetPrefix())
1025 type2 += modehandlers[pos]->GetModeChar();
1030 /* No parameters when removing */
1031 type3 += modehandlers[pos]->GetModeChar();
1037 type4 += modehandlers[pos]->GetModeChar();
1043 return type1 + "," + type2 + "," + type3 + "," + type4;
1046 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1048 return one.second > two.second;
1051 std::string ModeParser::BuildPrefixes()
1053 std::string mletters;
1054 std::string mprefixes;
1056 std::map<char,char> prefix_to_mode;
1058 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1060 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1063 unsigned char pos = (mode-65) | MASK_CHANNEL;
1065 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1067 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1068 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1072 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1074 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1076 mletters = mletters + n->first;
1077 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1080 return "(" + mprefixes + ")" + mletters;
1083 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1085 unsigned char mask = 0;
1086 unsigned char pos = 0;
1091 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1094 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1095 pos = (mw->GetModeChar()-65) | mask;
1097 modewatchers[pos].push_back(mw);
1102 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1104 unsigned char mask = 0;
1105 unsigned char pos = 0;
1110 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1113 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1114 pos = (mw->GetModeChar()-65) | mask;
1116 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1118 if (a == modewatchers[pos].end())
1123 modewatchers[pos].erase(a);
1128 /** This default implementation can remove simple user modes
1130 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1132 char moderemove[MAXBUF];
1133 std::vector<std::string> parameters;
1135 if (user->IsModeSet(this->GetModeChar()))
1139 stack->Push(this->GetModeChar());
1143 sprintf(moderemove,"-%c",this->GetModeChar());
1144 parameters.push_back(user->nick);
1145 parameters.push_back(moderemove);
1146 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1151 /** This default implementation can remove simple channel modes
1154 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1156 char moderemove[MAXBUF];
1157 std::vector<std::string> parameters;
1159 if (channel->IsModeSet(this->GetModeChar()))
1163 stack->Push(this->GetModeChar());
1167 sprintf(moderemove,"-%c",this->GetModeChar());
1168 parameters.push_back(channel->name);
1169 parameters.push_back(moderemove);
1170 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1175 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1177 ModeHandler* modes[] =
1179 new ModeChannelSecret(Instance),
1180 new ModeChannelPrivate(Instance),
1181 new ModeChannelModerated(Instance),
1182 new ModeChannelTopicOps(Instance),
1183 new ModeChannelNoExternal(Instance),
1184 new ModeChannelInviteOnly(Instance),
1185 new ModeChannelKey(Instance),
1186 new ModeChannelLimit(Instance),
1187 new ModeChannelBan(Instance),
1188 new ModeChannelOp(Instance),
1189 new ModeChannelHalfOp(Instance),
1190 new ModeChannelVoice(Instance),
1191 new ModeUserServerNotice(Instance),
1192 new ModeUserWallops(Instance),
1193 new ModeUserInvisible(Instance),
1194 new ModeUserOperator(Instance),
1195 new ModeUserServerNoticeMask(Instance),
1199 /* Clear mode handler list */
1200 memset(modehandlers, 0, sizeof(modehandlers));
1202 /* Last parse string */
1205 /* Initialise the RFC mode letters */
1206 for (int index = 0; modes[index]; index++)
1207 this->AddMode(modes[index]);
1210 memset(&sent, 0, 256);