/* * <@po||ux> DukeP: RFC 2813, 4.2.1: the JOIN command on server-server links * separates the modes ("o") with ASCII 7, not space. And you can't see ASCII 7. * * if a user joins a new channel, the ircd sends <channelname>\7<umode> */ void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override { User *user = source.GetUser(); size_t pos = params[0].find('\7'); Anope::string channel, modes; if (pos != Anope::string::npos) { channel = params[0].substr(0, pos); modes = '+' + params[0].substr(pos+1, params[0].length()) + " " + user->nick; } else { channel = params[0]; } std::vector<Anope::string> new_params; new_params.push_back(channel); Message::Join::Run(source, new_params); if (!modes.empty()) { Channel *c = Channel::Find(channel); if (c) c->SetModesInternal(source, modes); } }
/* * CHANINFO is used by servers to inform each other about a channel: its * modes, channel key, user limits and its topic. The parameter combination * <key> and <limit> is optional, as well as the <topic> parameter, so that * there are three possible forms of this command: * * CHANINFO <chan> +<modes> * CHANINFO <chan> +<modes> :<topic> * CHANINFO <chan> +<modes> <key> <limit> :<topic> * * The parameter <key> must be ignored if a channel has no key (the parameter * <modes> doesn't list the "k" channel mode). In this case <key> should * contain "*" because the parameter <key> is required by the CHANINFO syntax * and therefore can't be omitted. The parameter <limit> must be ignored when * a channel has no user limit (the parameter <modes> doesn't list the "l" * channel mode). In this case <limit> should be "0". */ void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override { bool created; Channel *c = Channel::FindOrCreate(params[0], created); Anope::string modes = params[1]; if (params.size() == 3) { c->ChangeTopicInternal(NULL, source.GetName(), params[2], Anope::CurTime); } else if (params.size() == 5) { for (size_t i = 0, end = params[1].length(); i < end; ++i) { switch(params[1][i]) { case 'k': modes += " " + params[2]; continue; case 'l': modes += " " + params[3]; continue; } } c->ChangeTopicInternal(NULL, source.GetName(), params[4], Anope::CurTime); } c->SetModesInternal(source, modes); }
void bahamut::Mode::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { if (params.size() > 2 && IRCD->IsChannelValid(params[0])) { Channel *c = Channel::Find(params[0]); time_t ts = 0; try { ts = convertTo<time_t>(params[1]); } catch (const ConvertException &) { } Anope::string modes = params[2]; for (unsigned int i = 3; i < params.size(); ++i) modes += " " + params[i]; if (c) c->SetModesInternal(source, modes, ts); } else { User *u = User::Find(params[0]); if (u) u->SetModesInternal(source, "%s", params[1].c_str()); } }
void hybrid::TMode::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { time_t ts = 0; try { ts = convertTo<time_t>(params[0]); } catch (const ConvertException &) { } Channel *c = Channel::Find(params[1]); Anope::string modes = params[2]; for (unsigned i = 3; i < params.size(); ++i) modes += " " + params[i]; if (c) c->SetModesInternal(source, modes, ts); }
void Message::Mode::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { Anope::string buf; for (unsigned i = 1; i < params.size(); ++i) buf += " " + params[i]; if (IRCD->IsChannelValid(params[0])) { Channel *c = Channel::Find(params[0]); if (c) c->SetModesInternal(source, buf.substr(1), 0); } else { User *u = User::Find(params[0]); if (u) u->SetModesInternal(source, "%s", buf.substr(1).c_str()); } }
void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) override { Anope::string modes = params[1]; for (size_t i = 2; i < params.size(); ++i) modes += " " + params[i]; if (IRCD->IsChannelValid(params[0])) { Channel *c = Channel::Find(params[0]); if (c) c->SetModesInternal(source, modes); } else { User *u = User::Find(params[0]); if (u) u->SetModesInternal(source, "%s", params[1].c_str()); } }
bool OnSJoin(const Anope::string &source, const std::vector<Anope::string> ¶ms) { Channel *c = findchan(params[1]); time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; bool keep_their_modes = true; if (!c) { c = new Channel(params[1], ts); c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; c->Reset(); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ else if (ts > c->creation_time) keep_their_modes = false; /* If we need to keep their modes, and this SJOIN string contains modes */ if (keep_their_modes && params.size() >= 4) { /* Set the modes internally */ Anope::string modes; for (unsigned i = 2; i < params.size(); ++i) modes += " " + params[i]; if (!modes.empty()) modes.erase(modes.begin()); c->SetModesInternal(NULL, modes); } /* For some reason, bahamut will send a SJOIN from the user joining a channel * if the channel already existed */ if (!c->HasFlag(CH_SYNCING) && params.size() == 2) { User *u = finduser(source); if (!u) Log(LOG_DEBUG) << "SJOIN for nonexistant user " << source << " on " << c->name; else { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); /* Add the user to the channel */ c->JoinUser(u); /* Now set whatever modes this user is allowed to have on the channel */ chan_set_correct_modes(u, c, 1); /* Check to see if modules want the user to join, if they do * check to see if they are allowed to join (CheckKick will kick/ban them) * Don't trigger OnJoinChannel event then as the user will be destroyed */ if (MOD_RESULT == EVENT_STOP && (!c->ci || !c->ci->CheckKick(u))) { FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); } } } else { spacesepstream sep(params[params.size() - 1]); Anope::string buf; while (sep.GetToken(buf)) { std::list<ChannelMode *> Status; char ch; /* Get prefixes from the nick */ while ((ch = ModeManager::GetStatusChar(buf[0]))) { buf.erase(buf.begin()); ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); if (!cm) { Log() << "Received unknown mode prefix " << cm << " in SJOIN string"; continue; } if (keep_their_modes) Status.push_back(cm); } User *u = finduser(buf); if (!u) { Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << c->name; continue; } EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); /* Add the user to the channel */ c->JoinUser(u); /* Update their status internally on the channel * This will enforce secureops etc on the user */ for (std::list<ChannelMode *>::iterator it = Status.begin(), it_end = Status.end(); it != it_end; ++it) c->SetModeInternal(*it, buf); /* Now set whatever modes this user is allowed to have on the channel */ chan_set_correct_modes(u, c, 1); /* Check to see if modules want the user to join, if they do * check to see if they are allowed to join (CheckKick will kick/ban them) * Don't trigger OnJoinChannel event then as the user will be destroyed */ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u)) continue; FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); } } /* Channel is done syncing */ if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); c->Sync(); } return true; }
void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::list<SJoinUser> &users) { bool created; Channel *c = Channel::FindOrCreate(chan, created, ts ? ts : Anope::CurTime); bool keep_their_modes = true; if (created) c->syncing = true; /* Some IRCds do not include a TS */ else if (!ts) ; /* Our creation time is newer than what the server gave us, so reset the channel to the older time */ else if (c->creation_time > ts) { c->creation_time = ts; c->Reset(); } /* Their TS is newer, don't accept any modes from them */ else if (ts > c->creation_time) keep_their_modes = false; /* Update the modes for the channel */ if (keep_their_modes && !modes.empty()) /* If we are syncing, mlock is checked later in Channel::Sync. It is important to not check it here * so that Channel::SetCorrectModes can correctly detect the presence of channel mode +r. */ c->SetModesInternal(source, modes, ts, !c->syncing); for (std::list<SJoinUser>::const_iterator it = users.begin(), it_end = users.end(); it != it_end; ++it) { const ChannelStatus &status = it->first; User *u = it->second; keep_their_modes = ts <= c->creation_time; // OnJoinChannel can call modules which can modify this channel's ts if (c->FindUser(u)) continue; /* Add the user to the channel */ c->JoinUser(u, keep_their_modes ? &status : NULL); /* Check if the user is allowed to join */ if (c->CheckKick(u)) continue; /* Set whatever modes the user should have, and remove any that * they aren't allowed to have (secureops etc). */ c->SetCorrectModes(u, true); EventManager::Get()->Dispatch(&Event::JoinChannel::OnJoinChannel, u, c); } /* Channel is done syncing */ if (c->syncing) { /* Sync the channel (mode lock, topic, etc) */ /* the channel is synced when the netmerge is complete */ Server *src = source.GetServer() ? source.GetServer() : Me; if (src && src->IsSynced()) { c->Sync(); if (c->CheckDelete()) delete c; } } }