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, 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);
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);
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, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
326 user->WriteNumeric(329, "%s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
331 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
333 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, text);
337 if ((targetuser == user) || (IS_OPER(user)))
339 /* Display user's current mode string */
340 user->WriteNumeric(221, "%s :+%s",targetuser->nick,targetuser->FormatModes());
341 if (IS_OPER(targetuser))
342 user->WriteNumeric(8, "%s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
347 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
352 /* No such nick/channel */
353 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, text);
357 void ModeParser::Process(const char* const* parameters, int pcnt, 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) && (pcnt == 2))
372 const char* mode = parameters[1];
373 int nonlistmodes_found = 0;
378 memset(&sent, 0, 256);
380 while (mode && *mode)
382 unsigned char mletter = *mode;
390 /* Ensure the user doesnt request the same mode twice,
391 * so they cant flood themselves off out of idiocy.
395 sent[mletter] = true;
403 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
406 if ((mh) && (mh->IsListMode()))
409 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
410 if (MOD_RESULT == ACR_DENY)
416 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
418 user->WriteNumeric(482, "%s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
419 mh->DisplayEmptyList(user, targetchannel);
423 /** See below for a description of what craq this is :D
425 unsigned char handler_id = (*mode - 65) | mask;
427 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
429 std::string dummyparam;
431 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
436 mh->DisplayList(user, targetchannel);
439 nonlistmodes_found++;
444 /* We didnt have any modes that were non-list, we can return here */
445 if (!nonlistmodes_found)
451 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
455 bool SkipAccessChecks = false;
459 type = MODETYPE_CHANNEL;
462 /* Extra security checks on channel modes
463 * (e.g. are they a (half)op?
466 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
468 /* We don't have halfop */
470 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
471 if (MOD_RESULT == ACR_DENY)
473 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
478 type = MODETYPE_USER;
480 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
482 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
488 /* No such nick/channel */
489 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, parameters[0]);
493 std::string mode_sequence = parameters[1];
494 std::string parameter;
495 std::ostringstream parameter_list;
496 std::string output_sequence;
497 bool adding = true, state_change = false;
498 unsigned char handler_id = 0;
499 int parameter_counter = 2; /* Index of first parameter */
500 int parameter_count = 0;
501 bool last_successful_state_change = false;
503 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
504 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
505 mode_sequence.insert(0, "+");
507 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
509 unsigned char modechar = *letter;
514 * For + and - mode characters, we don't just stick the character into the output sequence.
515 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
516 * appearing in the output sequence, we store a flag which says there was a state change,
517 * which is set on any + or -, however, the + or - that we finish on is only appended to
518 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
521 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
522 * however, will allow the + if it is the first item in the sequence, regardless.
524 if ((!adding) || (!output_sequence.length()))
527 if (!output_sequence.length())
528 last_successful_state_change = false;
532 if ((adding) || (!output_sequence.length()))
535 if (!output_sequence.length())
536 last_successful_state_change = true;
542 * Watch carefully for the sleight of hand trick.
543 * 65 is the ascii value of 'A'. We take this from
544 * the char we're looking at to get a number between
545 * 1 and 127. We then logic-or it to get the hashed
546 * position, dependent on wether its a channel or
547 * a user mode. This is a little stranger, but a lot
548 * faster, than using a map of pairs.
550 handler_id = (modechar - 65) | mask;
552 if (modehandlers[handler_id])
556 if (modehandlers[handler_id]->GetModeType() == type)
560 if (modehandlers[handler_id]->GetNumParams(adding))
562 /* This mode expects a parameter, do we have any parameters left in our list to use? */
563 if (parameter_counter < pcnt)
565 parameter = parameters[parameter_counter++];
568 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
573 /* No parameter, continue to the next mode */
577 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
581 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
584 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
587 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
589 /* Check access to this mode character */
590 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
592 char needed = modehandlers[handler_id]->GetNeededPrefix();
593 ModeHandler* prefixmode = FindPrefix(needed);
595 /* If the mode defined by the handler is not '\0', but the handler for it
596 * cannot be found, they probably dont have the right module loaded to implement
597 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
598 * Revert to checking against the minimum core prefix, '%'.
600 if (needed && !prefixmode)
601 prefixmode = FindPrefix('%');
603 unsigned int neededrank = prefixmode->GetPrefixRank();
604 /* Compare our rank on the channel against the rank of the required prefix,
605 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
606 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
607 * first, so we don't need to iterate, we just look up the first instead.
609 std::string modestring = targetchannel->GetAllPrefixChars(user);
610 char ml = (modestring.empty() ? '\0' : modestring[0]);
611 ModeHandler* ourmode = FindPrefix(ml);
612 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
615 user->WriteNumeric(482, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
616 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
622 bool had_parameter = !parameter.empty();
624 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
626 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
631 /* A module whacked the parameter completely, and there was one. abort. */
632 if ((had_parameter) && (parameter.empty()))
642 /* It's an oper only mode, check if theyre an oper. If they arent,
643 * eat any parameter that came with the mode, and continue to next
645 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
649 user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
652 type == MODETYPE_CHANNEL ? "channel" : "user",
653 modehandlers[handler_id]->GetModeChar());
657 user->WriteNumeric(481, "%s :Permission Denied - Only operators may set %s mode %c",
659 type == MODETYPE_CHANNEL ? "channel" : "user",
660 modehandlers[handler_id]->GetModeChar());
665 /* Call the handler for the mode */
666 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
668 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
670 /* The handler nuked the parameter and they are supposed to have one.
671 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
672 * so we bail to the next mode character.
677 if (ma == MODEACTION_ALLOW)
679 /* We're about to output a valid mode letter - was there previously a pending state-change? */
682 if (adding != last_successful_state_change)
683 output_sequence.append(adding ? "+" : "-");
684 last_successful_state_change = adding;
687 /* Add the mode letter */
688 output_sequence.push_back(modechar);
690 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
692 /* Is there a valid parameter for this mode? If so add it to the parameter list */
693 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
695 parameter_list << " " << parameter;
697 /* Does this mode have a prefix? */
698 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
700 User* user_to_prefix = ServerInstance->FindNick(parameter);
702 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
703 modehandlers[handler_id]->GetPrefixRank(), adding);
707 /* Call all the AfterMode events in the mode watchers for this mode */
708 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
709 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
711 /* Reset the state change flag */
712 state_change = false;
714 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
715 || (parameter_count > MAXMODES))
717 /* We cant have a mode sequence this long */
718 letter = mode_sequence.end() - 1;
726 /* No mode handler? Unknown mode character then. */
727 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
733 /* Was there at least one valid mode in the sequence? */
734 if (!output_sequence.empty())
738 if (type == MODETYPE_CHANNEL)
740 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
741 this->LastParse = targetchannel->name;
745 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
746 this->LastParse = targetuser->nick;
751 if (type == MODETYPE_CHANNEL)
753 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
754 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
755 this->LastParse = targetchannel->name;
759 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
760 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
761 this->LastParse = targetuser->nick;
765 LastParse.append(" ");
766 LastParse.append(output_sequence);
767 LastParse.append(parameter_list.str());
772 const std::string& ModeParser::GetLastParse()
777 void ModeParser::CleanMask(std::string &mask)
779 std::string::size_type pos_of_pling = mask.find_first_of('!');
780 std::string::size_type pos_of_at = mask.find_first_of('@');
781 std::string::size_type pos_of_dot = mask.find_first_of('.');
782 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
784 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
786 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
787 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
789 /* It has no '.' in it, it must be a nick. */
794 /* Got a dot in it? Has to be a host */
795 mask = "*!*@" + mask;
798 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
800 /* Has an @ but no !, its a user@host */
803 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
805 /* Has a ! but no @, it must be a nick!ident */
810 bool ModeParser::AddMode(ModeHandler* mh)
812 unsigned char mask = 0;
813 unsigned char pos = 0;
815 /* Yes, i know, this might let people declare modes like '_' or '^'.
816 * If they do that, thats their problem, and if i ever EVER see an
817 * official InspIRCd developer do that, i'll beat them with a paddle!
819 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
822 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
823 * A mode prefix of ':' will fuck up both server to server, and client to server.
824 * A mode prefix of '#' will mess up /whois and /privmsg
826 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
829 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
830 pos = (mh->GetModeChar()-65) | mask;
832 if (modehandlers[pos])
835 modehandlers[pos] = mh;
839 bool ModeParser::DelMode(ModeHandler* mh)
841 unsigned char mask = 0;
842 unsigned char pos = 0;
844 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
847 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
848 pos = (mh->GetModeChar()-65) | mask;
850 if (!modehandlers[pos])
853 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
854 * To stack here we have to make the algorithm slower. Discuss.
856 switch (mh->GetModeType())
859 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
861 mh->RemoveMode(i->second);
864 case MODETYPE_CHANNEL:
865 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
867 mh->RemoveMode(i->second);
872 modehandlers[pos] = NULL;
877 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
879 unsigned char mask = 0;
880 unsigned char pos = 0;
882 if ((modeletter < 'A') || (modeletter > 'z'))
885 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
886 pos = (modeletter-65) | mask;
888 return modehandlers[pos];
891 std::string ModeParser::UserModeList()
896 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
898 unsigned char pos = (mode-65) | MASK_USER;
900 if (modehandlers[pos])
901 modestr[pointer++] = mode;
903 modestr[pointer++] = 0;
907 std::string ModeParser::ChannelModeList()
912 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
914 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
917 unsigned char pos = (mode-65) | MASK_CHANNEL;
919 if (modehandlers[pos])
920 modestr[pointer++] = mode;
922 modestr[pointer++] = 0;
926 std::string ModeParser::ParaModeList()
931 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
933 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
936 unsigned char pos = (mode-65) | MASK_CHANNEL;
938 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
939 modestr[pointer++] = mode;
941 modestr[pointer++] = 0;
945 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
947 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
949 unsigned char pos = (mode-65) | MASK_CHANNEL;
951 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
953 return modehandlers[pos];
959 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
964 if (!channel || !user)
967 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
969 unsigned char pos = (mode-65) | MASK_CHANNEL;
970 ModeHandler* mh = modehandlers[pos];
971 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
974 ret = mh->ModeSet(NULL, user, channel, user->nick);
975 if ((ret.first) && (ret.second == user->nick))
980 pars.append(user->nick);
982 types.push_back(mh->GetModeChar());
993 std::string ModeParser::ChanModes()
995 std::string type1; /* Listmodes EXCEPT those with a prefix */
996 std::string type2; /* Modes that take a param when adding or removing */
997 std::string type3; /* Modes that only take a param when adding */
998 std::string type4; /* Modes that dont take a param */
1000 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1002 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1005 unsigned char pos = (mode-65) | MASK_CHANNEL;
1006 /* One parameter when adding */
1007 if (modehandlers[pos])
1009 if (modehandlers[pos]->GetNumParams(true))
1011 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1013 type1 += modehandlers[pos]->GetModeChar();
1017 /* ... and one parameter when removing */
1018 if (modehandlers[pos]->GetNumParams(false))
1020 /* But not a list mode */
1021 if (!modehandlers[pos]->GetPrefix())
1023 type2 += modehandlers[pos]->GetModeChar();
1028 /* No parameters when removing */
1029 type3 += modehandlers[pos]->GetModeChar();
1035 type4 += modehandlers[pos]->GetModeChar();
1041 return type1 + "," + type2 + "," + type3 + "," + type4;
1044 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1046 return one.second > two.second;
1049 std::string ModeParser::BuildPrefixes()
1051 std::string mletters;
1052 std::string mprefixes;
1054 std::map<char,char> prefix_to_mode;
1056 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1058 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1061 unsigned char pos = (mode-65) | MASK_CHANNEL;
1063 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1065 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1066 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1070 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1072 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1074 mletters = mletters + n->first;
1075 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1078 return "(" + mprefixes + ")" + mletters;
1081 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1083 unsigned char mask = 0;
1084 unsigned char pos = 0;
1089 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1092 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1093 pos = (mw->GetModeChar()-65) | mask;
1095 modewatchers[pos].push_back(mw);
1100 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1102 unsigned char mask = 0;
1103 unsigned char pos = 0;
1108 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1111 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1112 pos = (mw->GetModeChar()-65) | mask;
1114 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1116 if (a == modewatchers[pos].end())
1121 modewatchers[pos].erase(a);
1126 /** This default implementation can remove simple user modes
1128 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1130 char moderemove[MAXBUF];
1131 const char* parameters[] = { user->nick, moderemove };
1133 if (user->IsModeSet(this->GetModeChar()))
1137 stack->Push(this->GetModeChar());
1141 sprintf(moderemove,"-%c",this->GetModeChar());
1142 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1147 /** This default implementation can remove simple channel modes
1150 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1152 char moderemove[MAXBUF];
1153 const char* parameters[] = { channel->name, moderemove };
1155 if (channel->IsModeSet(this->GetModeChar()))
1159 stack->Push(this->GetModeChar());
1163 sprintf(moderemove,"-%c",this->GetModeChar());
1164 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1169 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1171 ModeHandler* modes[] =
1173 new ModeChannelSecret(Instance),
1174 new ModeChannelPrivate(Instance),
1175 new ModeChannelModerated(Instance),
1176 new ModeChannelTopicOps(Instance),
1177 new ModeChannelNoExternal(Instance),
1178 new ModeChannelInviteOnly(Instance),
1179 new ModeChannelKey(Instance),
1180 new ModeChannelLimit(Instance),
1181 new ModeChannelBan(Instance),
1182 new ModeChannelOp(Instance),
1183 new ModeChannelHalfOp(Instance),
1184 new ModeChannelVoice(Instance),
1185 new ModeUserServerNotice(Instance),
1186 new ModeUserWallops(Instance),
1187 new ModeUserInvisible(Instance),
1188 new ModeUserOperator(Instance),
1189 new ModeUserServerNoticeMask(Instance),
1193 /* Clear mode handler list */
1194 memset(modehandlers, 0, sizeof(modehandlers));
1196 /* Last parse string */
1199 /* Initialise the RFC mode letters */
1200 for (int index = 0; modes[index]; index++)
1201 this->AddMode(modes[index]);