virtual void OnBuildExemptList(MessageType message_type, chanrec* chan, userrec* sender, char status, CUList &exempt_list) { CUList *ulist; switch (status) { case '@': ulist = chan->GetOppedUsers(); break; case '%': ulist = chan->GetHalfoppedUsers(); break; case '+': ulist = chan->GetVoicedUsers(); break; default: ulist = chan->GetUsers(); break; } for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) { if (IS_LOCAL(i->first)) { if (i->first->IsModeSet('d')) { exempt_list[i->first] = i->first->nick; } } } }
virtual void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text) { int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE); CUList *ulist; switch (status) { case '@': ulist = chan->GetOppedUsers(); break; case '%': ulist = chan->GetHalfoppedUsers(); break; case '+': ulist = chan->GetVoicedUsers(); break; default: ulist = chan->GetUsers(); break; } for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) { if (IS_LOCAL(i->first)) { if (MatchPattern(i->first, sender, public_silence) == 1) { exempt_list[i->first] = i->first->nick; } } } }
void RemoveMode(chanrec* channel, char mc) { unload_kludge = true; CUList* cl = channel->GetUsers(); std::string item = extend + std::string(channel->name); const char* mode_junk[MAXMODES+2]; userrec* n = new userrec(MyInstance); n->SetFd(FD_MAGIC_NUMBER); mode_junk[0] = channel->name; irc::modestacker modestack(false); std::deque<std::string> stackresult; for (CUList::iterator i = cl->begin(); i != cl->end(); i++) { if (i->first->GetExt(item, dummyptr)) { modestack.Push(mc, i->first->nick); } } while (modestack.GetStackedLine(stackresult)) { for (size_t j = 0; j < stackresult.size(); j++) { mode_junk[j+1] = stackresult[j].c_str(); } MyInstance->SendMode(mode_junk, stackresult.size() + 1, n); } delete n; unload_kludge = false; }
void RemoveMode(Channel* channel, char mc, irc::modestacker* stack) { CUList* cl = channel->GetUsers(); std::string item = extend + std::string(channel->name); std::vector<std::string> mode_junk; mode_junk.push_back(channel->name); irc::modestacker modestack(MyInstance, false); std::deque<std::string> stackresult; for (CUList::iterator i = cl->begin(); i != cl->end(); i++) { if (i->first->GetExt(item)) { if (stack) stack->Push(mc, i->first->nick); else modestack.Push(mc, i->first->nick); } } if (stack) return; while (modestack.GetStackedLine(stackresult)) { mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); MyInstance->SendMode(mode_junk, MyInstance->FakeClient); mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); } }
/* returns a list of DIRECT servernames for a specific channel */ void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list) { unsigned int minrank = 0; if (status) { PrefixMode* mh = ServerInstance->Modes->FindPrefix(status); if (mh) minrank = mh->GetPrefixRank(); } const UserMembList *ulist = c->GetUsers(); for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { if (IS_LOCAL(i->first)) continue; if (minrank && i->second->getRank() < minrank) continue; if (exempt_list.find(i->first) == exempt_list.end()) { TreeServer* best = TreeServer::Get(i->first); list.insert(best->GetSocket()); } } return; }
virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque) { /* NOTE: If +qa prefix is on, this is propogated by the channel join, * so we dont need to propogate it manually */ if (!QAPrefixes) { // this is called when the server is linking into a net and wants to sync channel data. // we should send our mode changes for the channel here to ensure that other servers // know whos +q/+a on the channel. CUList* cl = chan->GetUsers(); string_list commands; std::string founder = "cm_founder_"+std::string(chan->name); std::string protect = "cm_protect_"+std::string(chan->name); irc::modestacker modestack(true); std::deque<std::string> stackresult; for (CUList::iterator i = cl->begin(); i != cl->end(); i++) { if (i->first->GetExt(founder,dummyptr)) { modestack.Push('q',i->first->nick); } if (i->first->GetExt(protect,dummyptr)) { modestack.Push('a',i->first->nick); } } while (modestack.GetStackedLine(stackresult)) { irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1); std::string line = mode_join.GetJoined(); proto->ProtoSendMode(opaque,TYPE_CHANNEL,chan, line); } } }
virtual void BuildDeafList(MessageType message_type, Channel* chan, User* sender, char status, const std::string &text, CUList &exempt_list) { CUList *ulist = chan->GetUsers(); bool is_a_uline; bool is_bypasschar, is_bypasschar_avail; bool is_bypasschar_uline, is_bypasschar_uline_avail; is_bypasschar = is_bypasschar_avail = is_bypasschar_uline = is_bypasschar_uline_avail = 0; if (!deaf_bypasschars.empty()) { is_bypasschar_avail = 1; if (deaf_bypasschars.find(text[0], 0) != std::string::npos) is_bypasschar = 1; } if (!deaf_bypasschars_uline.empty()) { is_bypasschar_uline_avail = 1; if (deaf_bypasschars_uline.find(text[0], 0) != std::string::npos) is_bypasschar_uline = 1; } /* * If we have no bypasschars_uline in config, and this is a bypasschar (regular) * Than it is obviously going to get through +d, no build required */ if (!is_bypasschar_uline_avail && is_bypasschar) return; for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) { /* not +d ? */ if (!i->first->IsModeSet('d')) continue; /* deliver message */ /* matched both U-line only and regular bypasses */ if (is_bypasschar && is_bypasschar_uline) continue; /* deliver message */ is_a_uline = ServerInstance->ULine(i->first->server); /* matched a U-line only bypass */ if (is_bypasschar_uline && is_a_uline) continue; /* deliver message */ /* matched a regular bypass */ if (is_bypasschar && !is_a_uline) continue; /* deliver message */ if (status && !strchr(chan->GetAllPrefixChars(i->first), status)) continue; /* don't deliver message! */ exempt_list[i->first] = i->first->nick; } }
void DisplayList(userrec* user, chanrec* channel) { CUList* cl = channel->GetUsers(); std::string item = extend+std::string(channel->name); for (CUList::reverse_iterator i = cl->rbegin(); i != cl->rend(); ++i) { if (i->first->GetExt(item, dummyptr)) { user->WriteServ("%d %s %s %s", list, user->nick, channel->name,i->first->nick); } } user->WriteServ("%d %s %s :End of channel %s list", end, user->nick, channel->name, type.c_str()); }
static void BuildExcept(Membership* memb, CUList& excepts) { const UserMembList* users = memb->chan->GetUsers(); for(UserMembCIter i = users->begin(); i != users->end(); i++) { if (IS_LOCAL(i->first) && i->first->HasPrivPermission("invisible/see")) excepts.insert(i->first); } }
static void populate(CUList& except, Membership* memb) { const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { if (i->first == memb->user || !IS_LOCAL(i->first)) continue; except.insert(i->first); } }
void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list) override { if (badchan) { const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) if (i->first != memb->user) except_list.insert(i->first); } }
/** Build CUList for showing this join/part/kick */ void BuildExcept(Membership* memb, CUList& excepts) { if (IsVisible(memb)) return; const UserMembList* users = memb->chan->GetUsers(); for(UserMembCIter i = users->begin(); i != users->end(); i++) { if (IS_LOCAL(i->first) && !CanSee(i->first, memb)) excepts.insert(i->first); } }
/** Build CUList for showing this join/part/kick */ void BuildExcept(Membership* memb, CUList& excepts) { if (IsVisible(memb)) return; const Channel::MemberMap& users = memb->chan->GetUsers(); for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i) { if (IS_LOCAL(i->first) && !CanSee(i->first, memb)) excepts.insert(i->first); } }
void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text) { int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE); const UserMembList *ulist = chan->GetUsers(); for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { if (IS_LOCAL(i->first)) { if (MatchPattern(i->first, sender, public_silence) == MOD_RES_DENY) { exempt_list.insert(i->first); } } } }
void BuildExemptList(MessageType message_type, Channel* chan, User* sender, CUList& exempt_list) { int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE); const Channel::MemberMap& ulist = chan->GetUsers(); for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i) { if (IS_LOCAL(i->first)) { if (MatchPattern(i->first, sender, public_silence) == MOD_RES_DENY) { exempt_list.insert(i->first); } } } }
void ModeChannelVoice::RemoveMode(chanrec* channel) { CUList* list = channel->GetVoicedUsers(); CUList copy; char moderemove[MAXBUF]; userrec* n = new userrec(ServerInstance); n->SetFd(FD_MAGIC_NUMBER); for (CUList::iterator i = list->begin(); i != list->end(); i++) { userrec* n = i->first; copy.insert(std::make_pair(n,n->nick)); } for (CUList::iterator i = copy.begin(); i != copy.end(); i++) { sprintf(moderemove,"-%c",this->GetModeChar()); const char* parameters[] = { channel->name, moderemove, i->first->nick }; ServerInstance->SendMode(parameters, 3, n); } delete n; }
void BuildDeafList(MessageType message_type, Channel* chan, User* sender, char status, const std::string &text, CUList &exempt_list) { const UserMembList *ulist = chan->GetUsers(); bool is_bypasschar = (deaf_bypasschars.find(text[0]) != std::string::npos); bool is_bypasschar_uline = (deaf_bypasschars_uline.find(text[0]) != std::string::npos); /* * If we have no bypasschars_uline in config, and this is a bypasschar (regular) * Than it is obviously going to get through +d, no build required */ if (!deaf_bypasschars_uline.empty() && is_bypasschar) return; for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { /* not +d ? */ if (!i->first->IsModeSet(m1)) continue; /* deliver message */ /* matched both U-line only and regular bypasses */ if (is_bypasschar && is_bypasschar_uline) continue; /* deliver message */ bool is_a_uline = i->first->server->IsULine(); /* matched a U-line only bypass */ if (is_bypasschar_uline && is_a_uline) continue; /* deliver message */ /* matched a regular bypass */ if (is_bypasschar && !is_a_uline) continue; /* deliver message */ if (status && !strchr(chan->GetAllPrefixChars(i->first), status)) continue; /* don't deliver message! */ exempt_list.insert(i->first); } }
void ModeChannelOp::RemoveMode(Channel* channel, irc::modestacker* stack) { CUList* clist = channel->GetOppedUsers(); CUList copy; for (CUList::iterator i = clist->begin(); i != clist->end(); i++) { User* n = i->first; copy.insert(std::make_pair(n,n->nick)); } for (CUList::iterator i = copy.begin(); i != copy.end(); i++) { if (stack) stack->Push(this->GetModeChar(), i->first->nick); else { std::vector<std::string> parameters; parameters.push_back(channel->name); parameters.push_back("-o"); parameters.push_back(i->first->nick); ServerInstance->SendMode(parameters, ServerInstance->FakeClient); } } }
/** Handle nick changes from users. * NOTE: If you are used to ircds based on ircd2.8, and are looking * for the client introduction code in here, youre in the wrong place. * You need to look in the spanningtree module for this! */ CmdResult CommandNick::Handle (const std::vector<std::string>& parameters, User *user) { std::string oldnick; if (parameters[0].empty()) { /* We cant put blanks in the parameters, so for this (extremely rare) issue we just put '*' here. */ user->WriteNumeric(432, "%s * :Erroneous Nickname", user->nick.empty() ? user->nick.c_str() : "*"); return CMD_FAILURE; } if (((!ServerInstance->IsNick(parameters[0].c_str(), ServerInstance->Config->Limits.NickMax))) && (IS_LOCAL(user))) { if (!allowinvalid) { if (parameters[0] == "0") { // Special case, Fake a /nick UIDHERE. Useful for evading "ERR: NICK IN USE" on connect etc. std::vector<std::string> p2; std::deque<classbase*> dummy; p2.push_back(user->uuid); this->HandleInternal(1, dummy); this->Handle(p2, user); this->HandleInternal(0, dummy); return CMD_SUCCESS; } user->WriteNumeric(432, "%s %s :Erroneous Nickname", user->nick.c_str(),parameters[0].c_str()); return CMD_FAILURE; } } if (assign(user->nick) == parameters[0]) { /* If its exactly the same, even case, dont do anything. */ if (parameters[0] == user->nick) { return CMD_SUCCESS; } /* Its a change of case. People insisted that they should be * able to do silly things like this even though the RFC says * the nick AAA is the same as the nick aaa. */ oldnick.assign(user->nick, 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user,parameters[0])); if (MOD_RESULT) return CMD_FAILURE; if (user->registered == REG_ALL) user->WriteCommon("NICK %s",parameters[0].c_str()); user->nick.assign(parameters[0], 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); user->InvalidateCache(); FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick)); return CMD_SUCCESS; } else { /* * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some f*****g *moron* * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be. * Thanks Kein for finding this. -- w00t * * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves. * -- w00t */ if (!allowinvalid || !IS_LOCAL(user)) { XLine* mq = ServerInstance->XLines->MatchesLine("Q",parameters[0]); if (mq) { if (user->registered == REG_ALL) { ServerInstance->SNO->WriteToSnoMask('x', "Q-Lined nickname %s from %s!%s@%s: %s", parameters[0].c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str(), mq->reason); } user->WriteNumeric(432, "%s %s :Invalid nickname: %s",user->nick.c_str(), parameters[0].c_str(), mq->reason); return CMD_FAILURE; } if (ServerInstance->Config->RestrictBannedUsers) { for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { Channel *chan = i->first; if (chan->GetStatus(user) < STATUS_VOICE && chan->IsBanned(user)) { user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); return CMD_FAILURE; } } } } /* * Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) -- * then we have a potential collide. Check whether someone else is camping on the nick * (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the * camper to their UID, and allow the incoming nick change. * * If the guy using the nick is already using it, tell the incoming nick change to gtfo, * because the nick is already (rightfully) in use. -- w00t */ User* InUse = ServerInstance->FindNickOnly(parameters[0]); if (InUse && (InUse != user)) { if (InUse->registered != REG_ALL) { /* force the camper to their UUID, and ask them to re-send a NICK. */ InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str()); InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str()); InUse->UpdateNickHash(InUse->uuid.c_str()); InUse->nick.assign(InUse->uuid, 0, IS_LOCAL(InUse) ? ServerInstance->Config->Limits.NickMax : MAXBUF); InUse->InvalidateCache(); InUse->registered &= ~REG_NICK; } else { /* No camping, tell the incoming user to stop trying to change nick ;p */ user->WriteNumeric(433, "%s %s :Nickname is already in use.", user->registered >= REG_NICK ? user->nick.c_str() : "*", parameters[0].c_str()); return CMD_FAILURE; } } } int MOD_RESULT = 0; FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(user, parameters[0])); if (MOD_RESULT) // if a module returns true, the nick change is silently forbidden. return CMD_FAILURE; if (user->registered == REG_ALL) user->WriteCommon("NICK %s", parameters[0].c_str()); oldnick.assign(user->nick, 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); /* change the nick of the user in the users_hash */ user = user->UpdateNickHash(parameters[0].c_str()); /* actually change the nick within the record */ if (!user) return CMD_FAILURE; user->nick.assign(parameters[0], 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); user->InvalidateCache(); /* Update display nicks */ for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++) { CUList* ulist = v->first->GetUsers(); CUList::iterator i = ulist->find(user); if (i != ulist->end()) i->second = user->nick; } if (user->registered < REG_NICKUSER) { user->registered = (user->registered | REG_NICK); if (user->registered == REG_NICKUSER) { /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ MOD_RESULT = 0; FOREACH_RESULT(I_OnUserRegister,OnUserRegister(user)); if (MOD_RESULT > 0) return CMD_FAILURE; // return early to not penalize new users return CMD_SUCCESS; } } if (user->registered == REG_ALL) { user->IncreasePenalty(10); FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user, oldnick)); } return CMD_SUCCESS; }
/** Send one or more FJOINs for a channel of users. * If the length of a single line is more than 480-NICKMAX * in length, it is split over multiple lines. */ void TreeSocket::SendFJoins(TreeServer* Current, Channel* c) { std::string buffer; char list[MAXBUF]; size_t curlen, headlen; curlen = headlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu +%s :", this->ServerInstance->Config->GetSID().c_str(), c->name.c_str(), (unsigned long)c->age, c->ChanModes(true)); int numusers = 0; char* ptr = list + curlen; bool looped_once = false; CUList *ulist = c->GetUsers(); std::string modes; std::string params; for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++) { size_t ptrlen = 0; std::string modestr = this->ServerInstance->Modes->ModeString(i->first, c, false); if ((curlen + modestr.length() + i->first->uuid.length() + 4) > 480) { // remove the final space if (ptr[-1] == ' ') ptr[-1] = '\0'; buffer.append(list).append("\r\n"); curlen = headlen; ptr = list + headlen; numusers = 0; } ptrlen = snprintf(ptr, MAXBUF-curlen, "%s,%s ", modestr.c_str(), i->first->uuid.c_str()); looped_once = true; curlen += ptrlen; ptr += ptrlen; numusers++; } // Okay, permanent channels will (of course) need this \r\n anyway, numusers check is if there // actually were people in the channel (looped_once == true) if (!looped_once || numusers > 0) { // remove the final space if (ptr[-1] == ' ') ptr[-1] = '\0'; buffer.append(list).append("\r\n"); } int linesize = 1; for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) { int size = b->data.length() + 2; int currsize = linesize + size; if (currsize <= 350) { modes.append("b"); params.append(" ").append(b->data); linesize += size; } if ((params.length() >= ServerInstance->Config->Limits.MaxModes) || (currsize > 350)) { /* Wrap at MAXMODES */ buffer.append(":").append(this->ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); modes.clear(); params.clear(); linesize = 1; } } /* Only send these if there are any */ if (!modes.empty()) buffer.append(":").append(this->ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); this->WriteLine(buffer); }