*/
-/* $Core */
-
#include "inspircd.h"
#include "listmode.h"
#include <cstdarg>
#include "mode.h"
-static ModeReference ban(NULL, "ban");
+namespace
+{
+ ChanModeReference ban(NULL, "ban");
+ ChanModeReference inviteonlymode(NULL, "inviteonly");
+ ChanModeReference keymode(NULL, "key");
+ ChanModeReference limitmode(NULL, "limit");
+ ChanModeReference secretmode(NULL, "secret");
+ ChanModeReference privatemode(NULL, "private");
+ UserModeReference invisiblemode(NULL, "invisible");
+}
Channel::Channel(const std::string &cname, time_t ts)
+ : name(cname), age(ts), topicset(0)
{
if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second)
throw CoreException("Cannot create duplicate channel " + cname);
-
- this->name = cname;
- this->age = ts ? ts : ServerInstance->Time();
-
- topicset = 0;
- modes.reset();
-}
-
-void Channel::SetMode(char mode,bool mode_on)
-{
- modes[mode-65] = mode_on;
}
void Channel::SetMode(ModeHandler* mh, bool on)
modes[mh->GetModeChar() - 65] = on;
}
-void Channel::SetModeParam(char mode, const std::string& parameter)
+void Channel::SetModeParam(ModeHandler* mh, const std::string& parameter)
{
+ char mode = mh->GetModeChar();
if (parameter.empty())
{
custom_mode_params.erase(mode);
}
}
-void Channel::SetModeParam(ModeHandler* mode, const std::string& parameter)
-{
- SetModeParam(mode->GetModeChar(), parameter);
-}
-
-std::string Channel::GetModeParameter(char mode)
-{
- CustomModeList::iterator n = custom_mode_params.find(mode);
- if (n != custom_mode_params.end())
- return n->second;
- return "";
-}
-
std::string Channel::GetModeParameter(ModeHandler* mode)
{
CustomModeList::iterator n = custom_mode_params.find(mode->GetModeChar());
this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
this->topicset = ServerInstance->Time();
- FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic));
+ FOREACH_MOD(OnPostTopicChange, (u, this, this->topic));
}
Membership* Channel::AddUser(User* user)
/* kill the record */
if (iter != ServerInstance->chanlist->end())
{
- FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
+ FOREACH_MOD(OnChannelDelete, (this));
ServerInstance->chanlist->erase(iter);
}
ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
if (mode)
{
+ if (mode->IsPrefixMode())
+ continue;
+
if (mode->GetNumParams(true))
list.GetToken(parameter);
else
{
if (user->chans.size() >= ServerInstance->Config->OperMaxChans)
{
- user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cname.c_str());
+ user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s :You are on too many channels", cname.c_str());
return NULL;
}
}
maxchans = ServerInstance->Config->MaxChans;
if (user->chans.size() >= maxchans)
{
- user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s %s :You are on too many channels",user->nick.c_str(), cname.c_str());
+ user->WriteNumeric(ERR_TOOMANYCHANNELS, "%s :You are on too many channels", cname.c_str());
return NULL;
}
}
if (!chan)
{
- privs = "o";
+ privs = ServerInstance->Config->DefaultModes.substr(0, ServerInstance->Config->DefaultModes.find(' '));
if (override == false)
{
// then this entire section is skipped
if (MOD_RESULT == MOD_RES_PASSTHRU)
{
- std::string ckey = chan->GetModeParameter('k');
+ std::string ckey = chan->GetModeParameter(keymode);
bool invited = user->IsInvited(chan);
bool can_bypass = ServerInstance->Config->InvBypassModes && invited;
if (!MOD_RESULT.check((ckey == key) || can_bypass))
{
// If no key provided, or key is not the right one, and can't bypass +k (not invited or option not enabled)
- user->WriteNumeric(ERR_BADCHANNELKEY, "%s %s :Cannot join channel (Incorrect channel key)",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_BADCHANNELKEY, "%s :Cannot join channel (Incorrect channel key)", chan->name.c_str());
return NULL;
}
}
- if (chan->IsModeSet('i'))
+ if (chan->IsModeSet(inviteonlymode))
{
FIRST_MOD_RESULT(OnCheckInvite, MOD_RESULT, (user, chan));
if (!MOD_RESULT.check(invited))
{
- user->WriteNumeric(ERR_INVITEONLYCHAN, "%s %s :Cannot join channel (Invite only)",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_INVITEONLYCHAN, "%s :Cannot join channel (Invite only)", chan->name.c_str());
return NULL;
}
}
- std::string limit = chan->GetModeParameter('l');
+ std::string limit = chan->GetModeParameter(limitmode);
if (!limit.empty())
{
FIRST_MOD_RESULT(OnCheckLimit, MOD_RESULT, (user, chan));
if (!MOD_RESULT.check((chan->GetUserCounter() < atol(limit.c_str()) || can_bypass)))
{
- user->WriteNumeric(ERR_CHANNELISFULL, "%s %s :Cannot join channel (Channel is full)",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_CHANNELISFULL, "%s :Cannot join channel (Channel is full)", chan->name.c_str());
return NULL;
}
}
if (chan->IsBanned(user) && !can_bypass)
{
- user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)",user->nick.c_str(), chan->name.c_str());
+ user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s :Cannot join channel (You're banned)", chan->name.c_str());
return NULL;
}
void Channel::ForceJoin(User* user, const std::string* privs, bool bursting, bool created_by_local)
{
- Membership* memb = this->AddUser(user);
- if (!memb)
- return; // Already on the channel
-
if (IS_SERVER(user))
{
ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "Attempted to join server user " + user->uuid + " to channel " + this->name);
return;
}
- user->chans.insert(this);
+ Membership* memb = this->AddUser(user);
+ if (!memb)
+ return; // Already on the channel
+
+ user->chans.push_front(memb);
if (privs)
{
// If the user was granted prefix modes (in the OnUserPreJoin hook, or he's a
// remote user and his own server set the modes), then set them internally now
- memb->modes = *privs;
for (std::string::const_iterator i = privs->begin(); i != privs->end(); ++i)
{
- ModeHandler* mh = ServerInstance->Modes->FindMode(*i, MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(*i);
if (mh)
{
std::string nick = user->nick;
- /* Set, and make sure that the mode handler knows this mode was now set */
- this->SetPrefix(user, mh->GetModeChar(), true);
- mh->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, nick, true);
+ // Set the mode on the user
+ mh->OnModeChange(ServerInstance->FakeClient, NULL, this, nick, true);
}
}
}
// Tell modules about this join, they have the chance now to populate except_list with users we won't send the JOIN (and possibly MODE) to
CUList except_list;
- FOREACH_MOD(I_OnUserJoin,OnUserJoin(memb, bursting, created_by_local, except_list));
+ FOREACH_MOD(OnUserJoin, (memb, bursting, created_by_local, except_list));
this->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", this->name.c_str());
{
if (this->topicset)
{
- user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), this->name.c_str(), this->topic.c_str());
- user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), this->name.c_str(), this->setby.c_str(), (unsigned long)this->topicset);
+ user->WriteNumeric(RPL_TOPIC, "%s :%s", this->name.c_str(), this->topic.c_str());
+ user->WriteNumeric(RPL_TOPICTIME, "%s %s %lu", this->name.c_str(), this->setby.c_str(), (unsigned long)this->topicset);
}
this->UserList(user);
}
- FOREACH_MOD(I_OnPostJoin,OnPostJoin(memb));
+ FOREACH_MOD(OnPostJoin, (memb));
}
bool Channel::IsBanned(User* user)
{
Membership* memb = membiter->second;
CUList except_list;
- FOREACH_MOD(I_OnUserPart,OnUserPart(memb, reason, except_list));
+ FOREACH_MOD(OnUserPart, (memb, reason, except_list));
WriteAllExcept(user, false, 0, except_list, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str());
// Remove this channel from the user's chanlist
- user->chans.erase(this);
+ user->chans.erase(memb);
// Remove the Membership from this channel's userlist and destroy it
this->DelUser(membiter);
}
if (!memb)
{
- src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), victim->nick.c_str(), this->name.c_str());
+ src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s :They are not on that channel", victim->nick.c_str(), this->name.c_str());
return;
}
if (them < req)
{
- src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",
- src->nick.c_str(), this->name.c_str(), req > HALFOP_VALUE ? "" : "half-");
+ src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must be a channel %soperator",
+ this->name.c_str(), req > HALFOP_VALUE ? "" : "half-");
return;
}
}
}
CUList except_list;
- FOREACH_MOD(I_OnUserKick,OnUserKick(src, memb, reason, except_list));
+ FOREACH_MOD(OnUserKick, (src, memb, reason, except_list));
WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), victim->nick.c_str(), reason.c_str());
- victim->chans.erase(this);
+ victim->chans.erase(memb);
this->DelUser(victimiter);
}
unsigned int minrank = 0;
if (status)
{
- ModeHandler* mh = ServerInstance->Modes->FindPrefix(status);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefix(status);
if (mh)
minrank = mh->GetPrefixRank();
}
if(this->modes[n])
{
scratch.push_back(n + 65);
+ ModeHandler* mh = ServerInstance->Modes->FindMode(n+'A', MODETYPE_CHANNEL);
+ if (!mh)
+ continue;
+
if (n == 'k' - 65 && !showkey)
{
sparam += " <key>";
}
else
{
- const std::string param = this->GetModeParameter(n + 65);
+ const std::string param = this->GetModeParameter(mh);
if (!param.empty())
{
sparam += ' ';
*/
void Channel::UserList(User *user)
{
- if (this->IsModeSet('s') && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex"))
+ bool has_privs = user->HasPrivPermission("channels/auspex");
+ if (this->IsModeSet(secretmode) && !this->HasUser(user) && !has_privs)
{
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", this->name.c_str());
return;
}
- std::string list = user->nick;
- list.push_back(' ');
- list.push_back(this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=');
+ std::string list;
+ list.push_back(this->IsModeSet(secretmode) ? '@' : this->IsModeSet(privatemode) ? '*' : '=');
list.push_back(' ');
list.append(this->name).append(" :");
std::string::size_type pos = list.size();
std::string nick;
for (UserMembIter i = userlist.begin(); i != userlist.end(); ++i)
{
- if (i->first->quitting)
- continue;
- if ((!has_user) && (i->first->IsModeSet('i')))
+ if ((!has_user) && (i->first->IsModeSet(invisiblemode)) && (!has_privs))
{
/*
* user is +i, and source not on the channel, does not show
prefixlist = this->GetPrefixChar(i->first);
nick = i->first->nick;
- FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick));
+ FOREACH_MOD(OnNamesListItem, (user, i->second, prefixlist, nick));
/* Nick was nuked, a module wants us to skip it */
if (nick.empty())
user->WriteNumeric(RPL_NAMREPLY, list);
}
- user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
+ user->WriteNumeric(RPL_ENDOFNAMES, "%s :End of /NAMES list.", this->name.c_str());
}
/* returns the status character for a given user on a channel, e.g. @ for op,
{
for(unsigned int i=0; i < m->second->modes.length(); i++)
{
- char mchar = m->second->modes[i];
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(m->second->modes[i]);
if (mh && mh->GetPrefixRank() > bestrank && mh->GetPrefix())
{
bestrank = mh->GetPrefixRank();
unsigned int rv = 0;
if (mchar)
{
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar);
if (mh)
rv = mh->GetPrefixRank();
}
{
for(unsigned int i=0; i < m->second->modes.length(); i++)
{
- char mchar = m->second->modes[i];
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(m->second->modes[i]);
if (mh && mh->GetPrefix())
prefix[ctr++] = mh->GetPrefix();
}
return m->second->getRank();
}
-bool Channel::SetPrefix(User* user, char prefix, bool adding)
+bool Membership::SetPrefix(PrefixMode* delta_mh, bool adding)
{
- ModeHandler* delta_mh = ServerInstance->Modes->FindMode(prefix, MODETYPE_CHANNEL);
- if (!delta_mh)
- return false;
- UserMembIter m = userlist.find(user);
- if (m == userlist.end())
- return false;
- for(unsigned int i=0; i < m->second->modes.length(); i++)
+ char prefix = delta_mh->GetModeChar();
+ for (unsigned int i = 0; i < modes.length(); i++)
{
- char mchar = m->second->modes[i];
- ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL);
+ char mchar = modes[i];
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(mchar);
if (mh && mh->GetPrefixRank() <= delta_mh->GetPrefixRank())
{
- m->second->modes =
- m->second->modes.substr(0,i) +
+ modes = modes.substr(0,i) +
(adding ? std::string(1, prefix) : "") +
- m->second->modes.substr(mchar == prefix ? i+1 : i);
+ modes.substr(mchar == prefix ? i+1 : i);
return adding != (mchar == prefix);
}
}
if (adding)
- m->second->modes += std::string(1, prefix);
+ modes.push_back(prefix);
return adding;
}
else
{
inv = new Invitation(c, u, timeout);
- c->invites.push_back(inv);
- u->invites.push_back(inv);
+ c->invites.push_front(inv);
+ u->invites.push_front(inv);
ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Create created new invitation %p", (void*) inv);
}
}
if (!u || u->invites.empty())
return NULL;
- InviteList locallist;
- locallist.swap(u->invites);
-
Invitation* result = NULL;
- for (InviteList::iterator i = locallist.begin(); i != locallist.end(); )
+ for (InviteList::iterator i = u->invites.begin(); i != u->invites.end(); )
{
Invitation* inv = *i;
+ ++i;
+
if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time()))
{
/* Expired invite, remove it. */
- std::string expiration = ServerInstance->TimeString(inv->expiry);
+ std::string expiration = InspIRCd::TimeString(inv->expiry);
ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str());
- i = locallist.erase(i);
- inv->cull();
delete inv;
}
else
result = inv;
break;
}
- ++i;
}
}
- locallist.swap(u->invites);
ServerInstance->Logs->Log("INVITATION", LOG_DEBUG, "Invitation::Find result=%p", (void*) result);
return result;
}
Invitation::~Invitation()
{
// Remove this entry from both lists
- InviteList::iterator it = std::find(chan->invites.begin(), chan->invites.end(), this);
- if (it != chan->invites.end())
- chan->invites.erase(it);
- it = std::find(user->invites.begin(), user->invites.end(), this);
- if (it != user->invites.end())
- user->invites.erase(it);
-}
-
-void InviteBase::ClearInvites()
-{
- ServerInstance->Logs->Log("INVITEBASE", LOG_DEBUG, "InviteBase::ClearInvites %p", (void*) this);
- InviteList locallist;
- locallist.swap(invites);
- for (InviteList::const_iterator i = locallist.begin(); i != locallist.end(); ++i)
- {
- (*i)->cull();
- delete *i;
- }
+ chan->invites.erase(this);
+ user->invites.erase(this);
+ ServerInstance->Logs->Log("INVITEBASE", LOG_DEBUG, "Invitation::~ %p", (void*) this);
}