-/* +------------------------------------+
- * | Inspire Internet Relay Chat Daemon |
- * +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2006, 2008 Oliver Lupton <oliverlupton@gmail.com>
+ * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
*
- * InspIRCd: (C) 2002-2009 InspIRCd Development Team
- * See: http://wiki.inspircd.org/Credits
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
*
- * This program is free but copyrighted software; see
- * the file COPYING for details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
*
- * ---------------------------------------------------
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
/* $Core */
#include "inspircd.h"
modes[mode-65] = mode_on;
}
-void Channel::SetModeParam(char mode, std::string parameter)
+void Channel::SetMode(ModeHandler* mh, bool on)
+{
+ modes[mh->GetModeChar() - 65] = on;
+}
+
+void Channel::SetModeParam(char mode, const std::string& parameter)
{
CustomModeList::iterator n = custom_mode_params.find(mode);
// always erase, even if changing, so that the map gets the new value
}
}
+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);
return "";
}
+std::string Channel::GetModeParameter(ModeHandler* mode)
+{
+ CustomModeList::iterator n = custom_mode_params.find(mode->GetModeChar());
+ if (n != custom_mode_params.end())
+ return n->second;
+ return "";
+}
+
int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
{
- if (u)
+ if (!u)
+ u = ServerInstance->FakeClient;
+ if (IS_LOCAL(u) && !forceset)
{
- if(!forceset)
- {
- ModResult res;
- /* 0: check status, 1: don't, -1: disallow change silently */
-
- FIRST_MOD_RESULT(OnPreTopicChange, res, (u,this,ntopic));
+ ModResult res;
+ FIRST_MOD_RESULT(OnPreTopicChange, res, (u,this,ntopic));
- if (res == MOD_RES_DENY)
+ if (res == MOD_RES_DENY)
+ return CMD_FAILURE;
+ if (res != MOD_RES_ALLOW)
+ {
+ if (!this->HasUser(u))
+ {
+ u->WriteNumeric(442, "%s %s :You're not on that channel!",u->nick.c_str(), this->name.c_str());
return CMD_FAILURE;
- if (res != MOD_RES_ALLOW)
+ }
+ if (IsModeSet('t') && !ServerInstance->OnCheckExemption(u,this,"topiclock").check(GetPrefixValue(u) >= HALFOP_VALUE))
{
- if (!this->HasUser(u))
- {
- u->WriteNumeric(442, "%s %s :You're not on that channel!",u->nick.c_str(), this->name.c_str());
- return CMD_FAILURE;
- }
- if ((this->IsModeSet('t')) && (this->GetPrefixValue(u) < HALFOP_VALUE))
- {
- u->WriteNumeric(482, "%s %s :You must be at least a half-operator to change the topic on this channel", u->nick.c_str(), this->name.c_str());
- return CMD_FAILURE;
- }
+ u->WriteNumeric(482, "%s %s :You do not have access to change the topic on this channel", u->nick.c_str(), this->name.c_str());
+ return CMD_FAILURE;
}
}
}
this->topicset = ServerInstance->Time();
- // XXX: this check for 'u' is probably pre-fake-user, and it fucking sucks anyway. we need to change this.
- if (u)
- {
- FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic));
- }
+ FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic));
return CMD_SUCCESS;
}
FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
ServerInstance->chanlist->erase(iter);
}
+
+ ClearInvites();
ServerInstance->GlobalCulls.AddItem(this);
}
}
if (!IS_LOCAL(user))
{
if (!TS)
- ServerInstance->Logs->Log("CHANNEL",DEBUG,"*** BUG *** Channel::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick.c_str(), cn);
+ ServerInstance->Logs->Log("CHANNELS",DEBUG,"*** BUG *** Channel::JoinUser called for REMOTE user '%s' on channel '%s' but no TS given!", user->nick.c_str(), cn);
}
else
{
Ptr->WriteAllExcept(user, false, 0, except_list, "JOIN :%s", Ptr->name.c_str());
/* Theyre not the first ones in here, make sure everyone else sees the modes we gave the user */
- std::string ms = ServerInstance->Modes->ModeString(user, Ptr);
- if ((Ptr->GetUserCounter() > 1) && (ms.length()))
- Ptr->WriteAllExceptSender(user, true, 0, "MODE %s +%s", Ptr->name.c_str(), ms.c_str());
+ if ((Ptr->GetUserCounter() > 1) && (!memb->modes.empty()))
+ {
+ std::string ms = memb->modes;
+ for(unsigned int i=0; i < memb->modes.length(); i++)
+ ms.append(" ").append(user->nick);
+
+ except_list.insert(user);
+ Ptr->WriteAllExcept(user, !ServerInstance->Config->CycleHostsFromUser, 0, except_list, "MODE %s +%s", Ptr->name.c_str(), ms.c_str());
+ }
- /* Major improvement by Brain - we dont need to be calculating all this pointlessly for remote users */
if (IS_LOCAL(user))
{
if (Ptr->topicset)
if (res == MOD_RES_PASSTHRU)
{
- int them = this->GetPrefixValue(src);
- int us = this->GetPrefixValue(user);
- if ((them < HALFOP_VALUE) || (them < us))
+ unsigned int them = this->GetPrefixValue(src);
+ unsigned int req = HALFOP_VALUE;
+ for (std::string::size_type i = 0; i < memb->modes.length(); i++)
+ {
+ ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL);
+ if (mh && mh->GetLevelRequired() > req)
+ req = mh->GetLevelRequired();
+ }
+
+ if (them < req)
{
- src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",src->nick.c_str(), this->name.c_str(), them >= HALFOP_VALUE ? "" : "half-");
+ src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator",
+ src->nick.c_str(), this->name.c_str(), req > HALFOP_VALUE ? "" : "half-");
return;
}
}
if (!text)
return;
- int offset = snprintf(textbuffer,MAXBUF,":%s ", user->GetFullHost().c_str());
+ int offset = snprintf(textbuffer,MAXBUF,":%s ", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str());
va_start(argsPtr, text);
vsnprintf(textbuffer + offset, MAXBUF - offset, text, argsPtr);
void Channel::RawWriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &out)
{
- char statmode = 0;
+ unsigned int minrank = 0;
if (status)
{
ModeHandler* mh = ServerInstance->Modes->FindPrefix(status);
if (mh)
- statmode = mh->GetModeChar();
+ minrank = mh->GetPrefixRank();
}
for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
{
- if ((IS_LOCAL(i->first)) && (except_list.find(i->first) == except_list.end()))
+ if (IS_LOCAL(i->first) && (except_list.find(i->first) == except_list.end()))
{
- /* User doesnt have the status we're after */
- if (statmode && !i->second->hasMode(statmode))
+ /* User doesn't have the status we're after */
+ if (minrank && i->second->getRank() < minrank)
continue;
i->first->Write(out);
{
*offset++ = n + 65;
extparam.clear();
- switch (n)
+ if (n == 'k' - 65 && !showkey)
{
- case CM_KEY:
- // Unfortunately this must be special-cased, as we definitely don't want to always display key.
- if (showkey)
- {
- extparam = this->GetModeParameter('k');
- }
- else
- {
- extparam = "<key>";
- }
- break;
- case CM_NOEXTERNAL:
- case CM_TOPICLOCK:
- case CM_INVITEONLY:
- case CM_MODERATED:
- case CM_SECRET:
- case CM_PRIVATE:
- /* We know these have no parameters */
- break;
- default:
- extparam = this->GetModeParameter(n + 65);
- break;
+ extparam = "<key>";
+ }
+ else
+ {
+ extparam = this->GetModeParameter(n + 65);
}
if (!extparam.empty())
{
{
char list[MAXBUF];
size_t dlen, curlen;
- ModResult call_modules;
if (!IS_LOCAL(user))
return;
- FIRST_MOD_RESULT(OnUserList, call_modules, (user, this));
-
- if (call_modules != MOD_RES_ALLOW)
+ if (this->IsModeSet('s') && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex"))
{
- if ((this->IsModeSet('s')) && (!this->HasUser(user)))
- {
- user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
- return;
- }
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
+ return;
}
dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
std::string prefixlist = this->GetPrefixChar(i->first);
std::string nick = i->first->nick;
- if (call_modules != MOD_RES_DENY)
- {
- FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick));
+ FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick));
- /* Nick was nuked, a module wants us to skip it */
- if (nick.empty())
- continue;
- }
+ /* Nick was nuked, a module wants us to skip it */
+ if (nick.empty())
+ continue;
size_t ptrlen = 0;
dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
ptr = list + dlen;
- ptrlen = 0;
numusers = 0;
}
return m->second->getRank();
}
-void Channel::SetPrefix(User* user, char prefix, bool adding)
+bool Channel::SetPrefix(User* user, char prefix, bool adding)
{
ModeHandler* delta_mh = ServerInstance->Modes->FindMode(prefix, MODETYPE_CHANNEL);
if (!delta_mh)
- return;
+ return false;
UserMembIter m = userlist.find(user);
if (m == userlist.end())
- return;
+ return false;
for(unsigned int i=0; i < m->second->modes.length(); i++)
{
char mchar = m->second->modes[i];
m->second->modes.substr(0,i) +
(adding ? std::string(1, prefix) : "") +
m->second->modes.substr(mchar == prefix ? i+1 : i);
- return;
+ return adding != (mchar == prefix);
}
}
if (adding)
m->second->modes += std::string(1, prefix);
+ return adding;
}
void Channel::RemoveAllPrefixes(User* user)
m->second->modes.clear();
}
}
+
+void Invitation::Create(Channel* c, LocalUser* u, time_t timeout)
+{
+ if ((timeout != 0) && (ServerInstance->Time() >= timeout))
+ // Expired, don't bother
+ return;
+
+ ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create chan=%s user=%s", c->name.c_str(), u->uuid.c_str());
+
+ Invitation* inv = Invitation::Find(c, u, false);
+ if (inv)
+ {
+ if ((inv->expiry == 0) || (inv->expiry > timeout))
+ return;
+ inv->expiry = timeout;
+ ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create changed expiry in existing invitation %p", (void*) inv);
+ }
+ else
+ {
+ inv = new Invitation(c, u, timeout);
+ c->invites.push_back(inv);
+ u->invites.push_back(inv);
+ ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Create created new invitation %p", (void*) inv);
+ }
+}
+
+Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired)
+{
+ ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find chan=%s user=%s check_expired=%d", c ? c->name.c_str() : "NULL", u ? u->uuid.c_str() : "NULL", check_expired);
+ 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(); )
+ {
+ Invitation* inv = *i;
+ if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time()))
+ {
+ /* Expired invite, remove it. */
+ ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p timed out at %lu", (void*) inv, inv->expiry);
+ i = locallist.erase(i);
+ inv->cull();
+ delete inv;
+ }
+ else
+ {
+ /* Is it what we're searching for? */
+ if (inv->chan == c)
+ {
+ result = inv;
+ break;
+ }
+ ++i;
+ }
+ }
+
+ locallist.swap(u->invites);
+ ServerInstance->Logs->Log("INVITATION", 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", 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;
+ }
+}