void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops) { std::string Parent = Utils->TreeRoot->GetName(); if (Current->GetParent()) { Parent = Current->GetParent()->GetName(); } for (unsigned int q = 0; q < Current->ChildCount(); q++) { if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) { if (IS_OPER(user)) { ShowLinks(Current->GetChild(q),user,hops+1); } } else { ShowLinks(Current->GetChild(q),user,hops+1); } } /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */ if ((Utils->HideULines) && (ServerInstance->ULine(Current->GetName().c_str())) && (!IS_OPER(user))) return; /* Or if the server is hidden and they're not an oper */ else if ((Current->Hidden) && (!IS_OPER(user))) return; user->WriteNumeric(364, "%s %s %s :%d %s", user->nick.c_str(),Current->GetName().c_str(), (Utils->FlatLinks && (!IS_OPER(user))) ? ServerInstance->Config->ServerName : Parent.c_str(), (Utils->FlatLinks && (!IS_OPER(user))) ? 0 : hops, Current->GetDesc().c_str()); }
virtual int OnKill(userrec* source, userrec* dest, const std::string &reason) { long dest_level = 0,source_level = 0; // oper killing an oper? if (IS_OPER(dest) && IS_OPER(source)) { for (int j =0; j < conf->Enumerate("type"); j++) { std::string typen = conf->ReadValue("type","name",j); if (!strcmp(typen.c_str(),dest->oper)) { dest_level = conf->ReadInteger("type","level",j,true); break; } } for (int k =0; k < conf->Enumerate("type"); k++) { std::string typen = conf->ReadValue("type","name",k); if (!strcmp(typen.c_str(),source->oper)) { source_level = conf->ReadInteger("type","level",k,true); break; } } if (dest_level > source_level) { ServerInstance->WriteOpers("Oper %s (level %d) attempted to /kill a higher oper: %s (level %d): Reason: %s",source->nick,source_level,dest->nick,dest_level,reason.c_str()); dest->WriteServ("NOTICE %s :Oper %s attempted to /kill you!",dest->nick,source->nick); source->WriteServ("481 %s :Permission Denied - Oper %s is a higher level than you",source->nick,dest->nick); return 1; } } return 0; }
virtual void OnWhois(User* source, User* dest) { if ((dest->IsModeSet('W')) && (source != dest)) { if (!ShowWhoisFromOpers && IS_OPER(source)) return; std::string wmsg = "*** "; wmsg += source->nick + " (" + source->ident + "@"; /* XXX HasPrivPermission doesn't work correctly for remote users */ if (IS_LOCAL(dest) && dest->HasPrivPermission("users/auspex")) { wmsg += source->host; } else { wmsg += source->dhost; } wmsg += ") did a /whois on you"; if (IS_LOCAL(dest)) { dest->WriteServ("NOTICE %s :%s", dest->nick.c_str(), wmsg.c_str()); } else { std::string msg = std::string("::") + dest->server + " NOTICE " + dest->nick + " :" + wmsg; ServerInstance->PI->PushToClient(dest, msg); } } }
void User::UnOper() { if (!IS_OPER(this)) return; /* * unset their oper type (what IS_OPER checks). * note, order is important - this must come before modes as -o attempts * to call UnOper. -- w00t */ oper = NULL; /* Remove all oper only modes from the user when the deoper - Bug #466*/ std::string moderemove("-"); for (unsigned char letter = 'A'; letter <= 'z'; letter++) { ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER); if (mh && mh->NeedsOper()) moderemove += letter; } std::vector<std::string> parameters; parameters.push_back(this->nick); parameters.push_back(moderemove); ServerInstance->Parser->CallHandler("MODE", parameters, this); /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */ ServerInstance->Users->all_opers.remove(this); this->modes[UM_OPERATOR] = 0; }
CmdResult CommandVersion::Handle (const std::vector<std::string>&, User *user) { std::string version = ServerInstance->GetVersionString(IS_OPER(user)); user->WriteNumeric(RPL_VERSION, "%s :%s", user->nick.c_str(), version.c_str()); ServerInstance->Config->Send005(user); return CMD_SUCCESS; }
/* Stop the join and clear the user's counter if they've hit the limit */ ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string& privs, const std::string& keygiven) { if (!chan || !chan->IsModeSet(jps.GetModeChar())) return MOD_RES_PASSTHRU; if (IS_OPER(user)) return MOD_RES_PASSTHRU; joinpartspamsettings* jpss = jps.ext.get(chan); if (jpss) { const std::string& mask(user->MakeHost()); if (jpss->zapme(mask)) { std::vector<std::string> parameters; parameters.push_back(chan->name); parameters.push_back("+b"); parameters.push_back(user->MakeWildHost()); ServerInstance->SendGlobalMode(parameters, ServerInstance->FakeClient); user->WriteNumeric(474, "%s %s :Channel join/part spam triggered (limit is %u cycles in %u secs)", user->nick.c_str(), chan->name.c_str(), jpss->cycles, jpss->secs); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; }
/** Handle /MODULES */ CmdResult cmd_modules::Handle (const char** parameters, int pcnt, userrec *user) { for (unsigned int i = 0; i < ServerInstance->Config->module_names.size(); i++) { Version V = ServerInstance->modules[i]->GetVersion(); char modulename[MAXBUF]; char flagstate[MAXBUF]; *flagstate = 0; if (V.Flags & VF_STATIC) strlcat(flagstate,", static",MAXBUF); if (V.Flags & VF_VENDOR) strlcat(flagstate,", vendor",MAXBUF); if (V.Flags & VF_COMMON) strlcat(flagstate,", common",MAXBUF); if (V.Flags & VF_SERVICEPROVIDER) strlcat(flagstate,", service provider",MAXBUF); if (!flagstate[0]) strcpy(flagstate," <no flags>"); strlcpy(modulename,ServerInstance->Config->module_names[i].c_str(),256); if (IS_OPER(user)) { user->WriteServ("900 %s :0x%08lx %d.%d.%d.%d %s (%s)",user->nick,ServerInstance->modules[i],V.Major,V.Minor,V.Revision,V.Build,ServerConfig::CleanFilename(modulename),flagstate+2); } else { user->WriteServ("900 %s :%s",user->nick,ServerConfig::CleanFilename(modulename)); } } user->WriteServ("901 %s :End of MODULES list",user->nick); return CMD_SUCCESS; }
CmdResult Handle (const std::vector<std::string> ¶meters, User *user) { std::string retbuf = std::string("340 ") + user->nick + " :"; int nicks = 0; for (int i = 0; i < (int)parameters.size(); i++) { User *u = ServerInstance->FindNick(parameters[i]); if ((u) && (u->registered == REG_ALL)) { retbuf = retbuf + u->nick + (IS_OPER(u) ? "*" : "") + "="; if (IS_AWAY(u)) retbuf += "-"; else retbuf += "+"; retbuf += u->ident + "@" + u->GetIPString() + " "; nicks++; } } if (nicks != 0) user->WriteServ(retbuf); /* Dont send to the network */ return CMD_LOCALONLY; }
ModResult OnWhoisLine(User* user, User* dest, int& numeric, std::string& text) { if ((numeric == 317) && (dest->IsModeSet('a')) && (!IS_OPER(user)) && (user != dest)) return MOD_RES_DENY; return MOD_RES_PASSTHRU; }
virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string& privs, const std::string& keygiven) { /* Do nothing if the channel already exists or if the user is either an oper or exempt */ if (chan) return MOD_RES_PASSTHRU; if (IS_OPER(user) || user->exempt) return MOD_RES_PASSTHRU; XLine* nc = ServerInstance->XLines->MatchesLine("NOCREATE", user); if (nc) { /* User is blocked from creating channels */ if (telluser) user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :You are not allowed to create channels", user->nick.c_str(), cname); else user->WriteNumeric(ERR_NOSUCHCHANNEL, "%s %s :Invalid channel name", user->nick.c_str(), cname); if (noisy) ServerInstance->SNO->WriteGlobalSno('a', "%s tried to create channel %s but is blocked from doing so (%s)", user->nick.c_str(), cname, nc->reason.c_str()); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; }
ModResult OnCheckBan(User *user, Channel *c, const std::string& mask) { if ((mask.length() > 2) && (mask[0] == 'O') && (mask[1] == ':')) { if (IS_OPER(user) && InspIRCd::Match(user->oper->name, mask.substr(2))) return MOD_RES_DENY; } return MOD_RES_PASSTHRU; }
void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text) { char tb1[MAXBUF]; char tb2[MAXBUF]; if (this->registered != REG_ALL) return; already_sent_t uniq_id = ++LocalUser::already_sent_id; snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),normal_text.c_str()); snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),oper_text.c_str()); std::string out1 = tb1; std::string out2 = tb2; UserChanList include_c(chans); std::map<User*,bool> exceptions; FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions)); for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting) { u->already_sent = uniq_id; if (i->second) u->Write(IS_OPER(u) ? out2 : out1); } } for (UCListIter v = include_c.begin(); v != include_c.end(); ++v) { const UserMembList* ulist = (*v)->GetUsers(); for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++) { LocalUser* u = IS_LOCAL(i->first); if (u && !u->quitting && (u->already_sent != uniq_id)) { u->already_sent = uniq_id; u->Write(IS_OPER(u) ? out2 : out1); } } } }
ModResult OnPreCommand(std::string &command, std::vector<std::string> ¶meters, LocalUser *user, bool validated, const std::string &original_line) { if (validated && !IS_OPER(user) && !url.empty() && (command == "MAP" || command == "LINKS")) { user->WriteServ("NOTICE %s :/%s has been disabled; visit %s", user->nick.c_str(), command.c_str(), url.c_str()); return MOD_RES_DENY; } else return MOD_RES_PASSTHRU; }
ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven) { if (chan && chan->IsModeSet('O') && !IS_OPER(user)) { user->WriteNumeric(ERR_CANTJOINOPERSONLY, "%s %s :Only IRC operators may join %s (+O is set)", user->nick.c_str(), chan->name.c_str(), chan->name.c_str()); return MOD_RES_DENY; } return MOD_RES_PASSTHRU; }
bool LocalUser::HasModePermission(unsigned char mode, ModeType type) { if (!IS_OPER(this)) return false; if (mode < 'A' || mode > ('A' + 64)) return false; return ((type == MODETYPE_USER ? oper->AllowedUserModes : oper->AllowedChanModes))[(mode - 'A')]; }
// WARNING: NOT THREAD SAFE - DONT GET ANY SMART IDEAS. void ModuleSpanningTree::ShowMap(TreeServer* Current, userrec* user, int depth, char matrix[128][128], float &totusers, float &totservers) { if (line < 128) { for (int t = 0; t < depth; t++) { matrix[line][t] = ' '; } // For Aligning, we need to work out exactly how deep this thing is, and produce // a 'Spacer' String to compensate. char spacer[40]; memset(spacer,' ',40); if ((40 - Current->GetName().length() - depth) > 1) { spacer[40 - Current->GetName().length() - depth] = '\0'; } else { spacer[5] = '\0'; } float percent; char text[128]; /* Neat and tidy default values, as we're dealing with a matrix not a simple string */ memset(text, 0, 128); if (ServerInstance->clientlist->size() == 0) { // If there are no users, WHO THE HELL DID THE /MAP?!?!?! percent = 0; } else { percent = ((float)Current->GetUserCount() / (float)ServerInstance->clientlist->size()) * 100; } const std::string operdata = IS_OPER(user) ? MapOperInfo(Current) : ""; snprintf(text, 126, "%s %s%5d [%5.2f%%]%s", Current->GetName().c_str(), spacer, Current->GetUserCount(), percent, operdata.c_str()); totusers += Current->GetUserCount(); totservers++; strlcpy(&matrix[line][depth],text,126); line++; for (unsigned int q = 0; q < Current->ChildCount(); q++) { if ((Current->GetChild(q)->Hidden) || ((Utils->HideULines) && (ServerInstance->ULine(Current->GetChild(q)->GetName().c_str())))) { if (*user->oper) { ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); } } else { ShowMap(Current->GetChild(q),user,(Utils->FlatLinks && (!*user->oper)) ? depth : depth+2,matrix,totusers,totservers); } } } }
virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if ((target_type == TYPE_USER) && (IS_LOCAL(user))) { User* u = (User*)dest; // message allowed if: // (1) the sender is opered // (2) the recipient is opered // anything else, blocked. if (IS_OPER(u) || IS_OPER(user)) { return MOD_RES_PASSTHRU; } user->WriteNumeric(ERR_CANTSENDTOUSER, "%s %s :You are not permitted to send private messages to this user",user->nick.c_str(),u->nick.c_str()); return MOD_RES_DENY; } // however, we must allow channel messages... return MOD_RES_PASSTHRU; }
virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if ((target_type == TYPE_USER) && (IS_LOCAL(user))) { userrec* u = (userrec*)dest; // message allowed if: // (1) the sender is opered // (2) the recipient is opered // anything else, blocked. if (IS_OPER(u) || IS_OPER(user)) { return 0; } user->WriteServ("531 %s %s :You are not permitted to send private messages to this user",user->nick,u->nick); return 1; } // however, we must allow channel messages... return 0; }
ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string& privs, const std::string& keygiven) { /* The user may have the +H umode on himself, but +H does not necessarily correspond * to the +H of m_hideoper. * However we only add the modewatcher when m_hideoper is loaded, so these * conditions (mw_added and the user being +H) together mean the user is a hidden oper. */ if (IS_OPER(user) && (!mw_added || !user->IsModeSet('H'))) privs.push_back('y'); return MOD_RES_PASSTHRU; }
virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if (target_type == TYPE_USER) { User* t = (User*)dest; if (!IS_OPER(user) && (t->IsModeSet('c')) && (!ServerInstance->ULine(user->server)) && !user->SharesChannelWith(t)) { user->WriteNumeric(ERR_CANTSENDTOUSER, "%s %s :You are not permitted to send private messages to this user (+c set)", user->nick.c_str(), t->nick.c_str()); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; }
/* No privmsg response when hiding - submitted by Eric at neowin */ ModResult ModuleInvisible::OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if ((target_type == TYPE_USER) && (IS_LOCAL(user))) { User* target = (User*)dest; if(hidemsg && target->IsModeSet('Q') && !IS_OPER(user)) { user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target->nick.c_str()); return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; }
int OnWhoisLine(User *user, User *dest, int &numeric, std::string &text) { if (numeric != 317 || user == dest || IS_OPER(user)) return 0; for (UCListIter it = dest->chans.begin(); it != dest->chans.end(); it++) { if (it->first->IsModeSet('U')) return 1; } return 0; }
bool LocalUser::HasPermission(const std::string &command) { // are they even an oper at all? if (!IS_OPER(this)) { return false; } if (oper->AllowedOperCommands.find(command) != oper->AllowedOperCommands.end()) return true; else if (oper->AllowedOperCommands.find("*") != oper->AllowedOperCommands.end()) return true; return false; }
virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) { irc::string x = cname; // user is not an oper and its not in the allow list if ((!IS_OPER(user)) && (allowchans.find(x) == allowchans.end())) { // channel does not yet exist (record is null, about to be created IF we were to allow it) if (!chan) { user->WriteServ("530 %s %s :Only IRC operators may create new channels",user->nick,cname,cname); return 1; } } return 0; }
/* Only count successful joins */ void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except) { if (sync) return; if (created || !memb->chan->IsModeSet(jps.GetModeChar())) return; if (IS_OPER(memb->user)) return; joinpartspamsettings* jpss = jps.ext.get(memb->chan); if (jpss) { const std::string& mask(memb->user->MakeHost()); jpss->addcycle(mask); } }
void ModuleSpanningTree::HandleLusers(const std::vector<std::string>& parameters, User* user) { unsigned int n_users = ServerInstance->Users->UserCount(); /* Only update these when someone wants to see them, more efficient */ if ((unsigned int)ServerInstance->Users->LocalUserCount() > max_local) max_local = ServerInstance->Users->LocalUserCount(); if (n_users > max_global) max_global = n_users; unsigned int ulined_count = 0; unsigned int ulined_local_count = 0; /* If ulined are hidden and we're not an oper, count the number of ulined servers hidden, * locally and globally (locally means directly connected to us) */ if ((Utils->HideULines) && (!IS_OPER(user))) { for (server_hash::iterator q = Utils->serverlist.begin(); q != Utils->serverlist.end(); q++) { if (ServerInstance->ULine(q->second->GetName().c_str())) { ulined_count++; if (q->second->GetParent() == Utils->TreeRoot) ulined_local_count++; } } } user->WriteNumeric(251, "%s :There are %d users and %d invisible on %d servers",user->nick.c_str(), n_users-ServerInstance->Users->ModeCount('i'), ServerInstance->Users->ModeCount('i'), ulined_count ? this->CountServs() - ulined_count : this->CountServs()); if (ServerInstance->Users->OperCount()) user->WriteNumeric(252, "%s %d :operator(s) online",user->nick.c_str(),ServerInstance->Users->OperCount()); if (ServerInstance->Users->UnregisteredUserCount()) user->WriteNumeric(253, "%s %d :unknown connections",user->nick.c_str(),ServerInstance->Users->UnregisteredUserCount()); if (ServerInstance->ChannelCount()) user->WriteNumeric(254, "%s %ld :channels formed",user->nick.c_str(),ServerInstance->ChannelCount()); user->WriteNumeric(255, "%s :I have %d clients and %d servers",user->nick.c_str(),ServerInstance->Users->LocalUserCount(),ulined_local_count ? this->CountLocalServs() - ulined_local_count : this->CountLocalServs()); user->WriteNumeric(265, "%s :Current Local Users: %d Max: %d",user->nick.c_str(),ServerInstance->Users->LocalUserCount(),max_local); user->WriteNumeric(266, "%s :Current Global Users: %d Max: %d",user->nick.c_str(),n_users,max_global); return; }
/** send all users and their oper state/modes */ void TreeSocket::SendUsers(TreeServer* Current) { char data[MAXBUF]; std::deque<std::string> list; std::string dataline; for (user_hash::iterator u = this->ServerInstance->Users->clientlist->begin(); u != this->ServerInstance->Users->clientlist->end(); u++) { if (u->second->registered == REG_ALL) { TreeServer* theirserver = Utils->FindServer(u->second->server); if (theirserver) { snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s", theirserver->GetID().c_str(), /* Prefix: SID */ u->second->uuid.c_str(), /* 0: UUID */ (unsigned long)u->second->age, /* 1: TS */ u->second->nick.c_str(), /* 2: Nick */ u->second->host.c_str(), /* 3: Displayed Host */ u->second->dhost.c_str(), /* 4: Real host */ u->second->ident.c_str(), /* 5: Ident */ u->second->GetIPString(), /* 6: IP string */ (unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */ u->second->FormatModes(true), /* 8...n: Modes and params */ u->second->fullname.c_str()); /* size-1: GECOS */ this->WriteLine(data); if (IS_OPER(u->second)) { snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper.c_str()); this->WriteLine(data); } if (IS_AWAY(u->second)) { snprintf(data,MAXBUF,":%s AWAY :%s", u->second->uuid.c_str(), u->second->awaymsg.c_str()); this->WriteLine(data); } } FOREACH_MOD_I(this->ServerInstance,I_OnSyncUser,OnSyncUser(u->second,(Module*)Utils->Creator,(void*)this)); list.clear(); u->second->GetExtList(list); for (unsigned int j = 0; j < list.size(); j++) { FOREACH_MOD_I(this->ServerInstance,I_OnSyncUserMetaData,OnSyncUserMetaData(u->second,(Module*)Utils->Creator,(void*)this,list[j])); } } } }
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { if (dest->IsModeSet('Q') != adding) { dest->SetMode('Q', adding); /* Fix for bug #379 reported by stealth. On +/-Q make m_watch think the user has signed on/off */ Module* m = ServerInstance->Modules->Find("m_watch.so"); /* This must come before setting/unsetting the handler */ if (m && adding) m->OnUserQuit(dest, "Connection closed", "Connection closed"); /* User appears to vanish or appear from nowhere */ for (UCListIter f = dest->chans.begin(); f != dest->chans.end(); f++) { const UserMembList *ulist = (*f)->GetUsers(); char tb[MAXBUF]; snprintf(tb,MAXBUF,":%s %s %s", dest->GetFullHost().c_str(), adding ? "PART" : "JOIN", (*f)->name.c_str()); std::string out = tb; Membership* memb = (**f).GetUser(dest); std::string ms = memb->modes; for(unsigned int i=0; i < memb->modes.length(); i++) ms.append(" ").append(dest->nick); for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { /* User only appears to vanish for non-opers */ if (IS_LOCAL(i->first) && !IS_OPER(i->first)) { i->first->Write(out); if (!ms.empty() && !adding) i->first->WriteServ("MODE %s +%s", (**f).name.c_str(), ms.c_str()); } } } ServerInstance->SNO->WriteToSnoMask('a', "\2NOTICE\2: Oper %s has become %svisible (%cQ)", dest->GetFullHost().c_str(), adding ? "in" : "", adding ? '+' : '-'); return MODEACTION_ALLOW; } else { return MODEACTION_DENY; } }
virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { if (target_type != TYPE_USER) return MOD_RES_PASSTHRU; User* target = (User*) dest; if (!target->IsModeSet('D')) return MOD_RES_PASSTHRU; if ((operoverride) && (IS_OPER(user))) return MOD_RES_PASSTHRU; if ((ulineoverride) && (ServerInstance->ULine(user->server))) return MOD_RES_PASSTHRU; return MOD_RES_DENY; }
ModeAction OnModeChange(User* source, User* dest, Channel* chan, std::string& parameter, bool adding) { if (dest->IsModeSet(GetModeChar()) == adding) return MODEACTION_DENY; dest->SetMode(GetModeChar(), adding); LocalUser* const localuser = IS_LOCAL(dest); // Send snotices char snodest = localuser ? 'v' : 'V'; if (snoonset && adding) ServerInstance->SNO->WriteToSnoMask(snodest, "Oper %s has turned on override", dest->nick.c_str()); else if (!adding) { // IS_OPER check is needed to make sure we don't send snotices when the server unsets // the mode due to deopering if ((snoonunset) && (IS_OPER(dest)) && (!IS_SERVER(source))) ServerInstance->SNO->WriteToSnoMask(snodest, "Oper %s has turned off override", dest->nick.c_str()); } // Ignore remote users, their own server handles them if (localuser) { if (adding) { if (activetime > 0) activeopers.push_back(ActiveOper(localuser)); } else { // Remove this oper from the list for (ActiveOperList::iterator i = activeopers.begin(); i != activeopers.end(); ++i) { ActiveOper& item = *i; if (item.uuid == dest->uuid) { activeopers.erase(i); break; } } } } return MODEACTION_ALLOW; }