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(ERR_NOSUCHNICK, "%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(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
326 user->WriteNumeric(RPL_CHANNELCREATED, "%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(RPL_NOSUCHNICK, "%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(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
341 if (IS_OPER(targetuser))
342 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
347 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
352 /* No such nick/channel */
353 user->WriteNumeric(ERR_NOSUCHNICK, "%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)
417 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
419 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
420 mh->DisplayEmptyList(user, targetchannel);
425 /** See below for a description of what craq this is :D
427 unsigned char handler_id = (*mode - 65) | mask;
429 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
431 std::string dummyparam;
433 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
438 mh->DisplayList(user, targetchannel);
441 nonlistmodes_found++;
446 /* We didnt have any modes that were non-list, we can return here */
447 if (!nonlistmodes_found)
451 if (parameters.size() == 1)
453 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
455 else if (parameters.size() > 1)
457 bool SkipAccessChecks = false;
461 type = MODETYPE_CHANNEL;
464 /* Extra security checks on channel modes
465 * (e.g. are they a (half)op?
468 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
470 /* We don't have halfop */
472 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
473 if (MOD_RESULT == ACR_DENY)
475 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
480 type = MODETYPE_USER;
482 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
484 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
490 /* No such nick/channel */
491 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
495 std::string mode_sequence = parameters[1];
496 std::string parameter;
497 std::ostringstream parameter_list;
498 std::string output_sequence;
499 bool adding = true, state_change = false;
500 unsigned char handler_id = 0;
501 unsigned int parameter_counter = 2; /* Index of first parameter */
502 unsigned int parameter_count = 0;
503 bool last_successful_state_change = false;
505 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
506 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
507 mode_sequence.insert(0, "+");
509 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
511 unsigned char modechar = *letter;
516 * For + and - mode characters, we don't just stick the character into the output sequence.
517 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
518 * appearing in the output sequence, we store a flag which says there was a state change,
519 * which is set on any + or -, however, the + or - that we finish on is only appended to
520 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
523 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
524 * however, will allow the + if it is the first item in the sequence, regardless.
526 if ((!adding) || (!output_sequence.length()))
529 if (!output_sequence.length())
530 last_successful_state_change = false;
534 if ((adding) || (!output_sequence.length()))
537 if (!output_sequence.length())
538 last_successful_state_change = true;
544 * Watch carefully for the sleight of hand trick.
545 * 65 is the ascii value of 'A'. We take this from
546 * the char we're looking at to get a number between
547 * 1 and 127. We then logic-or it to get the hashed
548 * position, dependent on wether its a channel or
549 * a user mode. This is a little stranger, but a lot
550 * faster, than using a map of pairs.
552 handler_id = (modechar - 65) | mask;
554 if (modehandlers[handler_id])
558 if (modehandlers[handler_id]->GetModeType() == type)
562 if (modehandlers[handler_id]->GetNumParams(adding))
564 /* This mode expects a parameter, do we have any parameters left in our list to use? */
565 if (parameter_counter < parameters.size())
567 parameter = parameters[parameter_counter++];
570 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
575 /* No parameter, continue to the next mode */
579 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
583 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
586 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
589 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
591 /* Check access to this mode character */
592 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
594 char needed = modehandlers[handler_id]->GetNeededPrefix();
595 ModeHandler* prefixmode = FindPrefix(needed);
597 /* If the mode defined by the handler is not '\0', but the handler for it
598 * cannot be found, they probably dont have the right module loaded to implement
599 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
600 * Revert to checking against the minimum core prefix, '%'.
602 if (needed && !prefixmode)
603 prefixmode = FindPrefix('%');
605 unsigned int neededrank = prefixmode->GetPrefixRank();
606 /* Compare our rank on the channel against the rank of the required prefix,
607 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
608 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
609 * first, so we don't need to iterate, we just look up the first instead.
611 std::string modestring = targetchannel->GetAllPrefixChars(user);
612 char ml = (modestring.empty() ? '\0' : modestring[0]);
613 ModeHandler* ourmode = FindPrefix(ml);
614 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
617 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
618 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
624 bool had_parameter = !parameter.empty();
626 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
628 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
633 /* A module whacked the parameter completely, and there was one. abort. */
634 if ((had_parameter) && (parameter.empty()))
644 /* It's an oper only mode, check if theyre an oper. If they arent,
645 * eat any parameter that came with the mode, and continue to next
647 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
651 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
654 type == MODETYPE_CHANNEL ? "channel" : "user",
655 modehandlers[handler_id]->GetModeChar());
659 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
661 type == MODETYPE_CHANNEL ? "channel" : "user",
662 modehandlers[handler_id]->GetModeChar());
667 /* Call the handler for the mode */
668 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
670 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
672 /* The handler nuked the parameter and they are supposed to have one.
673 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
674 * so we bail to the next mode character.
679 if (ma == MODEACTION_ALLOW)
681 /* We're about to output a valid mode letter - was there previously a pending state-change? */
684 if (adding != last_successful_state_change)
685 output_sequence.append(adding ? "+" : "-");
686 last_successful_state_change = adding;
689 /* Add the mode letter */
690 output_sequence.push_back(modechar);
692 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
694 /* Is there a valid parameter for this mode? If so add it to the parameter list */
695 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
697 parameter_list << " " << parameter;
699 /* Does this mode have a prefix? */
700 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
702 User* user_to_prefix = ServerInstance->FindNick(parameter);
704 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
705 modehandlers[handler_id]->GetPrefixRank(), adding);
709 /* Call all the AfterMode events in the mode watchers for this mode */
710 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
711 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
713 /* Reset the state change flag */
714 state_change = false;
716 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
717 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
719 /* We cant have a mode sequence this long */
720 letter = mode_sequence.end() - 1;
728 /* No mode handler? Unknown mode character then. */
729 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
735 /* Was there at least one valid mode in the sequence? */
736 if (!output_sequence.empty())
740 if (type == MODETYPE_CHANNEL)
742 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
743 this->LastParse = targetchannel->name;
747 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
748 this->LastParse = targetuser->nick;
753 if (type == MODETYPE_CHANNEL)
755 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
756 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
757 this->LastParse = targetchannel->name;
761 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
762 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
763 this->LastParse = targetuser->nick;
767 LastParse.append(" ");
768 LastParse.append(output_sequence);
769 LastParse.append(parameter_list.str());
774 const std::string& ModeParser::GetLastParse()
779 void ModeParser::CleanMask(std::string &mask)
781 std::string::size_type pos_of_pling = mask.find_first_of('!');
782 std::string::size_type pos_of_at = mask.find_first_of('@');
783 std::string::size_type pos_of_dot = mask.find_first_of('.');
784 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
786 if (mask.length() >= 2 && mask[1] == ':')
787 return; // if it's an extban, don't even try guess how it needs to be formed.
789 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
791 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
792 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
794 /* It has no '.' in it, it must be a nick. */
799 /* Got a dot in it? Has to be a host */
800 mask = "*!*@" + mask;
803 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
805 /* Has an @ but no !, its a user@host */
808 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
810 /* Has a ! but no @, it must be a nick!ident */
815 bool ModeParser::AddMode(ModeHandler* mh)
817 unsigned char mask = 0;
818 unsigned char pos = 0;
820 /* Yes, i know, this might let people declare modes like '_' or '^'.
821 * If they do that, thats their problem, and if i ever EVER see an
822 * official InspIRCd developer do that, i'll beat them with a paddle!
824 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
827 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
828 * A mode prefix of ':' will fuck up both server to server, and client to server.
829 * A mode prefix of '#' will mess up /whois and /privmsg
831 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
834 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
835 pos = (mh->GetModeChar()-65) | mask;
837 if (modehandlers[pos])
840 modehandlers[pos] = mh;
844 bool ModeParser::DelMode(ModeHandler* mh)
846 unsigned char mask = 0;
847 unsigned char pos = 0;
849 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
852 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
853 pos = (mh->GetModeChar()-65) | mask;
855 if (!modehandlers[pos])
858 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
859 * To stack here we have to make the algorithm slower. Discuss.
861 switch (mh->GetModeType())
864 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
866 mh->RemoveMode(i->second);
869 case MODETYPE_CHANNEL:
870 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
872 mh->RemoveMode(i->second);
877 modehandlers[pos] = NULL;
882 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
884 unsigned char mask = 0;
885 unsigned char pos = 0;
887 if ((modeletter < 'A') || (modeletter > 'z'))
890 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
891 pos = (modeletter-65) | mask;
893 return modehandlers[pos];
896 std::string ModeParser::UserModeList()
901 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
903 unsigned char pos = (mode-65) | MASK_USER;
905 if (modehandlers[pos])
906 modestr[pointer++] = mode;
908 modestr[pointer++] = 0;
912 std::string ModeParser::ChannelModeList()
917 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
919 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
922 unsigned char pos = (mode-65) | MASK_CHANNEL;
924 if (modehandlers[pos])
925 modestr[pointer++] = mode;
927 modestr[pointer++] = 0;
931 std::string ModeParser::ParaModeList()
936 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
938 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
941 unsigned char pos = (mode-65) | MASK_CHANNEL;
943 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
944 modestr[pointer++] = mode;
946 modestr[pointer++] = 0;
950 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
952 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
954 unsigned char pos = (mode-65) | MASK_CHANNEL;
956 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
958 return modehandlers[pos];
964 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
969 if (!channel || !user)
972 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
974 unsigned char pos = (mode-65) | MASK_CHANNEL;
975 ModeHandler* mh = modehandlers[pos];
976 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
979 ret = mh->ModeSet(NULL, user, channel, user->nick);
980 if ((ret.first) && (ret.second == user->nick))
985 pars.append(user->nick);
987 types.push_back(mh->GetModeChar());
998 std::string ModeParser::ChanModes()
1000 std::string type1; /* Listmodes EXCEPT those with a prefix */
1001 std::string type2; /* Modes that take a param when adding or removing */
1002 std::string type3; /* Modes that only take a param when adding */
1003 std::string type4; /* Modes that dont take a param */
1005 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1007 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1010 unsigned char pos = (mode-65) | MASK_CHANNEL;
1011 /* One parameter when adding */
1012 if (modehandlers[pos])
1014 if (modehandlers[pos]->GetNumParams(true))
1016 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1018 type1 += modehandlers[pos]->GetModeChar();
1022 /* ... and one parameter when removing */
1023 if (modehandlers[pos]->GetNumParams(false))
1025 /* But not a list mode */
1026 if (!modehandlers[pos]->GetPrefix())
1028 type2 += modehandlers[pos]->GetModeChar();
1033 /* No parameters when removing */
1034 type3 += modehandlers[pos]->GetModeChar();
1040 type4 += modehandlers[pos]->GetModeChar();
1046 return type1 + "," + type2 + "," + type3 + "," + type4;
1049 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1051 return one.second > two.second;
1054 std::string ModeParser::BuildPrefixes()
1056 std::string mletters;
1057 std::string mprefixes;
1059 std::map<char,char> prefix_to_mode;
1061 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1063 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1066 unsigned char pos = (mode-65) | MASK_CHANNEL;
1068 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1070 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1071 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1075 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1077 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1079 mletters = mletters + n->first;
1080 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1083 return "(" + mprefixes + ")" + mletters;
1086 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1088 unsigned char mask = 0;
1089 unsigned char pos = 0;
1094 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1097 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1098 pos = (mw->GetModeChar()-65) | mask;
1100 modewatchers[pos].push_back(mw);
1105 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1107 unsigned char mask = 0;
1108 unsigned char pos = 0;
1113 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1116 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1117 pos = (mw->GetModeChar()-65) | mask;
1119 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1121 if (a == modewatchers[pos].end())
1126 modewatchers[pos].erase(a);
1131 /** This default implementation can remove simple user modes
1133 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1135 char moderemove[MAXBUF];
1136 std::vector<std::string> parameters;
1138 if (user->IsModeSet(this->GetModeChar()))
1142 stack->Push(this->GetModeChar());
1146 sprintf(moderemove,"-%c",this->GetModeChar());
1147 parameters.push_back(user->nick);
1148 parameters.push_back(moderemove);
1149 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1154 /** This default implementation can remove simple channel modes
1157 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1159 char moderemove[MAXBUF];
1160 std::vector<std::string> parameters;
1162 if (channel->IsModeSet(this->GetModeChar()))
1166 stack->Push(this->GetModeChar());
1170 sprintf(moderemove,"-%c",this->GetModeChar());
1171 parameters.push_back(channel->name);
1172 parameters.push_back(moderemove);
1173 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1178 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1180 ModeHandler* modes[] =
1182 new ModeChannelSecret(Instance),
1183 new ModeChannelPrivate(Instance),
1184 new ModeChannelModerated(Instance),
1185 new ModeChannelTopicOps(Instance),
1186 new ModeChannelNoExternal(Instance),
1187 new ModeChannelInviteOnly(Instance),
1188 new ModeChannelKey(Instance),
1189 new ModeChannelLimit(Instance),
1190 new ModeChannelBan(Instance),
1191 new ModeChannelOp(Instance),
1192 new ModeChannelHalfOp(Instance),
1193 new ModeChannelVoice(Instance),
1194 new ModeUserServerNotice(Instance),
1195 new ModeUserWallops(Instance),
1196 new ModeUserInvisible(Instance),
1197 new ModeUserOperator(Instance),
1198 new ModeUserServerNoticeMask(Instance),
1202 /* Clear mode handler list */
1203 memset(modehandlers, 0, sizeof(modehandlers));
1205 /* Last parse string */
1208 /* Initialise the RFC mode letters */
1209 for (int index = 0; modes[index]; index++)
1210 this->AddMode(modes[index]);
1213 memset(&sent, 0, 256);