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->Log(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)
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)
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
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** 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]);
392 type = MODETYPE_CHANNEL;
395 /* Extra security checks on channel modes
396 * (e.g. are they a (half)op?
399 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
401 /* We don't have halfop */
403 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
404 if (MOD_RESULT == ACR_DENY)
410 type = MODETYPE_USER;
412 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
414 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
420 /* No such nick/channel */
421 user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
425 std::string mode_sequence = parameters[1];
426 std::string parameter;
427 std::ostringstream parameter_list;
428 std::string output_sequence;
429 bool adding = true, state_change = false;
430 unsigned char handler_id = 0;
431 int parameter_counter = 2; /* Index of first parameter */
432 int parameter_count = 0;
433 bool last_successful_state_change = false;
435 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
436 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
437 mode_sequence.insert(0, "+");
439 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
441 unsigned char modechar = *letter;
446 * For + and - mode characters, we don't just stick the character into the output sequence.
447 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
448 * appearing in the output sequence, we store a flag which says there was a state change,
449 * which is set on any + or -, however, the + or - that we finish on is only appended to
450 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
453 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
454 * however, will allow the + if it is the first item in the sequence, regardless.
456 if ((!adding) || (!output_sequence.length()))
459 if (!output_sequence.length())
460 last_successful_state_change = false;
464 if ((adding) || (!output_sequence.length()))
467 if (!output_sequence.length())
468 last_successful_state_change = true;
474 * Watch carefully for the sleight of hand trick.
475 * 65 is the ascii value of 'A'. We take this from
476 * the char we're looking at to get a number between
477 * 1 and 127. We then logic-or it to get the hashed
478 * position, dependent on wether its a channel or
479 * a user mode. This is a little stranger, but a lot
480 * faster, than using a map of pairs.
482 handler_id = (modechar - 65) | mask;
484 if (modehandlers[handler_id])
488 if (modehandlers[handler_id]->GetModeType() == type)
492 if (modehandlers[handler_id]->GetNumParams(adding))
494 /* This mode expects a parameter, do we have any parameters left in our list to use? */
495 if (parameter_counter < pcnt)
497 parameter = parameters[parameter_counter++];
500 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
505 /* No parameter, continue to the next mode */
509 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1));
513 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0));
516 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
519 if (IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
521 ServerInstance->Log(DEBUG,"Enter minimum prefix check");
522 /* Check access to this mode character */
523 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
525 char needed = modehandlers[handler_id]->GetNeededPrefix();
526 ModeHandler* prefixmode = FindPrefix(needed);
527 ServerInstance->Log(DEBUG,"Needed prefix: %c", needed);
530 unsigned int neededrank = prefixmode->GetPrefixRank();
531 /* Compare our rank on the channel against the rank of the required prefix,
532 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
533 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
534 * first, so we don't need to iterate, we just look up the first instead.
536 std::string modestring = targetchannel->GetAllPrefixChars(user);
537 char ml = (modestring.empty() ? '\0' : modestring[0]);
538 ModeHandler* ourmode = FindPrefix(ml);
539 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
542 user->WriteServ("482 %s %s :You require channel privilege %c or above to %sset channel mode %c",
543 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
550 bool had_parameter = !parameter.empty();
552 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
554 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
559 /* A module whacked the parameter completely, and there was one. abort. */
560 if ((had_parameter) && (parameter.empty()))
570 /* It's an oper only mode, check if theyre an oper. If they arent,
571 * eat any parameter that came with the mode, and continue to next
573 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
575 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
576 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
577 modehandlers[handler_id]->GetModeChar());
581 /* Call the handler for the mode */
582 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
584 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
586 /* The handler nuked the parameter and they are supposed to have one.
587 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
588 * so we bail to the next mode character.
593 if (ma == MODEACTION_ALLOW)
595 /* We're about to output a valid mode letter - was there previously a pending state-change? */
598 if (adding != last_successful_state_change)
599 output_sequence.append(adding ? "+" : "-");
600 last_successful_state_change = adding;
603 /* Add the mode letter */
604 output_sequence.push_back(modechar);
606 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
608 /* Is there a valid parameter for this mode? If so add it to the parameter list */
609 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
611 parameter_list << " " << parameter;
613 /* Does this mode have a prefix? */
614 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
616 User* user_to_prefix = ServerInstance->FindNick(parameter);
618 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
619 modehandlers[handler_id]->GetPrefixRank(), adding);
623 /* Call all the AfterMode events in the mode watchers for this mode */
624 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
625 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
627 /* Reset the state change flag */
628 state_change = false;
630 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
631 || (parameter_count > MAXMODES))
633 /* We cant have a mode sequence this long */
634 letter = mode_sequence.end() - 1;
642 /* No mode handler? Unknown mode character then. */
643 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
649 /* Was there at least one valid mode in the sequence? */
650 if (!output_sequence.empty())
654 if (type == MODETYPE_CHANNEL)
656 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
657 this->LastParse = targetchannel->name;
661 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
662 this->LastParse = targetuser->nick;
667 if (type == MODETYPE_CHANNEL)
669 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
670 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
671 this->LastParse = targetchannel->name;
675 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
676 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
677 this->LastParse = targetuser->nick;
681 LastParse.append(" ");
682 LastParse.append(output_sequence);
683 LastParse.append(parameter_list.str());
688 const std::string& ModeParser::GetLastParse()
693 void ModeParser::CleanMask(std::string &mask)
695 std::string::size_type pos_of_pling = mask.find_first_of('!');
696 std::string::size_type pos_of_at = mask.find_first_of('@');
697 std::string::size_type pos_of_dot = mask.find_first_of('.');
698 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
700 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
702 /* Just a nick, or just a host */
703 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
705 /* It has no '.' in it, it must be a nick. */
710 /* Got a dot in it? Has to be a host */
711 mask = "*!*@" + mask;
714 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
716 /* Has an @ but no !, its a user@host */
719 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
721 /* Has a ! but no @, it must be a nick!ident */
726 bool ModeParser::AddMode(ModeHandler* mh)
728 unsigned char mask = 0;
729 unsigned char pos = 0;
731 /* Yes, i know, this might let people declare modes like '_' or '^'.
732 * If they do that, thats their problem, and if i ever EVER see an
733 * official InspIRCd developer do that, i'll beat them with a paddle!
735 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
738 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
739 * A mode prefix of ':' will fuck up both server to server, and client to server.
740 * A mode prefix of '#' will mess up /whois and /privmsg
742 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
745 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
746 pos = (mh->GetModeChar()-65) | mask;
748 if (modehandlers[pos])
751 modehandlers[pos] = mh;
755 bool ModeParser::DelMode(ModeHandler* mh)
757 unsigned char mask = 0;
758 unsigned char pos = 0;
760 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
763 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
764 pos = (mh->GetModeChar()-65) | mask;
766 if (!modehandlers[pos])
769 switch (mh->GetModeType())
772 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
774 mh->RemoveMode(i->second);
777 case MODETYPE_CHANNEL:
778 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
780 mh->RemoveMode(i->second);
785 modehandlers[pos] = NULL;
790 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
792 unsigned char mask = 0;
793 unsigned char pos = 0;
795 if ((modeletter < 'A') || (modeletter > 'z'))
798 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
799 pos = (modeletter-65) | mask;
801 return modehandlers[pos];
804 std::string ModeParser::UserModeList()
809 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
811 unsigned char pos = (mode-65) | MASK_USER;
813 if (modehandlers[pos])
814 modestr[pointer++] = mode;
816 modestr[pointer++] = 0;
820 std::string ModeParser::ChannelModeList()
825 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
827 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
830 unsigned char pos = (mode-65) | MASK_CHANNEL;
832 if (modehandlers[pos])
833 modestr[pointer++] = mode;
835 modestr[pointer++] = 0;
839 std::string ModeParser::ParaModeList()
844 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
846 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
849 unsigned char pos = (mode-65) | MASK_CHANNEL;
851 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
852 modestr[pointer++] = mode;
854 modestr[pointer++] = 0;
858 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
860 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
862 unsigned char pos = (mode-65) | MASK_CHANNEL;
864 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
866 return modehandlers[pos];
872 std::string ModeParser::ModeString(User* user, Channel* channel)
877 if (!channel || !user)
880 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
882 unsigned char pos = (mode-65) | MASK_CHANNEL;
883 ModeHandler* mh = modehandlers[pos];
884 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
887 ret = mh->ModeSet(NULL, user, channel, user->nick);
888 if ((ret.first) && (ret.second == user->nick))
891 pars.append(user->nick);
892 types.push_back(mh->GetModeChar());
900 std::string ModeParser::ChanModes()
902 std::string type1; /* Listmodes EXCEPT those with a prefix */
903 std::string type2; /* Modes that take a param when adding or removing */
904 std::string type3; /* Modes that only take a param when adding */
905 std::string type4; /* Modes that dont take a param */
907 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
909 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
912 unsigned char pos = (mode-65) | MASK_CHANNEL;
913 /* One parameter when adding */
914 if (modehandlers[pos])
916 if (modehandlers[pos]->GetNumParams(true))
918 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
920 type1 += modehandlers[pos]->GetModeChar();
924 /* ... and one parameter when removing */
925 if (modehandlers[pos]->GetNumParams(false))
927 /* But not a list mode */
928 if (!modehandlers[pos]->GetPrefix())
930 type2 += modehandlers[pos]->GetModeChar();
935 /* No parameters when removing */
936 type3 += modehandlers[pos]->GetModeChar();
942 type4 += modehandlers[pos]->GetModeChar();
948 return type1 + "," + type2 + "," + type3 + "," + type4;
951 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
953 return one.second > two.second;
956 std::string ModeParser::BuildPrefixes()
958 std::string mletters;
959 std::string mprefixes;
961 std::map<char,char> prefix_to_mode;
963 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
965 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
968 unsigned char pos = (mode-65) | MASK_CHANNEL;
970 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
972 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
973 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
977 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
979 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
981 mletters = mletters + n->first;
982 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
985 return "(" + mprefixes + ")" + mletters;
988 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
990 unsigned char mask = 0;
991 unsigned char pos = 0;
996 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
999 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1000 pos = (mw->GetModeChar()-65) | mask;
1002 modewatchers[pos].push_back(mw);
1007 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1009 unsigned char mask = 0;
1010 unsigned char pos = 0;
1015 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1018 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1019 pos = (mw->GetModeChar()-65) | mask;
1021 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1023 if (a == modewatchers[pos].end())
1028 modewatchers[pos].erase(a);
1033 /** This default implementation can remove simple user modes
1035 void ModeHandler::RemoveMode(User* user)
1037 char moderemove[MAXBUF];
1038 const char* parameters[] = { user->nick, moderemove };
1040 if (user->IsModeSet(this->GetModeChar()))
1042 sprintf(moderemove,"-%c",this->GetModeChar());
1043 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1047 /** This default implementation can remove simple channel modes
1050 void ModeHandler::RemoveMode(Channel* channel)
1052 char moderemove[MAXBUF];
1053 const char* parameters[] = { channel->name, moderemove };
1055 if (channel->IsModeSet(this->GetModeChar()))
1057 sprintf(moderemove,"-%c",this->GetModeChar());
1058 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1062 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1064 ModeHandler* modes[] =
1066 new ModeChannelSecret(Instance),
1067 new ModeChannelPrivate(Instance),
1068 new ModeChannelModerated(Instance),
1069 new ModeChannelTopicOps(Instance),
1070 new ModeChannelNoExternal(Instance),
1071 new ModeChannelInviteOnly(Instance),
1072 new ModeChannelKey(Instance),
1073 new ModeChannelLimit(Instance),
1074 new ModeChannelBan(Instance),
1075 new ModeChannelOp(Instance),
1076 new ModeChannelHalfOp(Instance),
1077 new ModeChannelVoice(Instance),
1078 new ModeUserServerNotice(Instance),
1079 new ModeUserWallops(Instance),
1080 new ModeUserInvisible(Instance),
1081 new ModeUserOperator(Instance),
1082 new ModeUserServerNoticeMask(Instance),
1086 /* Clear mode list */
1087 memset(modehandlers, 0, sizeof(modehandlers));
1088 memset(modewatchers, 0, sizeof(modewatchers));
1090 /* Last parse string */
1093 /* Initialise the RFC mode letters */
1094 for (int index = 0; modes[index]; index++)
1095 this->AddMode(modes[index]);