]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/users.cpp
Extra debug
[user/henk/code/inspircd.git] / src / users.cpp
index f6ef92af336e40fcca24c991fecd0dfb40119275..387658ac6d3deb92625a4cfce970703a3a71e693 100644 (file)
 #include "bancache.h"
 #include "commands/cmd_whowas.h"
 
-static unsigned long already_sent[MAX_DESCRIPTORS] = {0};
+static unsigned long* already_sent = NULL;
+
+
+void InitializeAlreadySent(SocketEngine* SE)
+{
+       already_sent = new unsigned long[SE->GetMaxFds()];
+       memset(already_sent, 0, sizeof(already_sent));
+}
 
 /* XXX: Used for speeding up WriteCommon operations */
-unsigned long uniq_id = 0;
+unsigned long uniq_id = 1;
 
 std::string User::ProcessNoticeMasks(const char *sm)
 {
@@ -73,6 +80,9 @@ std::string User::ProcessNoticeMasks(const char *sm)
                                                output += *c;
                                        }
                                }
+                               else
+                                       this->WriteNumeric(501, "%s %c :is unknown snomask char to me", this->nick, *c);
+
                                oldadding = adding;
                        break;
                }
@@ -177,7 +187,7 @@ User::User(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance
        *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = *uuid = 0;
        server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);
        reset_due = ServerInstance->Time();
-       age = ServerInstance->Time(true);
+       age = ServerInstance->Time();
        Penalty = 0;
        lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;
        ChannelCount = timeout = bytes_in = bytes_out = cmds_in = cmds_out = 0;
@@ -190,6 +200,9 @@ User::User(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance
        Visibility = NULL;
        ip = NULL;
        MyClass = NULL;
+       io = NULL;
+       AllowedUserModes = NULL;
+       AllowedChanModes = NULL;
        AllowedOperCommands = NULL;
        chans.clear();
        invites.clear();
@@ -218,7 +231,7 @@ User::~User()
        if (this->MyClass)
        {
                this->MyClass->RefCount--;
-               ServerInstance->Logs->Log("USERS", DEBUG, "User destructor -- connect refcount now: %u", this->MyClass->RefCount);
+               ServerInstance->Logs->Log("USERS", DEBUG, "User destructor -- connect refcount now: %lu", this->MyClass->RefCount);
        }
        if (this->AllowedOperCommands)
        {
@@ -226,6 +239,18 @@ User::~User()
                AllowedOperCommands = NULL;
        }
 
+       if (this->AllowedUserModes)
+       {
+               delete[] AllowedUserModes;
+               AllowedUserModes = NULL;
+       }
+
+       if (this->AllowedChanModes)
+       {
+               delete[] AllowedChanModes;
+               AllowedChanModes = NULL;
+       }
+
        this->InvalidateCache();
        this->DecrementModes();
 
@@ -290,8 +315,11 @@ char* User::MakeHostIP()
 
 void User::CloseSocket()
 {
-       ServerInstance->SE->Shutdown(this, 2);
-       ServerInstance->SE->Close(this);
+       if (this->fd > -1)
+       {
+               ServerInstance->SE->Shutdown(this, 2);
+               ServerInstance->SE->Close(this);
+       }
 }
 
 char* User::GetFullHost()
@@ -434,6 +462,21 @@ void User::RemoveInvite(const irc::string &channel)
        }
 }
 
+bool User::HasModePermission(unsigned char mode, ModeType type)
+{
+       if (!IS_LOCAL(this))
+               return true;
+
+       if (!IS_OPER(this))
+               return false;
+
+       if (!AllowedUserModes || !AllowedChanModes)
+               return false;
+
+       return ((type == MODETYPE_USER ? AllowedUserModes : AllowedChanModes))[(mode - 'A')];
+       
+}
+
 bool User::HasPermission(const std::string &command)
 {
        /*
@@ -487,7 +530,7 @@ bool User::AddBuffer(std::string a)
                if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
                {
                        this->SetWriteError("RecvQ exceeded");
-                       ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->MyClass->GetRecvqMax());
+                       ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %lu exceeds connect class maximum of %lu",this->nick,(unsigned long int)recvq.length(),this->MyClass->GetRecvqMax());
                        return false;
                }
 
@@ -564,7 +607,7 @@ void User::AddWriteBuf(const std::string &data)
                 * to repeatedly add the text to the sendq!
                 */
                this->SetWriteError("SendQ exceeded");
-               ServerInstance->SNO->WriteToSnoMask('A', "User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->MyClass->GetSendqMax());
+               ServerInstance->SNO->WriteToSnoMask('A', "User %s SendQ of %lu exceeds connect class maximum of %lu",this->nick,(unsigned long int)sendq.length() + data.length(),this->MyClass->GetSendqMax());
                return;
        }
 
@@ -666,6 +709,15 @@ void User::Oper(const std::string &opertype, const std::string &opername)
                        else
                                AllowedOperCommands = new std::map<std::string, bool>;
 
+                       if (!AllowedChanModes)
+                               AllowedChanModes = new bool[64];
+
+                       if (!AllowedUserModes)
+                               AllowedUserModes = new bool[64];
+
+                       memset(AllowedUserModes, 0, 64);
+                       memset(AllowedChanModes, 0, 64);
+
                        char* Classes = strdup(iter_opertype->second);
                        char* myclass = strtok_r(Classes," ",&savept);
                        while (myclass)
@@ -673,7 +725,7 @@ void User::Oper(const std::string &opertype, const std::string &opername)
                                operclass_t::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass);
                                if (iter_operclass != ServerInstance->Config->operclass.end())
                                {
-                                       char* CommandList = strdup(iter_operclass->second);
+                                       char* CommandList = strdup(iter_operclass->second.commandlist);
                                        mycmd = strtok_r(CommandList," ",&savept2);
                                        while (mycmd)
                                        {
@@ -681,6 +733,29 @@ void User::Oper(const std::string &opertype, const std::string &opername)
                                                mycmd = strtok_r(NULL," ",&savept2);
                                        }
                                        free(CommandList);
+                                       this->AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want.
+                                       for (unsigned char* c = (unsigned char*)iter_operclass->second.umodelist; *c; ++c)
+                                       {
+                                               if (*c == '*')
+                                               {
+                                                       memset(this->AllowedUserModes, (int)(true), 64);
+                                               }
+                                               else
+                                               {
+                                                       this->AllowedUserModes[*c - 'A'] = true;
+                                               }
+                                       }
+                                       for (unsigned char* c = (unsigned char*)iter_operclass->second.cmodelist; *c; ++c)
+                                       {
+                                               if (*c == '*')
+                                               {
+                                                       memset(this->AllowedChanModes, (int)(true), 64);
+                                               }
+                                               else
+                                               {
+                                                       this->AllowedChanModes[*c - 'A'] = true;
+                                               }
+                                       }
                                }
                                myclass = strtok_r(NULL," ",&savept);
                        }
@@ -692,7 +767,7 @@ void User::Oper(const std::string &opertype, const std::string &opername)
 
        catch (...)
        {
-               ServerInstance->Log(DEBUG,"Exception in User::Oper()");
+               ServerInstance->Logs->Log("OPER", DEBUG,"Exception in User::Oper()");
        }
 }
 
@@ -700,11 +775,27 @@ void User::UnOper()
 {
        if (IS_OPER(this))
        {
-               // unset their oper type (what IS_OPER checks), and remove +o
+               /* Remove all oper only modes from the user when the deoper - Bug #466*/
+               std::string moderemove("-");
+
+               for (unsigned char letter = 'A'; letter <= 'z'; letter++)
+               {
+                       if (letter != 'o')
+                       {
+                               ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER);
+                               if (mh && mh->NeedsOper())
+                                       moderemove += letter;
+                       }
+               }
+
+               const char* parameters[] = { this->nick, moderemove.c_str() };
+               ServerInstance->Parser->CallHandler("MODE", parameters, 2, this);
+
+               /* unset their oper type (what IS_OPER checks), and remove +o */
                *this->oper = 0;
                this->modes[UM_OPERATOR] = 0;
                        
-               // remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404
+               /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
                ServerInstance->Users->all_opers.remove(this);
 
                if (AllowedOperCommands)
@@ -712,6 +803,17 @@ void User::UnOper()
                        delete AllowedOperCommands;
                        AllowedOperCommands = NULL;
                }
+               if (AllowedUserModes)
+               {
+                       delete[] AllowedUserModes;
+                       AllowedUserModes = NULL;
+               }
+               if (AllowedChanModes)
+               {
+                       delete[] AllowedChanModes;
+                       AllowedChanModes = NULL;
+               }
+
        }
 }
 
@@ -814,14 +916,13 @@ void User::FullConnect()
        }
 
        this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network);
-       this->WriteServ("001 %s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host);
-       this->WriteServ("002 %s :Your host is %s, running version %s",this->nick,ServerInstance->Config->ServerName,VERSION);
-       this->WriteServ("003 %s :This server was created %s %s", this->nick, __TIME__, __DATE__);
-       this->WriteServ("004 %s %s %s %s %s %s", this->nick, ServerInstance->Config->ServerName, VERSION, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());
+       this->WriteNumeric(001, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host);
+       this->WriteNumeric(002, "%s :Your host is %s, running version InspIRCd-1.2",this->nick,ServerInstance->Config->ServerName);
+       this->WriteNumeric(003, "%s :This server was created %s %s", this->nick, __TIME__, __DATE__);
+       this->WriteNumeric(004, "%s %s InspIRCd-1.2 %s %s %s", this->nick, ServerInstance->Config->ServerName, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());
 
        ServerInstance->Config->Send005(this);
-
-       this->WriteServ("042 %s %s :your unique ID", this->nick, this->uuid);
+       this->WriteNumeric(42, "%s %s :your unique ID", this->nick, this->uuid);
 
 
        this->ShowMOTD();
@@ -888,46 +989,29 @@ void User::InvalidateCache()
 
 bool User::ForceNickChange(const char* newnick)
 {
-       /*
-        * XXX this makes no sense..
-        * why do we do nothing for change on users not REG_ALL?
-        * why do we trigger events twice for everyone previously (and just them now)
-        * i think the first if () needs removing totally, or? -- w00t
-        */
-       if (this->registered != REG_ALL)
-       {
-               int MOD_RESULT = 0;
-
-               this->InvalidateCache();
+       int MOD_RESULT = 0;
 
-               FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick));
+       this->InvalidateCache();
 
-               if (MOD_RESULT)
-               {
-                       ServerInstance->stats->statsCollisions++;
-                       return false;
-               }
+       FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick));
 
-               if (ServerInstance->XLines->MatchesLine("Q",newnick))
-               {
-                       ServerInstance->stats->statsCollisions++;
-                       return false;
-               }
+       if (MOD_RESULT)
+       {
+               ServerInstance->stats->statsCollisions++;
+               return false;
        }
-       else
+
+       std::deque<classbase*> dummy;
+       Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
+       if (nickhandler) // wtfbbq, when would this not be here
        {
-               std::deque<classbase*> dummy;
-               Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
-               if (nickhandler) // wtfbbq, when would this not be here
-               {
-                       nickhandler->HandleInternal(1, dummy);
-                       bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);
-                       nickhandler->HandleInternal(0, dummy);
-                       return result;
-               }
+               nickhandler->HandleInternal(1, dummy);
+               bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);
+               nickhandler->HandleInternal(0, dummy);
+               return result;
        }
 
-       // Unreachable.
+       // Unreachable, we hope
        return false;
 }
 
@@ -958,7 +1042,7 @@ void User::SetSockAddr(int protocol_family, const char* sip, int port)
                }
                break;
                default:
-                       ServerInstance->Log(DEBUG,"Uh oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick);
+                       ServerInstance->Logs->Log("USERS",DEBUG,"Uh oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick);
                break;
        }
 }
@@ -1070,22 +1154,22 @@ void User::Write(std::string text)
        }
        catch (...)
        {
-               ServerInstance->Log(DEBUG,"Exception in User::Write() std::string::append");
+               ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"Exception in User::Write() std::string::append");
                return;
        }
 
-       if (ServerInstance->Config->GetIOHook(this->GetPort()))
+       if (this->io)
        {
                /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
                 * implement their own buffering mechanisms
                 */
                try
                {
-                       ServerInstance->Config->GetIOHook(this->GetPort())->OnRawSocketWrite(this->fd, text.data(), text.length());
+                       this->io->OnRawSocketWrite(this->fd, text.data(), text.length());
                }
                catch (CoreException& modexcept)
                {
-                       ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+                       ServerInstance->Logs->Log("USEROUTPUT", DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
                }
        }
        else
@@ -1134,6 +1218,32 @@ void User::WriteServ(const char* text, ...)
 }
 
 
+void User::WriteNumeric(unsigned int numeric, const char* text, ...)
+{
+       va_list argsPtr;
+       char textbuffer[MAXBUF];
+
+       va_start(argsPtr, text);
+       vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+       va_end(argsPtr);
+
+       this->WriteNumeric(numeric, std::string(textbuffer));
+}
+
+void User::WriteNumeric(unsigned int numeric, const std::string &text)
+{
+       char textbuffer[MAXBUF];
+       int MOD_RESULT = 0;
+
+       FOREACH_RESULT(I_OnNumeric, OnNumeric(this, numeric, text));
+
+       if (MOD_RESULT)
+               return;
+
+       snprintf(textbuffer,MAXBUF,":%s %03u %s",ServerInstance->Config->ServerName, numeric, text.c_str());
+       this->Write(std::string(textbuffer));
+}
+
 void User::WriteFrom(User *user, const std::string &text)
 {
        char tb[MAXBUF];
@@ -1204,6 +1314,9 @@ void User::WriteCommon(const std::string &text)
 
        uniq_id++;
 
+       if (!already_sent)
+               InitializeAlreadySent(ServerInstance->SE);
+
        /* We dont want to be doing this n times, just once */
        snprintf(tb,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());
        std::string out = tb;
@@ -1258,6 +1371,10 @@ void User::WriteCommonQuit(const std::string &normal_text, const std::string &op
                return;
 
        uniq_id++;
+
+       if (!already_sent)
+               InitializeAlreadySent(ServerInstance->SE);
+
        snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost(),normal_text.c_str());
        snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost(),oper_text.c_str());
        std::string out1 = tb1;
@@ -1289,6 +1406,10 @@ void User::WriteCommonExcept(const std::string &text)
                return;
 
        uniq_id++;
+
+       if (!already_sent)
+               InitializeAlreadySent(ServerInstance->SE);
+
        snprintf(tb1,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());
        out1 = tb1;
 
@@ -1312,7 +1433,7 @@ void User::WriteCommonExcept(const std::string &text)
 
 void User::WriteWallOps(const std::string &text)
 {
-       if (!IS_OPER(this) && IS_LOCAL(this))
+       if (!IS_LOCAL(this))
                return;
 
        std::string wallop("WALLOPS :");
@@ -1328,6 +1449,9 @@ void User::WriteWallOps(const std::string &text)
 
 void User::WriteWallOps(const char* text, ...)
 {
+       if (!IS_LOCAL(this))
+               return;
+
        char textbuffer[MAXBUF];
        va_list argsPtr;
 
@@ -1419,7 +1543,7 @@ bool User::ChangeDisplayedHost(const char* shost)
        }
 
        if (IS_LOCAL(this))
-               this->WriteServ("396 %s %s :is now your displayed host",this->nick,this->dhost);
+               this->WriteNumeric(396, "%s %s :is now your displayed host",this->nick,this->dhost);
 
        return true;
 }
@@ -1590,7 +1714,7 @@ ConnectClass* User::SetClass(const std::string &explicit_name)
                /* deny change if change will take class over the limit */
                if (found->limit && (found->RefCount + 1 >= found->limit))
                {
-                       ServerInstance->Log(DEBUG, "OOPS: Connect class limit (%u) hit, denying", found->limit);
+                       ServerInstance->Logs->Log("USERS", DEBUG, "OOPS: Connect class limit (%lu) hit, denying", found->limit);
                        return this->MyClass;
                }
 
@@ -1600,12 +1724,12 @@ ConnectClass* User::SetClass(const std::string &explicit_name)
                        if (found == this->MyClass) // no point changing this shit :P
                                return this->MyClass;
                        this->MyClass->RefCount--;
-                       ServerInstance->Log(DEBUG, "Untying user from connect class -- refcount: %u", this->MyClass->RefCount);
+                       ServerInstance->Logs->Log("USERS", DEBUG, "Untying user from connect class -- refcount: %lu", this->MyClass->RefCount);
                }
 
                this->MyClass = found;
                this->MyClass->RefCount++;
-               ServerInstance->Log(DEBUG, "User tied to new class -- connect refcount now: %u", this->MyClass->RefCount);
+               ServerInstance->Logs->Log("USERS", DEBUG, "User tied to new class -- connect refcount now: %lu", this->MyClass->RefCount);
        }
 
        return this->MyClass;
@@ -1638,7 +1762,7 @@ void User::PurgeEmptyChannels()
                        }
                        catch (...)
                        {
-                               ServerInstance->Log(DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()");
+                               ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()");
                        }
                }
        }
@@ -1663,31 +1787,31 @@ void User::ShowMOTD()
 {
        if (!ServerInstance->Config->MOTD.size())
        {
-               this->WriteServ("422 %s :Message of the day file is missing.",this->nick);
+               this->WriteNumeric(422, "%s :Message of the day file is missing.",this->nick);
                return;
        }
-       this->WriteServ("375 %s :%s message of the day", this->nick, ServerInstance->Config->ServerName);
+       this->WriteNumeric(375, "%s :%s message of the day", this->nick, ServerInstance->Config->ServerName);
 
        for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++)
-               this->WriteServ("372 %s :- %s",this->nick,i->c_str());
+               this->WriteNumeric(372, "%s :- %s",this->nick,i->c_str());
 
-       this->WriteServ("376 %s :End of message of the day.", this->nick);
+       this->WriteNumeric(376, "%s :End of message of the day.", this->nick);
 }
 
 void User::ShowRULES()
 {
        if (!ServerInstance->Config->RULES.size())
        {
-               this->WriteServ("434 %s :RULES File is missing",this->nick);
+               this->WriteNumeric(434, "%s :RULES File is missing",this->nick);
                return;
        }
 
-       this->WriteServ("308 %s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName);
+       this->WriteNumeric(308, "%s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName);
 
        for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++)
-               this->WriteServ("232 %s :- %s",this->nick,i->c_str());
+               this->WriteNumeric(232, "%s :- %s",this->nick,i->c_str());
 
-       this->WriteServ("309 %s :End of RULES command.",this->nick);
+       this->WriteNumeric(309, "%s :End of RULES command.",this->nick);
 }
 
 void User::HandleEvent(EventType et, int errornum)
@@ -1716,7 +1840,7 @@ void User::HandleEvent(EventType et, int errornum)
        }
        catch (...)
        {
-               ServerInstance->Log(DEBUG,"Exception in User::HandleEvent intercepted");
+               ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::HandleEvent intercepted");
        }
 
        /* If the user has raised an error whilst being processed, quit them now we're safe to */