X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmode.cpp;h=db120cfe587a59be26b676815fbc44f4002b8f90;hb=d7ac76bed17ac6c9f0884f5e37d01f075243a3b8;hp=11fecf06adf65fb67c9920088552257433e95f1c;hpb=02ccf82812a189c46d0495580b7d96ada34851b5;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/mode.cpp b/src/mode.cpp index 11fecf06a..db120cfe5 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -185,7 +185,6 @@ const char* ModeParser::Grant(userrec *d,chanrec *chan,int MASK) { if (n->second & MASK) { - ServerInstance->Log(DEBUG,"User already has privilage %d (privset: %d)", MASK, n->second); return ""; } n->second = n->second | MASK; @@ -201,13 +200,8 @@ const char* ModeParser::Grant(userrec *d,chanrec *chan,int MASK) n->first->AddVoicedUser(d); break; } - ServerInstance->Log(DEBUG,"grant: %s %s",n->first->name,d->nick); return d->nick; } - else - { - ServerInstance->Log(DEBUG,"Channel %s not in users joined list", chan->name); - } return ""; } @@ -236,7 +230,6 @@ const char* ModeParser::Revoke(userrec *d,chanrec *chan,int MASK) n->first->DelVoicedUser(d); break; } - ServerInstance->Log(DEBUG,"revoke: %s %s",n->first->name,d->nick); return d->nick; } return ""; @@ -253,11 +246,17 @@ void ModeParser::DisplayCurrentModes(userrec *user, userrec* targetuser, chanrec } else if (targetuser) { - if ((targetuser == user) || (*user->oper)) + if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user)) + { + user->WriteServ("401 %s %s :No such nick/channel",user->nick, text); + return; + } + + if ((targetuser == user) || (IS_OPER(user))) { /* Display user's current mode string */ user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes()); - if (*targetuser->oper) + if (IS_OPER(targetuser)) user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks()); return; } @@ -281,46 +280,87 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool chanrec* targetchannel = ServerInstance->FindChan(parameters[0]); userrec* targetuser = ServerInstance->FindNick(parameters[0]); - ServerInstance->Log(DEBUG,"ModeParser::Process start: pcnt=%d",pcnt); - - LastParse = ""; + LastParse.clear(); /* Special case for displaying the list for listmodes, * e.g. MODE #chan b, or MODE #chan +b without a parameter */ if ((targetchannel) && (pcnt == 2)) { - ServerInstance->Log(DEBUG,"Spool list"); const char* mode = parameters[1]; + int nonlistmodes_found = 0; + bool sent[256]; + + mask = MASK_CHANNEL; + memset(&sent, 0, 256); + while (mode && *mode) { + unsigned char mletter = *mode; + if (*mode == '+') { mode++; continue; } + /* Ensure the user doesnt request the same mode twice, + * so they cant flood themselves off out of idiocy. + */ + if (!sent[mletter]) + { + sent[mletter] = true; + } + else + { + mode++; + continue; + } + ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL); + bool display = true; if ((mh) && (mh->IsListMode())) { - mh->DisplayList(user, targetchannel); + if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP)) + { + user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++); + continue; + } + + /** See below for a description of what craq this is :D + */ + unsigned char handler_id = (*mode - 65) | mask; + + for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + { + std::string dummyparam; + + if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL))) + display = false; + } + + if (display) + mh->DisplayList(user, targetchannel); } + else + nonlistmodes_found++; mode++; } + + /* We didnt have any modes that were non-list, we can return here */ + if (!nonlistmodes_found) + return; } if (pcnt == 1) { - ServerInstance->Log(DEBUG,"Mode list request"); this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]); } else if (pcnt > 1) { - ServerInstance->Log(DEBUG,"More than one parameter"); - if (targetchannel) { type = MODETYPE_CHANNEL; @@ -333,8 +373,6 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP)) { /* We don't have halfop */ - ServerInstance->Log(DEBUG,"The user is not a halfop or above, checking other reasons for being able to set the modes"); - int MOD_RESULT = 0; FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE)); if (MOD_RESULT == ACR_DENY) @@ -373,13 +411,14 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool } std::string mode_sequence = parameters[1]; - std::string parameter = ""; + std::string parameter; std::ostringstream parameter_list; - std::string output_sequence = ""; + std::string output_sequence; bool adding = true, state_change = false; unsigned char handler_id = 0; int parameter_counter = 2; /* Index of first parameter */ int parameter_count = 0; + bool last_successful_state_change = false; /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */ if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-')) @@ -405,12 +444,16 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool if ((!adding) || (!output_sequence.length())) state_change = true; adding = true; + if (!output_sequence.length()) + last_successful_state_change = false; continue; break; case '-': if ((adding) || (!output_sequence.length())) state_change = true; adding = false; + if (!output_sequence.length()) + last_successful_state_change = true; continue; break; default: @@ -430,38 +473,67 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool { bool abort = false; - for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) - { - if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == MODEACTION_DENY) - abort = true; - } - if ((modehandlers[handler_id]->GetModeType() == type) && (!abort)) + if (modehandlers[handler_id]->GetModeType() == type) { if (modehandlers[handler_id]->GetNumParams(adding)) { /* This mode expects a parameter, do we have any parameters left in our list to use? */ if (parameter_counter < pcnt) { - ServerInstance->Log(DEBUG,"parameter_counter = %d, pcnt = %d", parameter_counter, pcnt); parameter = parameters[parameter_counter++]; /* Yerk, invalid! */ if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos)) - parameter = ""; + parameter.clear(); } else { /* No parameter, continue to the next mode */ continue; } + + bool had_parameter = !parameter.empty(); + + for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + { + if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false) + { + abort = true; + break; + } + /* A module whacked the parameter completely, and there was one. abort. */ + if ((had_parameter) && (parameter.empty())) + { + abort = true; + break; + } + } + + if (abort) + continue; + } + else + { + /* Fix by brain: mode watchers not being called for parameterless modes */ + for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++) + { + if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false) + { + abort = true; + break; + } + } + + if (abort) + continue; } /* It's an oper only mode, check if theyre an oper. If they arent, * eat any parameter that came with the mode, and continue to next */ - if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!*user->oper)) + if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user))) { - user->WriteServ("481 %s :Permission Denied- Only IRC operators may %sset %s mode %c", user->nick, + user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick, adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modehandlers[handler_id]->GetModeChar()); continue; @@ -470,7 +542,7 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool /* Call the handler for the mode */ ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding); - if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter == "")) + if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty())) { /* The handler nuked the parameter and they are supposed to have one. * We CANT continue now, even if they actually returned MODEACTION_ALLOW, @@ -483,13 +555,17 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool { /* We're about to output a valid mode letter - was there previously a pending state-change? */ if (state_change) - output_sequence.append(adding ? "+" : "-"); + { + if (adding != last_successful_state_change) + output_sequence.append(adding ? "+" : "-"); + last_successful_state_change = adding; + } /* Add the mode letter */ output_sequence.push_back(modechar); /* Is there a valid parameter for this mode? If so add it to the parameter list */ - if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter != "")) + if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty())) { parameter_list << " " << parameter; parameter_count++; @@ -528,8 +604,9 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool break; } } + /* Was there at least one valid mode in the sequence? */ - if (output_sequence != "") + if (!output_sequence.empty()) { if (servermode) { @@ -548,7 +625,6 @@ void ModeParser::Process(const char** parameters, int pcnt, userrec *user, bool { if (type == MODETYPE_CHANNEL) { - ServerInstance->Log(DEBUG,"Write output sequence and parameters to channel: %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str()); targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str()); FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str())); this->LastParse = targetchannel->name; @@ -615,7 +691,7 @@ bool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter) * If they do that, thats their problem, and if i ever EVER see an * official InspIRCd developer do that, i'll beat them with a paddle! */ - if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z')) + if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126)) return false; /* A mode prefix of ',' is not acceptable, it would fuck up server to server. @@ -632,7 +708,6 @@ bool ModeParser::AddMode(ModeHandler* mh, unsigned const char modeletter) return false; modehandlers[pos] = mh; - ServerInstance->Log(DEBUG,"ModeParser::AddMode: added mode %c",mh->GetModeChar()); return true; } @@ -708,6 +783,9 @@ std::string ModeParser::ChannelModeList() for (unsigned char mode = 'A'; mode <= 'z'; mode++) { + if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h')) + continue; + unsigned char pos = (mode-65) | MASK_CHANNEL; if (modehandlers[pos]) @@ -724,6 +802,9 @@ std::string ModeParser::ParaModeList() for (unsigned char mode = 'A'; mode <= 'z'; mode++) { + if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h')) + continue; + unsigned char pos = (mode-65) | MASK_CHANNEL; if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true))) @@ -784,6 +865,9 @@ std::string ModeParser::ChanModes() for (unsigned char mode = 'A'; mode <= 'z'; mode++) { + if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h')) + continue; + unsigned char pos = (mode-65) | MASK_CHANNEL; /* One parameter when adding */ if (modehandlers[pos]) @@ -823,20 +907,23 @@ std::string ModeParser::ChanModes() return type1 + "," + type2 + "," + type3 + "," + type4; } -bool ModeParser::PrefixComparison(const prefixtype one, const prefixtype two) +bool ModeParser::PrefixComparison(prefixtype one, prefixtype two) { return one.second > two.second; } std::string ModeParser::BuildPrefixes() { - std::string mletters = ""; - std::string mprefixes = ""; + std::string mletters; + std::string mprefixes; pfxcontainer pfx; std::map prefix_to_mode; for (unsigned char mode = 'A'; mode <= 'z'; mode++) { + if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h')) + continue; + unsigned char pos = (mode-65) | MASK_CHANNEL; if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix())) @@ -872,7 +959,6 @@ bool ModeParser::AddModeWatcher(ModeWatcher* mw) pos = (mw->GetModeChar()-65) | mask; modewatchers[pos].push_back(mw); - ServerInstance->Log(DEBUG,"ModeParser::AddModeWatcher: watching mode %c",mw->GetModeChar()); return true; } @@ -895,12 +981,10 @@ bool ModeParser::DelModeWatcher(ModeWatcher* mw) if (a == modewatchers[pos].end()) { - ServerInstance->Log(DEBUG, "ModeParser::DelModeWatcher: Couldn't find watcher for mode %c in list", mw->GetModeChar()); return false; } modewatchers[pos].erase(a); - ServerInstance->Log(DEBUG,"ModeParser::DelModeWatcher: stopped watching mode %c",mw->GetModeChar()); return true; } @@ -942,37 +1026,41 @@ void ModeHandler::RemoveMode(chanrec* channel) ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance) { + struct Initializer + { + char modechar; + ModeHandler* handler; + }; + + Initializer modes[] = { + { 's', new ModeChannelSecret(Instance) }, + { 'p', new ModeChannelPrivate(Instance) }, + { 'm', new ModeChannelModerated(Instance) }, + { 't', new ModeChannelTopicOps(Instance) }, + { 'n', new ModeChannelNoExternal(Instance) }, + { 'i', new ModeChannelInviteOnly(Instance) }, + { 'k', new ModeChannelKey(Instance) }, + { 'l', new ModeChannelLimit(Instance) }, + { 'b', new ModeChannelBan(Instance) }, + { 'o', new ModeChannelOp(Instance) }, + { 'h', new ModeChannelHalfOp(Instance) }, + { 'v', new ModeChannelVoice(Instance) }, + { 's', new ModeUserServerNotice(Instance) }, + { 'w', new ModeUserWallops(Instance) }, + { 'i', new ModeUserInvisible(Instance) }, + { 'o', new ModeUserOperator(Instance) }, + { 'n', new ModeUserServerNoticeMask(Instance) }, + { 0, NULL } + }; + /* Clear mode list */ memset(modehandlers, 0, sizeof(modehandlers)); memset(modewatchers, 0, sizeof(modewatchers)); /* Last parse string */ - LastParse = ""; + LastParse.clear(); /* Initialise the RFC mode letters */ - - /* Start with channel simple modes, no params */ - this->AddMode(new ModeChannelSecret(Instance), 's'); - this->AddMode(new ModeChannelPrivate(Instance), 'p'); - this->AddMode(new ModeChannelModerated(Instance), 'm'); - this->AddMode(new ModeChannelTopicOps(Instance), 't'); - this->AddMode(new ModeChannelNoExternal(Instance), 'n'); - this->AddMode(new ModeChannelInviteOnly(Instance), 'i'); - - /* Cannel modes with params */ - this->AddMode(new ModeChannelKey(Instance), 'k'); - this->AddMode(new ModeChannelLimit(Instance), 'l'); - - /* Channel listmodes */ - this->AddMode(new ModeChannelBan(Instance), 'b'); - this->AddMode(new ModeChannelOp(Instance), 'o'); - this->AddMode(new ModeChannelHalfOp(Instance), 'h'); - this->AddMode(new ModeChannelVoice(Instance), 'v'); - - /* Now for usermodes */ - this->AddMode(new ModeUserServerNotice(Instance), 's'); - this->AddMode(new ModeUserWallops(Instance), 'w'); - this->AddMode(new ModeUserInvisible(Instance), 'i'); - this->AddMode(new ModeUserOperator(Instance), 'o'); - this->AddMode(new ModeUserServerNoticeMask(Instance), 'n'); + for (int index = 0; modes[index].modechar; index++) + this->AddMode(modes[index].handler, modes[index].modechar); }