+ /* NOTE: Calling this one parameter constructor for User automatically
+ * allocates a new UUID and places it in the hash_map.
+ */
+ LocalUser* New = NULL;
+ try
+ {
+ New = new LocalUser(socket, client, server);
+ }
+ catch (...)
+ {
+ ServerInstance->Logs->Log("USERS", DEFAULT,"*** WTF *** Duplicated UUID! -- Crack smoking monkeys have been unleashed.");
+ ServerInstance->SNO->WriteToSnoMask('a', "WARNING *** Duplicate UUID allocated!");
+ return;
+ }
+ UserIOHandler* eh = &New->eh;
+
+ /* Give each of the modules an attempt to hook the user for I/O */
+ FOREACH_MOD(I_OnHookIO, OnHookIO(eh, via));
+
+ if (eh->GetIOHook())
+ {
+ try
+ {
+ eh->GetIOHook()->OnStreamSocketAccept(eh, client, server);
+ }
+ catch (CoreException& modexcept)
+ {
+ ServerInstance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
+ }
+ }
+
+ ServerInstance->Logs->Log("USERS", DEBUG,"New user fd: %d", socket);
+
+ this->unregistered_count++;
+
+ /* The users default nick is their UUID */
+ New->nick = New->uuid;
+ (*(this->clientlist))[New->nick] = New;
+
+ New->registered = REG_NONE;
+ New->signon = ServerInstance->Time() + ServerInstance->Config->dns_timeout;
+ New->lastping = 1;
+
+ ServerInstance->Users->AddLocalClone(New);
+ ServerInstance->Users->AddGlobalClone(New);
+
+ New->localuseriter = this->local_users.insert(local_users.end(), New);
+
+ if ((this->local_users.size() > ServerInstance->Config->SoftLimit) || (this->local_users.size() >= (unsigned int)ServerInstance->SE->GetMaxFds()))
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Warning: softlimit value has been reached: %d clients", ServerInstance->Config->SoftLimit);
+ this->QuitUser(New,"No more connections allowed");
+ return;
+ }
+
+ /*
+ * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
+ * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
+ */
+ New->SetClass();
+
+ /*
+ * Check connect class settings and initialise settings into User.
+ * This will be done again after DNS resolution. -- w00t
+ */
+ New->CheckClass();
+ if (New->quitting)
+ return;
+
+ /*
+ * even with bancache, we still have to keep User::exempt current.
+ * besides that, if we get a positive bancache hit, we still won't fuck
+ * them over if they are exempt. -- w00t
+ */
+ New->exempt = (ServerInstance->XLines->MatchesLine("E",New) != NULL);
+
+ if (BanCacheHit *b = ServerInstance->BanCache->GetHit(New->GetIPString()))
+ {
+ if (!b->Type.empty() && !New->exempt)
+ {
+ /* user banned */
+ ServerInstance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Positive hit for ") + New->GetIPString());
+ if (!ServerInstance->Config->MoronBanner.empty())
+ New->WriteServ("NOTICE %s :*** %s", New->nick.c_str(), ServerInstance->Config->MoronBanner.c_str());
+ this->QuitUser(New, b->Reason);
+ return;
+ }
+ else
+ {
+ ServerInstance->Logs->Log("BANCACHE", DEBUG, std::string("BanCache: Negative hit for ") + New->GetIPString());
+ }
+ }
+ else
+ {
+ if (!New->exempt)
+ {
+ XLine* r = ServerInstance->XLines->MatchesLine("Z",New);
+
+ if (r)
+ {
+ r->Apply(New);
+ return;
+ }
+ }
+ }
+
+ if (!ServerInstance->SE->AddFd(eh, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE))
+ {
+ ServerInstance->Logs->Log("USERS", DEBUG,"Internal error on new connection");
+ this->QuitUser(New, "Internal error handling connection");
+ }
+
+ /* NOTE: even if dns lookups are *off*, we still need to display this.
+ * BOPM and other stuff requires it.
+ */
+ New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
+ if (ServerInstance->Config->RawLog)
+ New->WriteServ("NOTICE Auth :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.");
+
+ FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(New));
+ if (New->quitting)
+ return;
+
+ FOREACH_MOD(I_OnUserInit,OnUserInit(New));
+
+ if (ServerInstance->Config->NoUserDns)
+ {
+ New->WriteServ("NOTICE %s :*** Skipping host resolution (disabled by server administrator)", New->nick.c_str());
+ New->dns_done = true;
+ }