#include "xline.h"
#include "cull_list.h"
-extern InspIRCd* ServerInstance;
extern std::vector<Module*> modules;
extern std::vector<ircd_module*> factory;
-extern std::vector<InspSocket*> module_sockets;
extern int MODCOUNT;
extern time_t TIME;
extern Server* MyServer;
-extern std::vector<userrec*> local_users;
irc::whowas::whowas_users whowas;
static unsigned long already_sent[MAX_DESCRIPTORS] = {0};
log(DEBUG,"Commencing reverse lookup");
try
{
- res_reverse = new UserResolver(this, this->GetIPString(), false);
+ log(DEBUG,"Passing instance: %08x",this->ServerInstance);
+ res_reverse = new UserResolver(this->ServerInstance, this, this->GetIPString(), false);
MyServer->AddResolver(res_reverse);
}
catch (ModuleException& e)
}
}
-UserResolver::UserResolver(userrec* user, std::string to_resolve, bool forward) : Resolver(to_resolve, forward ? DNS_QUERY_FORWARD : DNS_QUERY_REVERSE), bound_user(user)
+UserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_resolve, bool forward) :
+ Resolver(Instance, to_resolve, forward ? DNS_QUERY_FORWARD : DNS_QUERY_REVERSE), bound_user(user)
{
this->fwd = forward;
this->bound_fd = user->fd;
this->bound_user->stored_host = result;
try
{
- bound_user->res_forward = new UserResolver(this->bound_user, result, true);
+ bound_user->res_forward = new UserResolver(this->ServerInstance, this->bound_user, result, true);
MyServer->AddResolver(bound_user->res_forward);
}
catch (ModuleException& e)
return data;
}
-userrec::userrec()
+userrec::userrec(InspIRCd* Instance) : ServerInstance(Instance)
{
+ log(DEBUG,"userrec::userrec(): Instance: %08x",ServerInstance);
// the PROPER way to do it, AVOID bzero at *ALL* costs
*password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = 0;
- server = (char*)ServerInstance->FindServerNamePtr(ServerInstance->Config->ServerName);
+ server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);
reset_due = TIME;
lines_in = fd = lastping = signon = idle_lastmsg = nping = registered = 0;
timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;
if (recvq.length() > (unsigned)this->recvqmax)
{
this->SetWriteError("RecvQ exceeded");
- WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
+ ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
return false;
}
* to repeatedly add the text to the sendq!
*/
this->SetWriteError("SendQ exceeded");
- WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
+ ServerInstance->WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
return;
}
}
}
-void userrec::QuitUser(userrec *user,const std::string &quitreason)
+void userrec::QuitUser(InspIRCd* Instance, userrec *user,const std::string &quitreason)
{
- user_hash::iterator iter = ServerInstance->clientlist.find(user->nick);
+ user_hash::iterator iter = Instance->clientlist.find(user->nick);
/*
* I'm pretty sure returning here is causing a desync when part of the net thinks a user is gone,
if (user->registered == REG_ALL)
{
- purge_empty_chans(user);
- FOREACH_MOD(I_OnUserQuit,OnUserQuit(user,reason));
+ user->PurgeEmptyChannels();
+ FOREACH_MOD_I(Instance,I_OnUserQuit,OnUserQuit(user,reason));
user->WriteCommonExcept("QUIT :%s",reason.c_str());
}
if (IS_LOCAL(user))
user->FlushWriteBuf();
- FOREACH_MOD(I_OnUserDisconnect,OnUserDisconnect(user));
+ FOREACH_MOD_I(Instance,I_OnUserDisconnect,OnUserDisconnect(user));
if (IS_LOCAL(user))
{
- if (ServerInstance->Config->GetIOHook(user->GetPort()))
+ if (Instance->Config->GetIOHook(user->GetPort()))
{
try
{
- ServerInstance->Config->GetIOHook(user->GetPort())->OnRawSocketClose(user->fd);
+ Instance->Config->GetIOHook(user->GetPort())->OnRawSocketClose(user->fd);
}
catch (ModuleException& modexcept)
{
}
}
- ServerInstance->SE->DelFd(user->fd);
+ Instance->SE->DelFd(user->fd);
user->CloseSocket();
}
/*
- * this must come before the WriteOpers so that it doesnt try to fill their buffer with anything
+ * this must come before the ServerInstance->WriteOpers so that it doesnt try to fill their buffer with anything
* if they were an oper with +s.
*
* XXX -
if (user->registered == REG_ALL)
{
if (IS_LOCAL(user))
- WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason.c_str());
+ Instance->WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason.c_str());
user->AddToWhoWas();
}
- if (iter != ServerInstance->clientlist.end())
+ if (iter != Instance->clientlist.end())
{
log(DEBUG,"deleting user hash value %lx",(unsigned long)user);
if (IS_LOCAL(user))
{
- ServerInstance->fd_ref_table[user->fd] = NULL;
- if (find(local_users.begin(),local_users.end(),user) != local_users.end())
- local_users.erase(find(local_users.begin(),local_users.end(),user));
+ Instance->fd_ref_table[user->fd] = NULL;
+ if (find(Instance->local_users.begin(),Instance->local_users.end(),user) != Instance->local_users.end())
+ Instance->local_users.erase(find(Instance->local_users.begin(),Instance->local_users.end(),user));
}
- ServerInstance->clientlist.erase(iter);
+ Instance->clientlist.erase(iter);
DELETE(user);
}
}
}
/* add a client connection to the sockets list */
-void userrec::AddClient(int socket, int port, bool iscached, insp_inaddr ip)
+void userrec::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, insp_inaddr ip)
{
std::string tempnick = ConvToStr(socket) + "-unknown";
- user_hash::iterator iter = ServerInstance->clientlist.find(tempnick);
+ user_hash::iterator iter = Instance->clientlist.find(tempnick);
const char *ipaddr = insp_ntoa(ip);
userrec* _new;
int j = 0;
* this was probably the cause of 'server ignores me when i hammer it with reconnects'
* issue in earlier alphas/betas
*/
- if (iter != ServerInstance->clientlist.end())
+ if (iter != Instance->clientlist.end())
{
userrec* goner = iter->second;
DELETE(goner);
- ServerInstance->clientlist.erase(iter);
+ Instance->clientlist.erase(iter);
}
log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr);
- _new = new userrec();
- ServerInstance->clientlist[tempnick] = _new;
+ _new = new userrec(Instance);
+ Instance->clientlist[tempnick] = _new;
_new->fd = socket;
strlcpy(_new->nick,tempnick.c_str(),NICKMAX-1);
- _new->server = ServerInstance->FindServerNamePtr(ServerInstance->Config->ServerName);
+ _new->server = Instance->FindServerNamePtr(Instance->Config->ServerName);
/* We don't need range checking here, we KNOW 'unknown\0' will fit into the ident field. */
strcpy(_new->ident, "unknown");
_new->registered = REG_NONE;
- _new->signon = TIME + ServerInstance->Config->dns_timeout;
+ _new->signon = TIME + Instance->Config->dns_timeout;
_new->lastping = 1;
log(DEBUG,"Setting socket addresses");
long class_sqmax = 262144; // 256kb
long class_rqmax = 4096; // 4k
- for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+ for (ClassVector::iterator i = Instance->Config->Classes.begin(); i != Instance->Config->Classes.end(); i++)
{
if ((i->type == CC_ALLOW) && (match(ipaddr,i->host.c_str(),true)))
{
}
}
- _new->nping = TIME + _new->pingmax + ServerInstance->Config->dns_timeout;
+ _new->nping = TIME + _new->pingmax + Instance->Config->dns_timeout;
_new->timeout = TIME+class_regtimeout;
_new->flood = class_flood;
_new->threshold = class_threshold;
_new->sendqmax = class_sqmax;
_new->recvqmax = class_rqmax;
- ServerInstance->fd_ref_table[socket] = _new;
- local_users.push_back(_new);
+ Instance->fd_ref_table[socket] = _new;
+ Instance->local_users.push_back(_new);
- if (local_users.size() > ServerInstance->Config->SoftLimit)
+ if (Instance->local_users.size() > Instance->Config->SoftLimit)
{
- userrec::QuitUser(_new,"No more connections allowed");
+ userrec::QuitUser(Instance, _new,"No more connections allowed");
return;
}
- if (local_users.size() >= MAXCLIENTS)
+ if (Instance->local_users.size() >= MAXCLIENTS)
{
- userrec::QuitUser(_new,"No more connections allowed");
+ userrec::QuitUser(Instance, _new,"No more connections allowed");
return;
}
*/
if ((unsigned)socket >= MAX_DESCRIPTORS)
{
- userrec::QuitUser(_new,"Server is full");
+ userrec::QuitUser(Instance, _new,"Server is full");
return;
}
char* e = matches_exception(ipaddr);
{
char reason[MAXBUF];
snprintf(reason,MAXBUF,"Z-Lined: %s",r);
- userrec::QuitUser(_new,reason);
+ userrec::QuitUser(Instance, _new,reason);
return;
}
}
if (socket > -1)
{
- if (!ServerInstance->SE->AddFd(socket,true,X_ESTAB_CLIENT))
+ if (!Instance->SE->AddFd(socket,true,X_ESTAB_CLIENT))
{
- userrec::QuitUser(_new, "Internal error handling connection");
+ userrec::QuitUser(Instance, _new, "Internal error handling connection");
return;
}
}
long userrec::LocalCloneCount()
{
long x = 0;
- for (std::vector<userrec*>::const_iterator a = local_users.begin(); a != local_users.end(); a++)
+ for (std::vector<userrec*>::const_iterator a = ServerInstance->local_users.begin(); a != ServerInstance->local_users.end(); a++)
{
userrec* comp = *a;
#ifdef IPV6
ServerInstance->stats->statsConnects++;
this->idle_lastmsg = TIME;
- ConnectClass a = GetClass(this);
+ ConnectClass a = this->GetClass();
if (a.type == CC_DENY)
{
if (this->LocalCloneCount() > a.maxlocal)
{
Goners->AddItem(this, "No more connections allowed from your host via this connect class (local)");
- WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a.maxlocal, this->GetIPString());
+ ServerInstance->WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a.maxlocal, this->GetIPString());
return;
}
else if (this->GlobalCloneCount() > a.maxglobal)
{
Goners->AddItem(this, "No more connections allowed from your host via this connect class (global)");
- WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s",a.maxglobal, this->GetIPString());
+ ServerInstance->WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s",a.maxglobal, this->GetIPString());
return;
}
FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
FOREACH_MOD(I_OnGlobalConnect,OnGlobalConnect(this));
this->registered = REG_ALL;
- WriteOpers("*** Client connecting on port %d: %s!%s@%s [%s]", this->GetPort(), this->nick, this->ident, this->host, this->GetIPString());
+ ServerInstance->WriteOpers("*** Client connecting on port %d: %s!%s@%s [%s]", this->GetPort(), this->nick, this->ident, this->host, this->GetIPString());
}
/** userrec::UpdateNick()
std::string wallop = "WALLOPS :";
wallop.append(text);
- for (std::vector<userrec*>::const_iterator i = local_users.begin(); i != local_users.end(); i++)
+ for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
{
userrec* t = *i;
if ((IS_LOCAL(t)) && (t->modes[UM_WALLOPS]))
return true;
}
+void userrec::NoticeAll(char* text, ...)
+{
+ char textbuffer[MAXBUF];
+ char formatbuffer[MAXBUF];
+ va_list argsPtr;
+
+ va_start(argsPtr, text);
+ vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+ va_end(argsPtr);
+
+ snprintf(formatbuffer,MAXBUF,"NOTICE $* :%s",textbuffer);
+
+ for (std::vector<userrec*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
+ {
+ userrec* t = *i;
+ t->WriteFrom(this, std::string(formatbuffer));
+ }
+}
+
+
+std::string userrec::ChannelList(userrec* source)
+{
+ std::string list;
+ for (std::vector<ucrec*>::const_iterator i = this->chans.begin(); i != this->chans.end(); i++)
+ {
+ ucrec* rec = *i;
+
+ if(rec->channel && rec->channel->name)
+ {
+ /* If the target is the same as the sender, let them see all their channels.
+ * If the channel is NOT private/secret OR the user shares a common channel
+ * If the user is an oper, and the <options:operspywhois> option is set.
+ */
+ if ((source == this) || (*source->oper && ServerInstance->Config->OperSpyWhois) || (((!rec->channel->modes[CM_PRIVATE]) && (!rec->channel->modes[CM_SECRET])) || (rec->channel->HasUser(source))))
+ {
+ list.append(rec->channel->GetStatusChar(this)).append(rec->channel->name).append(" ");
+ }
+ }
+ }
+ return list;
+}
+
+void userrec::SplitChanList(userrec* dest, const std::string &cl)
+{
+ std::string line;
+ std::ostringstream prefix;
+ std::string::size_type start, pos, length;
+
+ prefix << ":" << ServerInstance->Config->ServerName << " 319 " << this->nick << " " << dest->nick << " :";
+ line = prefix.str();
+
+ for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
+ {
+ length = (pos == std::string::npos) ? cl.length() : pos;
+
+ if (line.length() + length - start > 510)
+ {
+ this->Write(line);
+ line = prefix.str();
+ }
+
+ if(pos == std::string::npos)
+ {
+ line += cl.substr(start, length - start);
+ break;
+ }
+ else
+ {
+ line += cl.substr(start, length - start + 1);
+ }
+ }
+
+ if (line.length())
+ {
+ this->Write(line);
+ }
+}
+
+
+/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
+ * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
+ * then their ip will be taken as 'priority' anyway, so for example,
+ * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
+ */
+ConnectClass& userrec::GetClass()
+{
+ for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
+ {
+ if ((match(this->GetIPString(),i->host.c_str(),true)) || (match(this->host,i->host.c_str())))
+ return *i;
+ }
+
+ return *(ServerInstance->Config->Classes.begin());
+}
+
+void userrec::PurgeEmptyChannels()
+{
+ std::vector<chanrec*> to_delete;
+
+ // firstly decrement the count on each channel
+ for (std::vector<ucrec*>::iterator f = this->chans.begin(); f != this->chans.end(); f++)
+ {
+ ucrec* uc = *f;
+ if (uc->channel)
+ {
+ if (uc->channel->DelUser(this) == 0)
+ {
+ /* No users left in here, mark it for deletion */
+ to_delete.push_back(uc->channel);
+ uc->channel = NULL;
+ }
+ }
+ }
+
+ for (std::vector<chanrec*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
+ {
+ chanrec* thischan = *n;
+ chan_hash::iterator i2 = ServerInstance->chanlist.find(thischan->name);
+ if (i2 != ServerInstance->chanlist.end())
+ {
+ FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
+ DELETE(i2->second);
+ ServerInstance->chanlist.erase(i2);
+ }
+ }
+
+ this->UnOper();
+}
+