]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/users.cpp
Log all snomasks to "snomask" log type, level DEFAULT. This means your log gets all...
[user/henk/code/inspircd.git] / src / users.cpp
index 5b46d172c8b281f9177e1767abbdba611842b4ba..b81cd6d912d2bd6ca3bc8bbdc3833183144f12ae 100644 (file)
 #include "bancache.h"
 #include "commands/cmd_whowas.h"
 
+/* XXX: Used for speeding up WriteCommon operations */
+unsigned long uniq_id = 1;
+
 static unsigned long* already_sent = NULL;
 
 
 void InitializeAlreadySent(SocketEngine* SE)
 {
        already_sent = new unsigned long[SE->GetMaxFds()];
-       memset(already_sent, 0, sizeof(already_sent));
+       memset(already_sent, 0, SE->GetMaxFds() * sizeof(unsigned long));
 }
 
-/* XXX: Used for speeding up WriteCommon operations */
-unsigned long uniq_id = 1;
 
 std::string User::ProcessNoticeMasks(const char *sm)
 {
@@ -506,42 +507,68 @@ bool User::HasPermission(const std::string &command)
        return false;
 }
 
-/** NOTE: We cannot pass a const reference to this method.
- * The string is changed by the workings of the method,
- * so that if we pass const ref, we end up copying it to
- * something we can change anyway. Makes sense to just let
- * the compiler do that copy for us.
- */
-bool User::AddBuffer(std::string a)
+bool User::AddBuffer(const std::string &a)
 {
-       try
-       {
-               std::string::size_type i = a.rfind('\r');
+       std::string::size_type start = 0;
+       std::string::size_type i = a.find('\r');
 
+       /*
+        * The old implementation here took a copy, and rfind() on \r, removing as it found them, before
+        * copying a second time onto the recvq. That's ok, but involves three copies minimum (recv() to buffer,
+        * buffer to here, here to recvq) - The new method now copies twice (recv() to buffer, buffer to recvq).
+        *
+        * We use find() instead of rfind() for clarity, however unlike the old code, our scanning of the string is
+        * contiguous: as we specify a startpoint, we never see characters we have scanned previously, making this
+        * marginally faster in cases with a number of \r hidden early on in the buffer.
+        *
+        * How it works:
+        * Start at first pos of string, find first \r, append everything in the chunk (excluding \r) to recvq. Set
+        * i ahead of the \r, search for next \r, add next chunk to buffer... repeat.
+        *              -- w00t (7 may, 2008)
+        */
+       if (i == std::string::npos)
+       {
+               // no \r that we need to dance around, just add to buffer
+               recvq.append(a);
+       }
+       else
+       {
+               // While we can find the end of a chunk to add
                while (i != std::string::npos)
                {
-                       a.erase(i, 1);
-                       i = a.rfind('\r');
-               }
+                       // Append the chunk that we have
+                       recvq.append(a, start, (i - start));
 
-               if (a.length())
-                       recvq.append(a);
+                       // Start looking for the next one
+                       start = i + 1;
+                       i = a.find('\r', start);
+               }
 
-               if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
+               if (start != a.length())
                {
-                       this->SetWriteError("RecvQ exceeded");
-                       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;
+                       /*
+                        * This is here to catch a corner case when we get something like:
+                        * NICK w0
+                        * 0t\r\nU
+                        * SER ...
+                        * in successive calls to us.
+                        *
+                        * Without this conditional, the 'U' on the second case will be dropped,
+                        * which is most *certainly* not the behaviour we want!
+                        *              -- w00t
+                        */
+                       recvq.append(a, start, (a.length() - start));
                }
-
-               return true;
        }
 
-       catch (...)
+       if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
        {
-               ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::AddBuffer()");
+               this->SetWriteError("RecvQ exceeded");
+               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;
        }
+
+       return true;
 }
 
 bool User::BufferIsReady()
@@ -788,8 +815,11 @@ void User::UnOper()
                        }
                }
 
-               const char* parameters[] = { this->nick, moderemove.c_str() };
-               ServerInstance->Parser->CallHandler("MODE", parameters, 2, this);
+               std::vector<std::string> parameters;
+               parameters.push_back(this->nick);
+               parameters.push_back(moderemove);
+
+               ServerInstance->Parser->CallHandler("MODE", parameters, this);
 
                /* unset their oper type (what IS_OPER checks), and remove +o */
                *this->oper = 0;
@@ -861,7 +891,7 @@ void User::CheckClass()
 
 void User::CheckLines()
 {
-       char* check[] = { "G" , "K", NULL };
+       const char* check[] = { "G" , "K", NULL };
 
        if (!this->exempt)
        {
@@ -920,9 +950,9 @@ void User::FullConnect()
 
        /* Trigger LUSERS output, give modules a chance too */
        int MOD_RESULT = 0;
-       FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", NULL, 0, this, true, "LUSERS"));
+       FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", std::vector<std::string>(), this, true, "LUSERS"));
        if (!MOD_RESULT)
-               ServerInstance->CallCommandHandler("LUSERS", NULL, 0, this);
+               ServerInstance->CallCommandHandler("LUSERS", std::vector<std::string>(), this);
 
        /*
         * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
@@ -992,8 +1022,10 @@ bool User::ForceNickChange(const char* newnick)
        Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
        if (nickhandler) // wtfbbq, when would this not be here
        {
+               std::vector<std::string> parameters;
                nickhandler->HandleInternal(1, dummy);
-               bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);
+               parameters.push_back(newnick);
+               bool result = (ServerInstance->Parser->CallHandler("NICK", parameters, this) == CMD_SUCCESS);
                nickhandler->HandleInternal(0, dummy);
                return result;
        }