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 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
156 ModeWatcher::~ModeWatcher()
160 char ModeWatcher::GetModeChar()
165 ModeType ModeWatcher::GetModeType()
170 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
179 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
182 if ((!user) || (!dest) || (!chan) || (!*dest))
186 d = ServerInstance->FindNick(dest);
189 user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);
195 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
200 UCListIter n = d->chans.find(chan);
201 if (n != d->chans.end())
203 if (n->second & MASK)
207 n->second = n->second | MASK;
211 n->first->AddOppedUser(d);
214 n->first->AddHalfoppedUser(d);
217 n->first->AddVoicedUser(d);
225 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
230 UCListIter n = d->chans.find(chan);
231 if (n != d->chans.end())
233 if ((n->second & MASK) == 0)
241 n->first->DelOppedUser(d);
244 n->first->DelHalfoppedUser(d);
247 n->first->DelVoicedUser(d);
255 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
259 /* Display channel's current mode string */
260 user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261 user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
266 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
268 user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
272 if ((targetuser == user) || (IS_OPER(user)))
274 /* Display user's current mode string */
275 user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
276 if (IS_OPER(targetuser))
277 user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
282 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
287 /* No such nick/channel */
288 user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
292 void ModeParser::Process(const char* const* parameters, int pcnt, User *user, bool servermode)
294 std::string target = parameters[0];
295 ModeType type = MODETYPE_USER;
296 unsigned char mask = 0;
297 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
298 User* targetuser = ServerInstance->FindNick(parameters[0]);
302 /* Special case for displaying the list for listmodes,
303 * e.g. MODE #chan b, or MODE #chan +b without a parameter
305 if ((targetchannel) && (pcnt == 2))
307 const char* mode = parameters[1];
308 int nonlistmodes_found = 0;
313 memset(&sent, 0, 256);
315 while (mode && *mode)
317 unsigned char mletter = *mode;
325 /* Ensure the user doesnt request the same mode twice,
326 * so they cant flood themselves off out of idiocy.
330 sent[mletter] = true;
338 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
341 if ((mh) && (mh->IsListMode()))
344 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
345 if (MOD_RESULT == ACR_DENY)
351 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
353 user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
354 mh->DisplayEmptyList(user, targetchannel);
358 /** See below for a description of what craq this is :D
360 unsigned char handler_id = (*mode - 65) | mask;
362 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
364 std::string dummyparam;
366 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
371 mh->DisplayList(user, targetchannel);
374 nonlistmodes_found++;
379 /* We didnt have any modes that were non-list, we can return here */
380 if (!nonlistmodes_found)
386 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
390 bool SkipAccessChecks = false;
394 type = MODETYPE_CHANNEL;
397 /* Extra security checks on channel modes
398 * (e.g. are they a (half)op?
401 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
403 /* We don't have halfop */
405 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
406 if (MOD_RESULT == ACR_DENY)
408 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
413 type = MODETYPE_USER;
415 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
417 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
423 /* No such nick/channel */
424 user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
428 std::string mode_sequence = parameters[1];
429 std::string parameter;
430 std::ostringstream parameter_list;
431 std::string output_sequence;
432 bool adding = true, state_change = false;
433 unsigned char handler_id = 0;
434 int parameter_counter = 2; /* Index of first parameter */
435 int parameter_count = 0;
436 bool last_successful_state_change = false;
438 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
439 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
440 mode_sequence.insert(0, "+");
442 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
444 unsigned char modechar = *letter;
449 * For + and - mode characters, we don't just stick the character into the output sequence.
450 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
451 * appearing in the output sequence, we store a flag which says there was a state change,
452 * which is set on any + or -, however, the + or - that we finish on is only appended to
453 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
456 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
457 * however, will allow the + if it is the first item in the sequence, regardless.
459 if ((!adding) || (!output_sequence.length()))
462 if (!output_sequence.length())
463 last_successful_state_change = false;
467 if ((adding) || (!output_sequence.length()))
470 if (!output_sequence.length())
471 last_successful_state_change = true;
477 * Watch carefully for the sleight of hand trick.
478 * 65 is the ascii value of 'A'. We take this from
479 * the char we're looking at to get a number between
480 * 1 and 127. We then logic-or it to get the hashed
481 * position, dependent on wether its a channel or
482 * a user mode. This is a little stranger, but a lot
483 * faster, than using a map of pairs.
485 handler_id = (modechar - 65) | mask;
487 if (modehandlers[handler_id])
491 if (modehandlers[handler_id]->GetModeType() == type)
495 if (modehandlers[handler_id]->GetNumParams(adding))
497 /* This mode expects a parameter, do we have any parameters left in our list to use? */
498 if (parameter_counter < pcnt)
500 parameter = parameters[parameter_counter++];
503 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
508 /* No parameter, continue to the next mode */
512 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
516 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
519 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
522 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
524 ServerInstance->Logs->Log("MODE", DEBUG,"Enter minimum prefix check");
525 /* Check access to this mode character */
526 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
528 char needed = modehandlers[handler_id]->GetNeededPrefix();
529 ModeHandler* prefixmode = FindPrefix(needed);
530 ServerInstance->Logs->Log("MODE", DEBUG,"Needed prefix: %c", needed);
532 /* If the mode defined by the handler is not '\0', but the handler for it
533 * cannot be found, they probably dont have the right module loaded to implement
534 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
535 * Revert to checking against the minimum core prefix, '%'.
537 if (needed && !prefixmode)
538 prefixmode = FindPrefix('%');
540 unsigned int neededrank = prefixmode->GetPrefixRank();
541 /* Compare our rank on the channel against the rank of the required prefix,
542 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
543 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
544 * first, so we don't need to iterate, we just look up the first instead.
546 std::string modestring = targetchannel->GetAllPrefixChars(user);
547 char ml = (modestring.empty() ? '\0' : modestring[0]);
548 ModeHandler* ourmode = FindPrefix(ml);
549 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
552 user->WriteServ("482 %s %s :You must have channel privilege %c or above to %sset channel mode %c",
553 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
559 bool had_parameter = !parameter.empty();
561 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
563 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
568 /* A module whacked the parameter completely, and there was one. abort. */
569 if ((had_parameter) && (parameter.empty()))
579 /* It's an oper only mode, check if theyre an oper. If they arent,
580 * eat any parameter that came with the mode, and continue to next
582 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
584 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
585 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
586 modehandlers[handler_id]->GetModeChar());
590 /* Call the handler for the mode */
591 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
593 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
595 /* The handler nuked the parameter and they are supposed to have one.
596 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
597 * so we bail to the next mode character.
602 if (ma == MODEACTION_ALLOW)
604 /* We're about to output a valid mode letter - was there previously a pending state-change? */
607 if (adding != last_successful_state_change)
608 output_sequence.append(adding ? "+" : "-");
609 last_successful_state_change = adding;
612 /* Add the mode letter */
613 output_sequence.push_back(modechar);
615 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
617 /* Is there a valid parameter for this mode? If so add it to the parameter list */
618 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
620 parameter_list << " " << parameter;
622 /* Does this mode have a prefix? */
623 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
625 User* user_to_prefix = ServerInstance->FindNick(parameter);
627 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
628 modehandlers[handler_id]->GetPrefixRank(), adding);
632 /* Call all the AfterMode events in the mode watchers for this mode */
633 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
634 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
636 /* Reset the state change flag */
637 state_change = false;
639 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
640 || (parameter_count > MAXMODES))
642 /* We cant have a mode sequence this long */
643 letter = mode_sequence.end() - 1;
651 /* No mode handler? Unknown mode character then. */
652 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
658 /* Was there at least one valid mode in the sequence? */
659 if (!output_sequence.empty())
663 if (type == MODETYPE_CHANNEL)
665 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
666 this->LastParse = targetchannel->name;
670 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
671 this->LastParse = targetuser->nick;
676 if (type == MODETYPE_CHANNEL)
678 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
679 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
680 this->LastParse = targetchannel->name;
684 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
685 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
686 this->LastParse = targetuser->nick;
690 LastParse.append(" ");
691 LastParse.append(output_sequence);
692 LastParse.append(parameter_list.str());
697 const std::string& ModeParser::GetLastParse()
702 void ModeParser::CleanMask(std::string &mask)
704 std::string::size_type pos_of_pling = mask.find_first_of('!');
705 std::string::size_type pos_of_at = mask.find_first_of('@');
706 std::string::size_type pos_of_dot = mask.find_first_of('.');
707 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
709 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
711 /* Just a nick, or just a host */
712 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
714 /* It has no '.' in it, it must be a nick. */
719 /* Got a dot in it? Has to be a host */
720 mask = "*!*@" + mask;
723 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
725 /* Has an @ but no !, its a user@host */
728 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
730 /* Has a ! but no @, it must be a nick!ident */
735 bool ModeParser::AddMode(ModeHandler* mh)
737 unsigned char mask = 0;
738 unsigned char pos = 0;
740 /* Yes, i know, this might let people declare modes like '_' or '^'.
741 * If they do that, thats their problem, and if i ever EVER see an
742 * official InspIRCd developer do that, i'll beat them with a paddle!
744 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
747 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
748 * A mode prefix of ':' will fuck up both server to server, and client to server.
749 * A mode prefix of '#' will mess up /whois and /privmsg
751 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
754 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
755 pos = (mh->GetModeChar()-65) | mask;
757 if (modehandlers[pos])
760 modehandlers[pos] = mh;
764 bool ModeParser::DelMode(ModeHandler* mh)
766 unsigned char mask = 0;
767 unsigned char pos = 0;
769 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
772 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
773 pos = (mh->GetModeChar()-65) | mask;
775 if (!modehandlers[pos])
778 switch (mh->GetModeType())
781 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
783 mh->RemoveMode(i->second);
786 case MODETYPE_CHANNEL:
787 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
789 mh->RemoveMode(i->second);
794 modehandlers[pos] = NULL;
799 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
801 unsigned char mask = 0;
802 unsigned char pos = 0;
804 if ((modeletter < 'A') || (modeletter > 'z'))
807 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
808 pos = (modeletter-65) | mask;
810 return modehandlers[pos];
813 std::string ModeParser::UserModeList()
818 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
820 unsigned char pos = (mode-65) | MASK_USER;
822 if (modehandlers[pos])
823 modestr[pointer++] = mode;
825 modestr[pointer++] = 0;
829 std::string ModeParser::ChannelModeList()
834 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
836 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
839 unsigned char pos = (mode-65) | MASK_CHANNEL;
841 if (modehandlers[pos])
842 modestr[pointer++] = mode;
844 modestr[pointer++] = 0;
848 std::string ModeParser::ParaModeList()
853 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
855 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
858 unsigned char pos = (mode-65) | MASK_CHANNEL;
860 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
861 modestr[pointer++] = mode;
863 modestr[pointer++] = 0;
867 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
869 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
871 unsigned char pos = (mode-65) | MASK_CHANNEL;
873 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
875 return modehandlers[pos];
881 std::string ModeParser::ModeString(User* user, Channel* channel)
886 if (!channel || !user)
889 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
891 unsigned char pos = (mode-65) | MASK_CHANNEL;
892 ModeHandler* mh = modehandlers[pos];
893 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
896 ret = mh->ModeSet(NULL, user, channel, user->nick);
897 if ((ret.first) && (ret.second == user->nick))
900 pars.append(user->nick);
901 types.push_back(mh->GetModeChar());
909 std::string ModeParser::ChanModes()
911 std::string type1; /* Listmodes EXCEPT those with a prefix */
912 std::string type2; /* Modes that take a param when adding or removing */
913 std::string type3; /* Modes that only take a param when adding */
914 std::string type4; /* Modes that dont take a param */
916 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
918 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
921 unsigned char pos = (mode-65) | MASK_CHANNEL;
922 /* One parameter when adding */
923 if (modehandlers[pos])
925 if (modehandlers[pos]->GetNumParams(true))
927 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
929 type1 += modehandlers[pos]->GetModeChar();
933 /* ... and one parameter when removing */
934 if (modehandlers[pos]->GetNumParams(false))
936 /* But not a list mode */
937 if (!modehandlers[pos]->GetPrefix())
939 type2 += modehandlers[pos]->GetModeChar();
944 /* No parameters when removing */
945 type3 += modehandlers[pos]->GetModeChar();
951 type4 += modehandlers[pos]->GetModeChar();
957 return type1 + "," + type2 + "," + type3 + "," + type4;
960 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
962 return one.second > two.second;
965 std::string ModeParser::BuildPrefixes()
967 std::string mletters;
968 std::string mprefixes;
970 std::map<char,char> prefix_to_mode;
972 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
974 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
977 unsigned char pos = (mode-65) | MASK_CHANNEL;
979 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
981 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
982 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
986 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
988 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
990 mletters = mletters + n->first;
991 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
994 return "(" + mprefixes + ")" + mletters;
997 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
999 unsigned char mask = 0;
1000 unsigned char pos = 0;
1005 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1008 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1009 pos = (mw->GetModeChar()-65) | mask;
1011 modewatchers[pos].push_back(mw);
1016 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1018 unsigned char mask = 0;
1019 unsigned char pos = 0;
1024 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1027 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1028 pos = (mw->GetModeChar()-65) | mask;
1030 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1032 if (a == modewatchers[pos].end())
1037 modewatchers[pos].erase(a);
1042 /** This default implementation can remove simple user modes
1044 void ModeHandler::RemoveMode(User* user)
1046 char moderemove[MAXBUF];
1047 const char* parameters[] = { user->nick, moderemove };
1049 if (user->IsModeSet(this->GetModeChar()))
1051 sprintf(moderemove,"-%c",this->GetModeChar());
1052 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1056 /** This default implementation can remove simple channel modes
1059 void ModeHandler::RemoveMode(Channel* channel)
1061 char moderemove[MAXBUF];
1062 const char* parameters[] = { channel->name, moderemove };
1064 if (channel->IsModeSet(this->GetModeChar()))
1066 sprintf(moderemove,"-%c",this->GetModeChar());
1067 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1071 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1073 ModeHandler* modes[] =
1075 new ModeChannelSecret(Instance),
1076 new ModeChannelPrivate(Instance),
1077 new ModeChannelModerated(Instance),
1078 new ModeChannelTopicOps(Instance),
1079 new ModeChannelNoExternal(Instance),
1080 new ModeChannelInviteOnly(Instance),
1081 new ModeChannelKey(Instance),
1082 new ModeChannelLimit(Instance),
1083 new ModeChannelBan(Instance),
1084 new ModeChannelOp(Instance),
1085 new ModeChannelHalfOp(Instance),
1086 new ModeChannelVoice(Instance),
1087 new ModeUserServerNotice(Instance),
1088 new ModeUserWallops(Instance),
1089 new ModeUserInvisible(Instance),
1090 new ModeUserOperator(Instance),
1091 new ModeUserServerNoticeMask(Instance),
1095 /* Clear mode list */
1096 memset(modehandlers, 0, sizeof(modehandlers));
1097 memset(modewatchers, 0, sizeof(modewatchers));
1099 /* Last parse string */
1102 /* Initialise the RFC mode letters */
1103 for (int index = 0; modes[index]; index++)
1104 this->AddMode(modes[index]);