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 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, targetchannel->name, *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);
487 /* No such nick/channel */
488 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, 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, targetchannel->name, 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 > 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, 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, output_sequence.c_str(), parameter_list.str().c_str());
740 this->LastParse = targetchannel->name;
744 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,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,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,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 ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
785 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
786 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
788 /* It has no '.' in it, it must be a nick. */
793 /* Got a dot in it? Has to be a host */
794 mask = "*!*@" + mask;
797 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
799 /* Has an @ but no !, its a user@host */
802 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
804 /* Has a ! but no @, it must be a nick!ident */
809 bool ModeParser::AddMode(ModeHandler* mh)
811 unsigned char mask = 0;
812 unsigned char pos = 0;
814 /* Yes, i know, this might let people declare modes like '_' or '^'.
815 * If they do that, thats their problem, and if i ever EVER see an
816 * official InspIRCd developer do that, i'll beat them with a paddle!
818 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
821 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
822 * A mode prefix of ':' will fuck up both server to server, and client to server.
823 * A mode prefix of '#' will mess up /whois and /privmsg
825 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
828 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
829 pos = (mh->GetModeChar()-65) | mask;
831 if (modehandlers[pos])
834 modehandlers[pos] = mh;
838 bool ModeParser::DelMode(ModeHandler* mh)
840 unsigned char mask = 0;
841 unsigned char pos = 0;
843 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
846 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
847 pos = (mh->GetModeChar()-65) | mask;
849 if (!modehandlers[pos])
852 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
853 * To stack here we have to make the algorithm slower. Discuss.
855 switch (mh->GetModeType())
858 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
860 mh->RemoveMode(i->second);
863 case MODETYPE_CHANNEL:
864 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
866 mh->RemoveMode(i->second);
871 modehandlers[pos] = NULL;
876 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
878 unsigned char mask = 0;
879 unsigned char pos = 0;
881 if ((modeletter < 'A') || (modeletter > 'z'))
884 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
885 pos = (modeletter-65) | mask;
887 return modehandlers[pos];
890 std::string ModeParser::UserModeList()
895 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
897 unsigned char pos = (mode-65) | MASK_USER;
899 if (modehandlers[pos])
900 modestr[pointer++] = mode;
902 modestr[pointer++] = 0;
906 std::string ModeParser::ChannelModeList()
911 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
913 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
916 unsigned char pos = (mode-65) | MASK_CHANNEL;
918 if (modehandlers[pos])
919 modestr[pointer++] = mode;
921 modestr[pointer++] = 0;
925 std::string ModeParser::ParaModeList()
930 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
932 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
935 unsigned char pos = (mode-65) | MASK_CHANNEL;
937 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
938 modestr[pointer++] = mode;
940 modestr[pointer++] = 0;
944 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
946 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
948 unsigned char pos = (mode-65) | MASK_CHANNEL;
950 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
952 return modehandlers[pos];
958 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
963 if (!channel || !user)
966 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
968 unsigned char pos = (mode-65) | MASK_CHANNEL;
969 ModeHandler* mh = modehandlers[pos];
970 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
973 ret = mh->ModeSet(NULL, user, channel, user->nick);
974 if ((ret.first) && (ret.second == user->nick))
979 pars.append(user->nick);
981 types.push_back(mh->GetModeChar());
992 std::string ModeParser::ChanModes()
994 std::string type1; /* Listmodes EXCEPT those with a prefix */
995 std::string type2; /* Modes that take a param when adding or removing */
996 std::string type3; /* Modes that only take a param when adding */
997 std::string type4; /* Modes that dont take a param */
999 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1001 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1004 unsigned char pos = (mode-65) | MASK_CHANNEL;
1005 /* One parameter when adding */
1006 if (modehandlers[pos])
1008 if (modehandlers[pos]->GetNumParams(true))
1010 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1012 type1 += modehandlers[pos]->GetModeChar();
1016 /* ... and one parameter when removing */
1017 if (modehandlers[pos]->GetNumParams(false))
1019 /* But not a list mode */
1020 if (!modehandlers[pos]->GetPrefix())
1022 type2 += modehandlers[pos]->GetModeChar();
1027 /* No parameters when removing */
1028 type3 += modehandlers[pos]->GetModeChar();
1034 type4 += modehandlers[pos]->GetModeChar();
1040 return type1 + "," + type2 + "," + type3 + "," + type4;
1043 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1045 return one.second > two.second;
1048 std::string ModeParser::BuildPrefixes()
1050 std::string mletters;
1051 std::string mprefixes;
1053 std::map<char,char> prefix_to_mode;
1055 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1057 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1060 unsigned char pos = (mode-65) | MASK_CHANNEL;
1062 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1064 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1065 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1069 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1071 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1073 mletters = mletters + n->first;
1074 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1077 return "(" + mprefixes + ")" + mletters;
1080 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1082 unsigned char mask = 0;
1083 unsigned char pos = 0;
1088 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1091 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1092 pos = (mw->GetModeChar()-65) | mask;
1094 modewatchers[pos].push_back(mw);
1099 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1101 unsigned char mask = 0;
1102 unsigned char pos = 0;
1107 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1110 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1111 pos = (mw->GetModeChar()-65) | mask;
1113 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1115 if (a == modewatchers[pos].end())
1120 modewatchers[pos].erase(a);
1125 /** This default implementation can remove simple user modes
1127 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1129 char moderemove[MAXBUF];
1130 std::vector<std::string> parameters;
1132 if (user->IsModeSet(this->GetModeChar()))
1136 stack->Push(this->GetModeChar());
1140 sprintf(moderemove,"-%c",this->GetModeChar());
1141 parameters.push_back(user->nick);
1142 parameters.push_back(moderemove);
1143 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1148 /** This default implementation can remove simple channel modes
1151 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1153 char moderemove[MAXBUF];
1154 std::vector<std::string> parameters;
1156 if (channel->IsModeSet(this->GetModeChar()))
1160 stack->Push(this->GetModeChar());
1164 sprintf(moderemove,"-%c",this->GetModeChar());
1165 parameters.push_back(channel->name);
1166 parameters.push_back(moderemove);
1167 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1172 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1174 ModeHandler* modes[] =
1176 new ModeChannelSecret(Instance),
1177 new ModeChannelPrivate(Instance),
1178 new ModeChannelModerated(Instance),
1179 new ModeChannelTopicOps(Instance),
1180 new ModeChannelNoExternal(Instance),
1181 new ModeChannelInviteOnly(Instance),
1182 new ModeChannelKey(Instance),
1183 new ModeChannelLimit(Instance),
1184 new ModeChannelBan(Instance),
1185 new ModeChannelOp(Instance),
1186 new ModeChannelHalfOp(Instance),
1187 new ModeChannelVoice(Instance),
1188 new ModeUserServerNotice(Instance),
1189 new ModeUserWallops(Instance),
1190 new ModeUserInvisible(Instance),
1191 new ModeUserOperator(Instance),
1192 new ModeUserServerNoticeMask(Instance),
1196 /* Clear mode handler list */
1197 memset(modehandlers, 0, sizeof(modehandlers));
1199 /* Last parse string */
1202 /* Initialise the RFC mode letters */
1203 for (int index = 0; modes[index]; index++)
1204 this->AddMode(modes[index]);
1207 memset(&sent, 0, 256);