]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/users.cpp
fe593a13915816c41fb7c91a69bf22f6dae441c2
[user/henk/code/inspircd.git] / src / users.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2006-2007, 2009 Dennis Friis <peavey@inspircd.org>
7  *   Copyright (C) 2008 John Brooks <john.brooks@dereferenced.net>
8  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
9  *   Copyright (C) 2008 Oliver Lupton <oliverlupton@gmail.com>
10  *   Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc>
11  *
12  * This file is part of InspIRCd.  InspIRCd is free software: you can
13  * redistribute it and/or modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25
26 #include "inspircd.h"
27 #include <stdarg.h>
28 #include "socketengine.h"
29 #include "xline.h"
30 #include "bancache.h"
31
32 already_sent_t LocalUser::already_sent_id = 0;
33
34 bool User::IsNoticeMaskSet(unsigned char sm)
35 {
36         if (!isalpha(sm))
37                 return false;
38         return (snomasks[sm-65]);
39 }
40
41 bool User::IsModeSet(unsigned char m)
42 {
43         if (!isalpha(m))
44                 return false;
45         return (modes[m-65]);
46 }
47
48 const char* User::FormatModes(bool showparameters)
49 {
50         static std::string data;
51         std::string params;
52         data.clear();
53
54         for (unsigned char n = 0; n < 64; n++)
55         {
56                 if (modes[n])
57                 {
58                         data.push_back(n + 65);
59                         ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_USER);
60                         if (showparameters && mh && mh->GetNumParams(true))
61                         {
62                                 std::string p = mh->GetUserParameter(this);
63                                 if (p.length())
64                                         params.append(" ").append(p);
65                         }
66                 }
67         }
68         data += params;
69         return data.c_str();
70 }
71
72 User::User(const std::string &uid, const std::string& sid, int type)
73         : uuid(uid), server(sid), usertype(type)
74 {
75         age = ServerInstance->Time();
76         signon = 0;
77         registered = 0;
78         quietquit = quitting = false;
79         client_sa.sa.sa_family = AF_UNSPEC;
80
81         ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New UUID for user: %s", uuid.c_str());
82
83         user_hash::iterator finduuid = ServerInstance->Users->uuidlist->find(uuid);
84         if (finduuid == ServerInstance->Users->uuidlist->end())
85                 (*ServerInstance->Users->uuidlist)[uuid] = this;
86         else
87                 throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor");
88 }
89
90 LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* servaddr)
91         : User(ServerInstance->UIDGen.GetUID(), ServerInstance->Config->ServerName, USERTYPE_LOCAL), eh(this),
92         localuseriter(ServerInstance->Users->local_users.end()),
93         bytes_in(0), bytes_out(0), cmds_in(0), cmds_out(0), nping(0), CommandFloodPenalty(0),
94         already_sent(0)
95 {
96         exempt = quitting_sendq = false;
97         idle_lastmsg = 0;
98         ident = "unknown";
99         lastping = 0;
100         eh.SetFd(myfd);
101         memcpy(&client_sa, client, sizeof(irc::sockets::sockaddrs));
102         memcpy(&server_sa, servaddr, sizeof(irc::sockets::sockaddrs));
103         dhost = host = GetIPString();
104 }
105
106 User::~User()
107 {
108         if (ServerInstance->Users->uuidlist->find(uuid) != ServerInstance->Users->uuidlist->end())
109                 ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "User destructor for %s called without cull", uuid.c_str());
110 }
111
112 const std::string& User::MakeHost()
113 {
114         if (!this->cached_makehost.empty())
115                 return this->cached_makehost;
116
117         // XXX: Is there really a need to cache this?
118         this->cached_makehost = ident + "@" + host;
119         return this->cached_makehost;
120 }
121
122 const std::string& User::MakeHostIP()
123 {
124         if (!this->cached_hostip.empty())
125                 return this->cached_hostip;
126
127         // XXX: Is there really a need to cache this?
128         this->cached_hostip = ident + "@" + this->GetIPString();
129         return this->cached_hostip;
130 }
131
132 const std::string& User::GetFullHost()
133 {
134         if (!this->cached_fullhost.empty())
135                 return this->cached_fullhost;
136
137         // XXX: Is there really a need to cache this?
138         this->cached_fullhost = nick + "!" + ident + "@" + dhost;
139         return this->cached_fullhost;
140 }
141
142 const std::string& User::GetFullRealHost()
143 {
144         if (!this->cached_fullrealhost.empty())
145                 return this->cached_fullrealhost;
146
147         // XXX: Is there really a need to cache this?
148         this->cached_fullrealhost = nick + "!" + ident + "@" + host;
149         return this->cached_fullrealhost;
150 }
151
152 InviteList& LocalUser::GetInviteList()
153 {
154         RemoveExpiredInvites();
155         return invites;
156 }
157
158 bool LocalUser::RemoveInvite(Channel* chan)
159 {
160         Invitation* inv = Invitation::Find(chan, this);
161         if (inv)
162         {
163                 inv->cull();
164                 delete inv;
165                 return true;
166         }
167         return false;
168 }
169
170 void LocalUser::RemoveExpiredInvites()
171 {
172         Invitation::Find(NULL, this);
173 }
174
175 bool User::HasModePermission(unsigned char, ModeType)
176 {
177         return true;
178 }
179
180 bool LocalUser::HasModePermission(unsigned char mode, ModeType type)
181 {
182         if (!this->IsOper())
183                 return false;
184
185         if (mode < 'A' || mode > ('A' + 64)) return false;
186
187         return ((type == MODETYPE_USER ? oper->AllowedUserModes : oper->AllowedChanModes))[(mode - 'A')];
188
189 }
190 /*
191  * users on remote servers can completely bypass all permissions based checks.
192  * This prevents desyncs when one server has different type/class tags to another.
193  * That having been said, this does open things up to the possibility of source changes
194  * allowing remote kills, etc - but if they have access to the src, they most likely have
195  * access to the conf - so it's an end to a means either way.
196  */
197 bool User::HasPermission(const std::string&)
198 {
199         return true;
200 }
201
202 bool LocalUser::HasPermission(const std::string &command)
203 {
204         // are they even an oper at all?
205         if (!this->IsOper())
206         {
207                 return false;
208         }
209
210         if (oper->AllowedOperCommands.find(command) != oper->AllowedOperCommands.end())
211                 return true;
212         else if (oper->AllowedOperCommands.find("*") != oper->AllowedOperCommands.end())
213                 return true;
214
215         return false;
216 }
217
218 bool User::HasPrivPermission(const std::string &privstr, bool noisy)
219 {
220         return true;
221 }
222
223 bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy)
224 {
225         if (!this->IsOper())
226         {
227                 if (noisy)
228                         this->WriteNotice("You are not an oper");
229                 return false;
230         }
231
232         if (oper->AllowedPrivs.find(privstr) != oper->AllowedPrivs.end())
233         {
234                 return true;
235         }
236         else if (oper->AllowedPrivs.find("*") != oper->AllowedPrivs.end())
237         {
238                 return true;
239         }
240
241         if (noisy)
242                 this->WriteNotice("Oper type " + oper->name + " does not have access to priv " + privstr);
243
244         return false;
245 }
246
247 void UserIOHandler::OnDataReady()
248 {
249         if (user->quitting)
250                 return;
251
252         if (recvq.length() > user->MyClass->GetRecvqMax() && !user->HasPrivPermission("users/flood/increased-buffers"))
253         {
254                 ServerInstance->Users->QuitUser(user, "RecvQ exceeded");
255                 ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu",
256                         user->nick.c_str(), (unsigned long)recvq.length(), user->MyClass->GetRecvqMax());
257                 return;
258         }
259         unsigned long sendqmax = ULONG_MAX;
260         if (!user->HasPrivPermission("users/flood/increased-buffers"))
261                 sendqmax = user->MyClass->GetSendqSoftMax();
262         unsigned long penaltymax = ULONG_MAX;
263         if (!user->HasPrivPermission("users/flood/no-fakelag"))
264                 penaltymax = user->MyClass->GetPenaltyThreshold() * 1000;
265
266         while (user->CommandFloodPenalty < penaltymax && getSendQSize() < sendqmax)
267         {
268                 std::string line;
269                 line.reserve(ServerInstance->Config->Limits.MaxLine);
270                 std::string::size_type qpos = 0;
271                 while (qpos < recvq.length())
272                 {
273                         char c = recvq[qpos++];
274                         switch (c)
275                         {
276                         case '\0':
277                                 c = ' ';
278                                 break;
279                         case '\r':
280                                 continue;
281                         case '\n':
282                                 goto eol_found;
283                         }
284                         if (line.length() < ServerInstance->Config->Limits.MaxLine - 2)
285                                 line.push_back(c);
286                 }
287                 // if we got here, the recvq ran out before we found a newline
288                 return;
289 eol_found:
290                 // just found a newline. Terminate the string, and pull it out of recvq
291                 recvq = recvq.substr(qpos);
292
293                 // TODO should this be moved to when it was inserted in recvq?
294                 ServerInstance->stats->statsRecv += qpos;
295                 user->bytes_in += qpos;
296                 user->cmds_in++;
297
298                 ServerInstance->Parser->ProcessBuffer(line, user);
299                 if (user->quitting)
300                         return;
301         }
302         if (user->CommandFloodPenalty >= penaltymax && !user->MyClass->fakelag)
303                 ServerInstance->Users->QuitUser(user, "Excess Flood");
304 }
305
306 void UserIOHandler::AddWriteBuf(const std::string &data)
307 {
308         if (user->quitting_sendq)
309                 return;
310         if (!user->quitting && getSendQSize() + data.length() > user->MyClass->GetSendqHardMax() &&
311                 !user->HasPrivPermission("users/flood/increased-buffers"))
312         {
313                 user->quitting_sendq = true;
314                 ServerInstance->GlobalCulls.AddSQItem(user);
315                 return;
316         }
317
318         // We still want to append data to the sendq of a quitting user,
319         // e.g. their ERROR message that says 'closing link'
320
321         WriteData(data);
322 }
323
324 void UserIOHandler::OnError(BufferedSocketError)
325 {
326         ServerInstance->Users->QuitUser(user, getError());
327 }
328
329 CullResult User::cull()
330 {
331         if (!quitting)
332                 ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
333         PurgeEmptyChannels();
334
335         if (client_sa.sa.sa_family != AF_UNSPEC)
336                 ServerInstance->Users->RemoveCloneCounts(this);
337
338         return Extensible::cull();
339 }
340
341 CullResult LocalUser::cull()
342 {
343         // The iterator is initialized to local_users.end() in the constructor. It is
344         // overwritten in UserManager::AddUser() with the real iterator so this check
345         // is only a precaution currently.
346         if (localuseriter != ServerInstance->Users->local_users.end())
347         {
348                 ServerInstance->Users->local_count--;
349                 ServerInstance->Users->local_users.erase(localuseriter);
350         }
351         else
352                 ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: LocalUserIter does not point to a valid entry for " + this->nick);
353
354         ClearInvites();
355         eh.cull();
356         return User::cull();
357 }
358
359 CullResult FakeUser::cull()
360 {
361         // Fake users don't quit, they just get culled.
362         quitting = true;
363         ServerInstance->Users->clientlist->erase(nick);
364         ServerInstance->Users->uuidlist->erase(uuid);
365         return User::cull();
366 }
367
368 void User::Oper(OperInfo* info)
369 {
370         ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
371         if (this->IsModeSet(opermh))
372                 this->UnOper();
373
374         this->SetMode(opermh, true);
375         this->oper = info;
376         this->WriteServ("MODE %s :+o", this->nick.c_str());
377         FOREACH_MOD(I_OnOper, OnOper(this, info->name));
378
379         std::string opername;
380         if (info->oper_block)
381                 opername = info->oper_block->getString("name");
382
383         if (IS_LOCAL(this))
384         {
385                 LocalUser* l = IS_LOCAL(this);
386                 std::string vhost = oper->getConfig("vhost");
387                 if (!vhost.empty())
388                         l->ChangeDisplayedHost(vhost.c_str());
389                 std::string opClass = oper->getConfig("class");
390                 if (!opClass.empty())
391                         l->SetClass(opClass);
392         }
393
394         ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')",
395                 nick.c_str(), ident.c_str(), host.c_str(), oper->name.c_str(), opername.c_str());
396         this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str());
397
398         ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str());
399         ServerInstance->Users->all_opers.push_back(this);
400
401         // Expand permissions from config for faster lookup
402         if (IS_LOCAL(this))
403                 oper->init();
404
405         FOREACH_MOD(I_OnPostOper,OnPostOper(this, oper->name, opername));
406 }
407
408 void OperInfo::init()
409 {
410         AllowedOperCommands.clear();
411         AllowedPrivs.clear();
412         AllowedUserModes.reset();
413         AllowedChanModes.reset();
414         AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want.
415
416         for(std::vector<reference<ConfigTag> >::iterator iter = class_blocks.begin(); iter != class_blocks.end(); ++iter)
417         {
418                 ConfigTag* tag = *iter;
419                 std::string mycmd, mypriv;
420                 /* Process commands */
421                 irc::spacesepstream CommandList(tag->getString("commands"));
422                 while (CommandList.GetToken(mycmd))
423                 {
424                         AllowedOperCommands.insert(mycmd);
425                 }
426
427                 irc::spacesepstream PrivList(tag->getString("privs"));
428                 while (PrivList.GetToken(mypriv))
429                 {
430                         AllowedPrivs.insert(mypriv);
431                 }
432
433                 std::string modes = tag->getString("usermodes");
434                 for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c)
435                 {
436                         if (*c == '*')
437                         {
438                                 this->AllowedUserModes.set();
439                         }
440                         else if (*c >= 'A' && *c < 'z')
441                         {
442                                 this->AllowedUserModes[*c - 'A'] = true;
443                         }
444                 }
445
446                 modes = tag->getString("chanmodes");
447                 for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c)
448                 {
449                         if (*c == '*')
450                         {
451                                 this->AllowedChanModes.set();
452                         }
453                         else if (*c >= 'A' && *c < 'z')
454                         {
455                                 this->AllowedChanModes[*c - 'A'] = true;
456                         }
457                 }
458         }
459 }
460
461 void User::UnOper()
462 {
463         if (!this->IsOper())
464                 return;
465
466         /*
467          * unset their oper type (what IS_OPER checks).
468          * note, order is important - this must come before modes as -o attempts
469          * to call UnOper. -- w00t
470          */
471         oper = NULL;
472
473
474         /* Remove all oper only modes from the user when the deoper - Bug #466*/
475         std::string moderemove("-");
476
477         for (unsigned char letter = 'A'; letter <= 'z'; letter++)
478         {
479                 ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER);
480                 if (mh && mh->NeedsOper())
481                         moderemove += letter;
482         }
483
484
485         std::vector<std::string> parameters;
486         parameters.push_back(this->nick);
487         parameters.push_back(moderemove);
488
489         ServerInstance->Parser->CallHandler("MODE", parameters, this);
490
491         /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
492         ServerInstance->Users->all_opers.remove(this);
493
494         ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
495         this->SetMode(opermh, false);
496 }
497
498 /*
499  * Check class restrictions
500  */
501 void LocalUser::CheckClass(bool clone_count)
502 {
503         ConnectClass* a = this->MyClass;
504
505         if (!a)
506         {
507                 ServerInstance->Users->QuitUser(this, "Access denied by configuration");
508                 return;
509         }
510         else if (a->type == CC_DENY)
511         {
512                 ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection"));
513                 return;
514         }
515         else if (clone_count)
516         {
517                 if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal()))
518                 {
519                         ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
520                         if (a->maxconnwarn)
521                                 ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString().c_str());
522                         return;
523                 }
524                 else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal()))
525                 {
526                         ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
527                         if (a->maxconnwarn)
528                                 ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString().c_str());
529                         return;
530                 }
531         }
532
533         this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
534 }
535
536 bool LocalUser::CheckLines(bool doZline)
537 {
538         const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL };
539
540         if (!this->exempt)
541         {
542                 for (int n = 0; check[n]; ++n)
543                 {
544                         XLine *r = ServerInstance->XLines->MatchesLine(check[n], this);
545
546                         if (r)
547                         {
548                                 r->Apply(this);
549                                 return true;
550                         }
551                 }
552         }
553
554         return false;
555 }
556
557 void LocalUser::FullConnect()
558 {
559         ServerInstance->stats->statsConnects++;
560         this->idle_lastmsg = ServerInstance->Time();
561
562         /*
563          * You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT.
564          * At the time AddClient is called, we don't have a resolved host, by here we probably do - which
565          * may put the user into a totally seperate class with different restrictions! so we *must* check again.
566          * Don't remove this! -- w00t
567          */
568         MyClass = NULL;
569         SetClass();
570         CheckClass();
571         CheckLines();
572
573         if (quitting)
574                 return;
575
576         this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str());
577         this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version %s",this->nick.c_str(),ServerInstance->Config->ServerName.c_str(),BRANCH);
578         this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__);
579
580         const std::string& modelist = ServerInstance->Modes->GetModeListFor004Numeric();
581         this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, modelist.c_str());
582
583         ServerInstance->ISupport.SendTo(this);
584         this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str());
585
586         /* Now registered */
587         if (ServerInstance->Users->unregistered_count)
588                 ServerInstance->Users->unregistered_count--;
589
590         /* Trigger MOTD and LUSERS output, give modules a chance too */
591         ModResult MOD_RESULT;
592         std::string command("LUSERS");
593         std::vector<std::string> parameters;
594         FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
595         if (!MOD_RESULT)
596                 ServerInstance->Parser->CallHandler(command, parameters, this);
597
598         MOD_RESULT = MOD_RES_PASSTHRU;
599         command = "MOTD";
600         FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
601         if (!MOD_RESULT)
602                 ServerInstance->Parser->CallHandler(command, parameters, this);
603
604         if (ServerInstance->Config->RawLog)
605                 WriteServ("PRIVMSG %s :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.", nick.c_str());
606
607         /*
608          * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
609          * for a user that doesn't exist yet.
610          */
611         FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
612
613         this->registered = REG_ALL;
614
615         FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
616
617         ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]",
618                 this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->fullname.c_str());
619         ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString());
620         ServerInstance->BanCache->AddHit(this->GetIPString(), "", "");
621         // reset the flood penalty (which could have been raised due to things like auto +x)
622         CommandFloodPenalty = 0;
623 }
624
625 void User::InvalidateCache()
626 {
627         /* Invalidate cache */
628         cached_fullhost.clear();
629         cached_hostip.clear();
630         cached_makehost.clear();
631         cached_fullrealhost.clear();
632 }
633
634 bool User::ChangeNick(const std::string& newnick, bool force)
635 {
636         if (quitting)
637         {
638                 ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick);
639                 return false;
640         }
641
642         if (!force)
643         {
644                 ModResult MOD_RESULT;
645                 FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick));
646
647                 if (MOD_RESULT == MOD_RES_DENY)
648                 {
649                         ServerInstance->stats->statsCollisions++;
650                         return false;
651                 }
652         }
653
654         if (assign(newnick) == assign(nick))
655         {
656                 // case change, don't need to check Q:lines and such
657                 // and, if it's identical including case, we can leave right now
658                 if (newnick == nick)
659                         return true;
660         }
661         else
662         {
663                 /*
664                  * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some fucking *moron*
665                  * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be.
666                  * Thanks Kein for finding this. -- w00t
667                  *
668                  * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves.
669                  *              -- w00t
670                  */
671                 if (IS_LOCAL(this) && !force)
672                 {
673                         XLine* mq = ServerInstance->XLines->MatchesLine("Q",newnick);
674                         if (mq)
675                         {
676                                 if (this->registered == REG_ALL)
677                                 {
678                                         ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s: %s",
679                                                 newnick.c_str(), GetFullRealHost().c_str(), mq->reason.c_str());
680                                 }
681                                 this->WriteNumeric(432, "%s %s :Invalid nickname: %s",this->nick.c_str(), newnick.c_str(), mq->reason.c_str());
682                                 return false;
683                         }
684
685                         if (ServerInstance->Config->RestrictBannedUsers)
686                         {
687                                 for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
688                                 {
689                                         Channel *chan = *i;
690                                         if (chan->GetPrefixValue(this) < VOICE_VALUE && chan->IsBanned(this))
691                                         {
692                                                 this->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", this->nick.c_str(), chan->name.c_str());
693                                                 return false;
694                                         }
695                                 }
696                         }
697                 }
698
699                 /*
700                  * Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) --
701                  * then we have a potential collide. Check whether someone else is camping on the nick
702                  * (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the
703                  * camper to their UID, and allow the incoming nick change.
704                  *
705                  * If the guy using the nick is already using it, tell the incoming nick change to gtfo,
706                  * because the nick is already (rightfully) in use. -- w00t
707                  */
708                 User* InUse = ServerInstance->FindNickOnly(newnick);
709                 if (InUse && (InUse != this))
710                 {
711                         if (InUse->registered != REG_ALL)
712                         {
713                                 /* force the camper to their UUID, and ask them to re-send a NICK. */
714                                 InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str());
715                                 InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str());
716
717                                 ServerInstance->Users->clientlist->erase(InUse->nick);
718                                 (*(ServerInstance->Users->clientlist))[InUse->uuid] = InUse;
719
720                                 InUse->nick = InUse->uuid;
721                                 InUse->InvalidateCache();
722                                 InUse->registered &= ~REG_NICK;
723                         }
724                         else
725                         {
726                                 /* No camping, tell the incoming user  to stop trying to change nick ;p */
727                                 this->WriteNumeric(433, "%s %s :Nickname is already in use.", this->registered >= REG_NICK ? this->nick.c_str() : "*", newnick.c_str());
728                                 return false;
729                         }
730                 }
731         }
732
733         if (this->registered == REG_ALL)
734                 this->WriteCommon("NICK %s",newnick.c_str());
735         std::string oldnick = nick;
736         nick = newnick;
737
738         InvalidateCache();
739         ServerInstance->Users->clientlist->erase(oldnick);
740         (*(ServerInstance->Users->clientlist))[newnick] = this;
741
742         if (registered == REG_ALL)
743                 FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(this,oldnick));
744
745         return true;
746 }
747
748 int LocalUser::GetServerPort()
749 {
750         switch (this->server_sa.sa.sa_family)
751         {
752                 case AF_INET6:
753                         return htons(this->server_sa.in6.sin6_port);
754                 case AF_INET:
755                         return htons(this->server_sa.in4.sin_port);
756         }
757         return 0;
758 }
759
760 const std::string& User::GetIPString()
761 {
762         int port;
763         if (cachedip.empty())
764         {
765                 irc::sockets::satoap(client_sa, cachedip, port);
766                 /* IP addresses starting with a : on irc are a Bad Thing (tm) */
767                 if (cachedip[0] == ':')
768                         cachedip.insert(0,1,'0');
769         }
770
771         return cachedip;
772 }
773
774 irc::sockets::cidr_mask User::GetCIDRMask()
775 {
776         int range = 0;
777         switch (client_sa.sa.sa_family)
778         {
779                 case AF_INET6:
780                         range = ServerInstance->Config->c_ipv6_range;
781                         break;
782                 case AF_INET:
783                         range = ServerInstance->Config->c_ipv4_range;
784                         break;
785         }
786         return irc::sockets::cidr_mask(client_sa, range);
787 }
788
789 bool User::SetClientIP(const char* sip, bool recheck_eline)
790 {
791         cachedip.clear();
792         cached_hostip.clear();
793         return irc::sockets::aptosa(sip, 0, client_sa);
794 }
795
796 void User::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_eline)
797 {
798         cachedip.clear();
799         cached_hostip.clear();
800         memcpy(&client_sa, &sa, sizeof(irc::sockets::sockaddrs));
801 }
802
803 bool LocalUser::SetClientIP(const char* sip, bool recheck_eline)
804 {
805         irc::sockets::sockaddrs sa;
806         if (!irc::sockets::aptosa(sip, 0, sa))
807                 // Invalid
808                 return false;
809
810         LocalUser::SetClientIP(sa, recheck_eline);
811         return true;
812 }
813
814 void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_eline)
815 {
816         if (sa != client_sa)
817         {
818                 User::SetClientIP(sa);
819                 if (recheck_eline)
820                         this->exempt = (ServerInstance->XLines->MatchesLine("E", this) != NULL);
821
822                 FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(this));
823         }
824 }
825
826 static std::string wide_newline("\r\n");
827
828 void User::Write(const std::string& text)
829 {
830 }
831
832 void User::Write(const char *text, ...)
833 {
834 }
835
836 void LocalUser::Write(const std::string& text)
837 {
838         if (!ServerInstance->SE->BoundsCheckFd(&eh))
839                 return;
840
841         if (text.length() > ServerInstance->Config->Limits.MaxLine - 2)
842         {
843                 // this should happen rarely or never. Crop the string at 512 and try again.
844                 std::string try_again = text.substr(0, ServerInstance->Config->Limits.MaxLine - 2);
845                 Write(try_again);
846                 return;
847         }
848
849         ServerInstance->Logs->Log("USEROUTPUT", LOG_RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str());
850
851         eh.AddWriteBuf(text);
852         eh.AddWriteBuf(wide_newline);
853
854         ServerInstance->stats->statsSent += text.length() + 2;
855         this->bytes_out += text.length() + 2;
856         this->cmds_out++;
857 }
858
859 /** Write()
860  */
861 void LocalUser::Write(const char *text, ...)
862 {
863         std::string textbuffer;
864         VAFORMAT(textbuffer, text, text);
865         this->Write(textbuffer);
866 }
867
868 void User::WriteServ(const std::string& text)
869 {
870         this->Write(":%s %s",ServerInstance->Config->ServerName.c_str(),text.c_str());
871 }
872
873 /** WriteServ()
874  *  Same as Write(), except `text' is prefixed with `:server.name '.
875  */
876 void User::WriteServ(const char* text, ...)
877 {
878         std::string textbuffer;
879         VAFORMAT(textbuffer, text, text);
880         this->WriteServ(textbuffer);
881 }
882
883 void User::WriteNotice(const std::string& text)
884 {
885         this->WriteServ("NOTICE " + (this->registered == REG_ALL ? this->nick : "*") + " :" + text);
886 }
887
888 void User::WriteNumeric(unsigned int numeric, const char* text, ...)
889 {
890         std::string textbuffer;
891         VAFORMAT(textbuffer, text, text);
892         this->WriteNumeric(numeric, textbuffer);
893 }
894
895 void User::WriteNumeric(unsigned int numeric, const std::string &text)
896 {
897         ModResult MOD_RESULT;
898
899         FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric, text));
900
901         if (MOD_RESULT == MOD_RES_DENY)
902                 return;
903         
904         const std::string message = InspIRCd::Format(":%s %03u %s", ServerInstance->Config->ServerName.c_str(),
905                 numeric, text.c_str());
906         this->Write(message);
907 }
908
909 void User::WriteFrom(User *user, const std::string &text)
910 {
911         const std::string message = ":" + user->GetFullHost() + " " + text;
912         this->Write(message);
913 }
914
915
916 /* write text from an originating user to originating user */
917
918 void User::WriteFrom(User *user, const char* text, ...)
919 {
920         std::string textbuffer;
921         VAFORMAT(textbuffer, text, text);
922         this->WriteFrom(user, textbuffer);
923 }
924
925
926 /* write text to an destination user from a source user (e.g. user privmsg) */
927
928 void User::WriteTo(User *dest, const char *data, ...)
929 {
930         std::string textbuffer;
931         VAFORMAT(textbuffer, data, data);
932         this->WriteTo(dest, textbuffer);
933 }
934
935 void User::WriteTo(User *dest, const std::string &data)
936 {
937         dest->WriteFrom(this, data);
938 }
939
940 void User::WriteCommon(const char* text, ...)
941 {
942         if (this->registered != REG_ALL || quitting)
943                 return;
944
945         std::string textbuffer;
946         VAFORMAT(textbuffer, text, text);
947         textbuffer = ":" + this->GetFullHost() + " " + textbuffer;
948         this->WriteCommonRaw(textbuffer, true);
949 }
950
951 void User::WriteCommonExcept(const char* text, ...)
952 {
953         if (this->registered != REG_ALL || quitting)
954                 return;
955
956         std::string textbuffer;
957         VAFORMAT(textbuffer, text, text);
958         textbuffer = ":" + this->GetFullHost() + " " + textbuffer;
959         this->WriteCommonRaw(textbuffer, false);
960 }
961
962 void User::WriteCommonRaw(const std::string &line, bool include_self)
963 {
964         if (this->registered != REG_ALL || quitting)
965                 return;
966
967         LocalUser::already_sent_id++;
968
969         UserChanList include_c(chans);
970         std::map<User*,bool> exceptions;
971
972         exceptions[this] = include_self;
973
974         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
975
976         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
977         {
978                 LocalUser* u = IS_LOCAL(i->first);
979                 if (u && !u->quitting)
980                 {
981                         u->already_sent = LocalUser::already_sent_id;
982                         if (i->second)
983                                 u->Write(line);
984                 }
985         }
986         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
987         {
988                 Channel* c = *v;
989                 const UserMembList* ulist = c->GetUsers();
990                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
991                 {
992                         LocalUser* u = IS_LOCAL(i->first);
993                         if (u && !u->quitting && u->already_sent != LocalUser::already_sent_id)
994                         {
995                                 u->already_sent = LocalUser::already_sent_id;
996                                 u->Write(line);
997                         }
998                 }
999         }
1000 }
1001
1002 void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
1003 {
1004         if (this->registered != REG_ALL)
1005                 return;
1006
1007         already_sent_t uniq_id = ++LocalUser::already_sent_id;
1008
1009         const std::string normalMessage = ":" + this->GetFullHost() + " QUIT :" + normal_text;
1010         const std::string operMessage = ":" + this->GetFullHost() + " QUIT :" + oper_text;
1011
1012         UserChanList include_c(chans);
1013         std::map<User*,bool> exceptions;
1014
1015         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1016
1017         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1018         {
1019                 LocalUser* u = IS_LOCAL(i->first);
1020                 if (u && !u->quitting)
1021                 {
1022                         u->already_sent = uniq_id;
1023                         if (i->second)
1024                                 u->Write(u->IsOper() ? operMessage : normalMessage);
1025                 }
1026         }
1027         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1028         {
1029                 const UserMembList* ulist = (*v)->GetUsers();
1030                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1031                 {
1032                         LocalUser* u = IS_LOCAL(i->first);
1033                         if (u && !u->quitting && (u->already_sent != uniq_id))
1034                         {
1035                                 u->already_sent = uniq_id;
1036                                 u->Write(u->IsOper() ? operMessage : normalMessage);
1037                         }
1038                 }
1039         }
1040 }
1041
1042 void LocalUser::SendText(const std::string& line)
1043 {
1044         Write(line);
1045 }
1046
1047 void RemoteUser::SendText(const std::string& line)
1048 {
1049         ServerInstance->PI->PushToClient(this, line);
1050 }
1051
1052 void FakeUser::SendText(const std::string& line)
1053 {
1054 }
1055
1056 void User::SendText(const char *text, ...)
1057 {
1058         std::string line;
1059         VAFORMAT(line, text, text);
1060         SendText(line);
1061 }
1062
1063 void User::SendText(const std::string& linePrefix, std::stringstream& textStream)
1064 {
1065         std::string line;
1066         std::string word;
1067         while (textStream >> word)
1068         {
1069                 size_t lineLength = linePrefix.length() + line.length() + word.length() + 3; // "\s\n\r"
1070                 if (lineLength > ServerInstance->Config->Limits.MaxLine)
1071                 {
1072                         SendText(linePrefix + line);
1073                         line.clear();
1074                 }
1075                 line += " " + word;
1076         }
1077         SendText(linePrefix + line);
1078 }
1079
1080 /* return 0 or 1 depending if users u and u2 share one or more common channels
1081  * (used by QUIT, NICK etc which arent channel specific notices)
1082  *
1083  * The old algorithm in 1.0 for this was relatively inefficient, iterating over
1084  * the first users channels then the second users channels within the outer loop,
1085  * therefore it was a maximum of x*y iterations (upon returning 0 and checking
1086  * all possible iterations). However this new function instead checks against the
1087  * channel's userlist in the inner loop which is a std::map<User*,User*>
1088  * and saves us time as we already know what pointer value we are after.
1089  * Don't quote me on the maths as i am not a mathematician or computer scientist,
1090  * but i believe this algorithm is now x+(log y) maximum iterations instead.
1091  */
1092 bool User::SharesChannelWith(User *other)
1093 {
1094         if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))
1095                 return false;
1096
1097         /* Outer loop */
1098         for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1099         {
1100                 /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
1101                  * by replacing it with a map::find which *should* be more efficient
1102                  */
1103                 if ((*i)->HasUser(other))
1104                         return true;
1105         }
1106         return false;
1107 }
1108
1109 bool User::ChangeName(const char* gecos)
1110 {
1111         if (!this->fullname.compare(gecos))
1112                 return true;
1113
1114         if (IS_LOCAL(this))
1115         {
1116                 ModResult MOD_RESULT;
1117                 FIRST_MOD_RESULT(OnChangeLocalUserGECOS, MOD_RESULT, (IS_LOCAL(this),gecos));
1118                 if (MOD_RESULT == MOD_RES_DENY)
1119                         return false;
1120                 FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));
1121         }
1122         this->fullname.assign(gecos, 0, ServerInstance->Config->Limits.MaxGecos);
1123
1124         return true;
1125 }
1126
1127 void User::DoHostCycle(const std::string &quitline)
1128 {
1129         if (!ServerInstance->Config->CycleHosts)
1130                 return;
1131
1132         already_sent_t silent_id = ++LocalUser::already_sent_id;
1133         already_sent_t seen_id = ++LocalUser::already_sent_id;
1134
1135         UserChanList include_c(chans);
1136         std::map<User*,bool> exceptions;
1137
1138         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1139
1140         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1141         {
1142                 LocalUser* u = IS_LOCAL(i->first);
1143                 if (u && !u->quitting)
1144                 {
1145                         if (i->second)
1146                         {
1147                                 u->already_sent = seen_id;
1148                                 u->Write(quitline);
1149                         }
1150                         else
1151                         {
1152                                 u->already_sent = silent_id;
1153                         }
1154                 }
1155         }
1156         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1157         {
1158                 Channel* c = *v;
1159                 Membership* memb = c->GetUser(this);
1160                 const std::string joinline = ":" + GetFullHost() + " JOIN " + c->name;
1161                 std::string modeline;
1162
1163                 if (!memb->modes.empty())
1164                 {
1165                         modeline = ":" + (ServerInstance->Config->CycleHostsFromUser ? GetFullHost() : ServerInstance->Config->ServerName)
1166                                 + " MODE " + c->name + " +" + memb->modes;
1167
1168                         for (size_t i = 0; i < memb->modes.length(); i++)
1169                                 modeline.append(" ").append(nick);
1170                 }
1171
1172                 const UserMembList *ulist = c->GetUsers();
1173                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1174                 {
1175                         LocalUser* u = IS_LOCAL(i->first);
1176                         if (u == NULL || u == this)
1177                                 continue;
1178                         if (u->already_sent == silent_id)
1179                                 continue;
1180
1181                         if (u->already_sent != seen_id)
1182                         {
1183                                 u->Write(quitline);
1184                                 u->already_sent = seen_id;
1185                         }
1186                         u->Write(joinline);
1187                         if (!memb->modes.empty())
1188                                 u->Write(modeline);
1189                 }
1190         }
1191 }
1192
1193 bool User::ChangeDisplayedHost(const char* shost)
1194 {
1195         if (dhost == shost)
1196                 return true;
1197
1198         if (IS_LOCAL(this))
1199         {
1200                 ModResult MOD_RESULT;
1201                 FIRST_MOD_RESULT(OnChangeLocalUserHost, MOD_RESULT, (IS_LOCAL(this),shost));
1202                 if (MOD_RESULT == MOD_RES_DENY)
1203                         return false;
1204         }
1205
1206         FOREACH_MOD(I_OnChangeHost, OnChangeHost(this,shost));
1207
1208         std::string quitstr = ":" + GetFullHost() + " QUIT :Changing host";
1209
1210         /* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */
1211         this->dhost.assign(shost, 0, 64);
1212
1213         this->InvalidateCache();
1214
1215         this->DoHostCycle(quitstr);
1216
1217         if (IS_LOCAL(this))
1218                 this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s %s :is now your displayed host",this->nick.c_str(),this->dhost.c_str());
1219
1220         return true;
1221 }
1222
1223 bool User::ChangeIdent(const char* newident)
1224 {
1225         if (this->ident == newident)
1226                 return true;
1227
1228         FOREACH_MOD(I_OnChangeIdent, OnChangeIdent(this,newident));
1229
1230         std::string quitstr = ":" + GetFullHost() + " QUIT :Changing ident";
1231
1232         this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax);
1233
1234         this->InvalidateCache();
1235
1236         this->DoHostCycle(quitstr);
1237
1238         return true;
1239 }
1240
1241 void User::SendAll(const char* command, const char* text, ...)
1242 {
1243         std::string textbuffer;
1244         VAFORMAT(textbuffer, text, text);
1245         const std::string message = ":" + this->GetFullHost() + " " + command + " $* :" + textbuffer;
1246
1247         for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
1248         {
1249                 if ((*i)->registered == REG_ALL)
1250                         (*i)->Write(message);
1251         }
1252 }
1253
1254 /*
1255  * Sets a user's connection class.
1256  * If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc.
1257  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1258  * then their ip will be taken as 'priority' anyway, so for example,
1259  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1260  */
1261 void LocalUser::SetClass(const std::string &explicit_name)
1262 {
1263         ConnectClass *found = NULL;
1264
1265         ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Setting connect class for UID %s", this->uuid.c_str());
1266
1267         if (!explicit_name.empty())
1268         {
1269                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1270                 {
1271                         ConnectClass* c = *i;
1272
1273                         if (explicit_name == c->name)
1274                         {
1275                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Explicitly set to %s", explicit_name.c_str());
1276                                 found = c;
1277                         }
1278                 }
1279         }
1280         else
1281         {
1282                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1283                 {
1284                         ConnectClass* c = *i;
1285                         ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Checking %s", c->GetName().c_str());
1286
1287                         ModResult MOD_RESULT;
1288                         FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c));
1289                         if (MOD_RESULT == MOD_RES_DENY)
1290                                 continue;
1291                         if (MOD_RESULT == MOD_RES_ALLOW)
1292                         {
1293                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class forced by module to %s", c->GetName().c_str());
1294                                 found = c;
1295                                 break;
1296                         }
1297
1298                         if (c->type == CC_NAMED)
1299                                 continue;
1300
1301                         bool regdone = (registered != REG_NONE);
1302                         if (c->config->getBool("registered", regdone) != regdone)
1303                                 continue;
1304
1305                         /* check if host matches.. */
1306                         if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) &&
1307                             !InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL))
1308                         {
1309                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "No host match (for %s)", c->GetHost().c_str());
1310                                 continue;
1311                         }
1312
1313                         /*
1314                          * deny change if change will take class over the limit check it HERE, not after we found a matching class,
1315                          * because we should attempt to find another class if this one doesn't match us. -- w00t
1316                          */
1317                         if (c->limit && (c->GetReferenceCount() >= c->limit))
1318                         {
1319                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit);
1320                                 continue;
1321                         }
1322
1323                         /* if it requires a port ... */
1324                         int port = c->config->getInt("port");
1325                         if (port)
1326                         {
1327                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires port (%d)", port);
1328
1329                                 /* and our port doesn't match, fail. */
1330                                 if (this->GetServerPort() != port)
1331                                         continue;
1332                         }
1333
1334                         if (regdone && !c->config->getString("password").empty())
1335                         {
1336                                 if (ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash")))
1337                                 {
1338                                         ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping");
1339                                         continue;
1340                                 }
1341                         }
1342
1343                         /* we stop at the first class that meets ALL critera. */
1344                         found = c;
1345                         break;
1346                 }
1347         }
1348
1349         /*
1350          * Okay, assuming we found a class that matches.. switch us into that class, keeping refcounts up to date.
1351          */
1352         if (found)
1353         {
1354                 MyClass = found;
1355         }
1356 }
1357
1358 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1359  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1360  * then their ip will be taken as 'priority' anyway, so for example,
1361  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1362  */
1363 ConnectClass* LocalUser::GetClass()
1364 {
1365         return MyClass;
1366 }
1367
1368 ConnectClass* User::GetClass()
1369 {
1370         return NULL;
1371 }
1372
1373 void User::PurgeEmptyChannels()
1374 {
1375         // firstly decrement the count on each channel
1376         for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
1377         {
1378                 Channel* c = *f;
1379                 c->DelUser(this);
1380         }
1381
1382         this->UnOper();
1383 }
1384
1385 const std::string& FakeUser::GetFullHost()
1386 {
1387         if (!ServerInstance->Config->HideWhoisServer.empty())
1388                 return ServerInstance->Config->HideWhoisServer;
1389         return server;
1390 }
1391
1392 const std::string& FakeUser::GetFullRealHost()
1393 {
1394         if (!ServerInstance->Config->HideWhoisServer.empty())
1395                 return ServerInstance->Config->HideWhoisServer;
1396         return server;
1397 }
1398
1399 ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask)
1400         : config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask),
1401         pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0),
1402         penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0),
1403         limit(0), nouserdns(false)
1404 {
1405 }
1406
1407 ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, const ConnectClass& parent)
1408         : config(tag), type(t), fakelag(parent.fakelag), name("unnamed"),
1409         registration_timeout(parent.registration_timeout), host(mask), pingtime(parent.pingtime),
1410         softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax),
1411         penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate),
1412         maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxconnwarn(parent.maxconnwarn), maxchans(parent.maxchans),
1413         limit(parent.limit), nouserdns(parent.nouserdns)
1414 {
1415 }
1416
1417 void ConnectClass::Update(const ConnectClass* src)
1418 {
1419         config = src->config;
1420         type = src->type;
1421         fakelag = src->fakelag;
1422         name = src->name;
1423         registration_timeout = src->registration_timeout;
1424         host = src->host;
1425         pingtime = src->pingtime;
1426         softsendqmax = src->softsendqmax;
1427         hardsendqmax = src->hardsendqmax;
1428         recvqmax = src->recvqmax;
1429         penaltythreshold = src->penaltythreshold;
1430         commandrate = src->commandrate;
1431         maxlocal = src->maxlocal;
1432         maxglobal = src->maxglobal;
1433         maxconnwarn = src->maxconnwarn;
1434         maxchans = src->maxchans;
1435         limit = src->limit;
1436         nouserdns = src->nouserdns;
1437 }