]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/users.cpp
Replace hardcoded mode letters, part 3
[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         if (this->IsModeSet('o'))
371                 this->UnOper();
372
373         this->modes[UM_OPERATOR] = 1;
374         this->oper = info;
375         this->WriteServ("MODE %s :+o", this->nick.c_str());
376         FOREACH_MOD(I_OnOper, OnOper(this, info->name));
377
378         std::string opername;
379         if (info->oper_block)
380                 opername = info->oper_block->getString("name");
381
382         if (IS_LOCAL(this))
383         {
384                 LocalUser* l = IS_LOCAL(this);
385                 std::string vhost = oper->getConfig("vhost");
386                 if (!vhost.empty())
387                         l->ChangeDisplayedHost(vhost.c_str());
388                 std::string opClass = oper->getConfig("class");
389                 if (!opClass.empty())
390                         l->SetClass(opClass);
391         }
392
393         ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')",
394                 nick.c_str(), ident.c_str(), host.c_str(), oper->name.c_str(), opername.c_str());
395         this->WriteNumeric(381, "%s :You are now %s %s", nick.c_str(), strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str());
396
397         ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str());
398         ServerInstance->Users->all_opers.push_back(this);
399
400         // Expand permissions from config for faster lookup
401         if (IS_LOCAL(this))
402                 oper->init();
403
404         FOREACH_MOD(I_OnPostOper,OnPostOper(this, oper->name, opername));
405 }
406
407 void OperInfo::init()
408 {
409         AllowedOperCommands.clear();
410         AllowedPrivs.clear();
411         AllowedUserModes.reset();
412         AllowedChanModes.reset();
413         AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want.
414
415         for(std::vector<reference<ConfigTag> >::iterator iter = class_blocks.begin(); iter != class_blocks.end(); ++iter)
416         {
417                 ConfigTag* tag = *iter;
418                 std::string mycmd, mypriv;
419                 /* Process commands */
420                 irc::spacesepstream CommandList(tag->getString("commands"));
421                 while (CommandList.GetToken(mycmd))
422                 {
423                         AllowedOperCommands.insert(mycmd);
424                 }
425
426                 irc::spacesepstream PrivList(tag->getString("privs"));
427                 while (PrivList.GetToken(mypriv))
428                 {
429                         AllowedPrivs.insert(mypriv);
430                 }
431
432                 std::string modes = tag->getString("usermodes");
433                 for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c)
434                 {
435                         if (*c == '*')
436                         {
437                                 this->AllowedUserModes.set();
438                         }
439                         else if (*c >= 'A' && *c < 'z')
440                         {
441                                 this->AllowedUserModes[*c - 'A'] = true;
442                         }
443                 }
444
445                 modes = tag->getString("chanmodes");
446                 for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c)
447                 {
448                         if (*c == '*')
449                         {
450                                 this->AllowedChanModes.set();
451                         }
452                         else if (*c >= 'A' && *c < 'z')
453                         {
454                                 this->AllowedChanModes[*c - 'A'] = true;
455                         }
456                 }
457         }
458 }
459
460 void User::UnOper()
461 {
462         if (!this->IsOper())
463                 return;
464
465         /*
466          * unset their oper type (what IS_OPER checks).
467          * note, order is important - this must come before modes as -o attempts
468          * to call UnOper. -- w00t
469          */
470         oper = NULL;
471
472
473         /* Remove all oper only modes from the user when the deoper - Bug #466*/
474         std::string moderemove("-");
475
476         for (unsigned char letter = 'A'; letter <= 'z'; letter++)
477         {
478                 ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER);
479                 if (mh && mh->NeedsOper())
480                         moderemove += letter;
481         }
482
483
484         std::vector<std::string> parameters;
485         parameters.push_back(this->nick);
486         parameters.push_back(moderemove);
487
488         ServerInstance->Parser->CallHandler("MODE", parameters, this);
489
490         /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
491         ServerInstance->Users->all_opers.remove(this);
492
493         this->modes[UM_OPERATOR] = 0;
494 }
495
496 /*
497  * Check class restrictions
498  */
499 void LocalUser::CheckClass(bool clone_count)
500 {
501         ConnectClass* a = this->MyClass;
502
503         if (!a)
504         {
505                 ServerInstance->Users->QuitUser(this, "Access denied by configuration");
506                 return;
507         }
508         else if (a->type == CC_DENY)
509         {
510                 ServerInstance->Users->QuitUser(this, a->config->getString("reason", "Unauthorised connection"));
511                 return;
512         }
513         else if (clone_count)
514         {
515                 if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal()))
516                 {
517                         ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
518                         if (a->maxconnwarn)
519                                 ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString().c_str());
520                         return;
521                 }
522                 else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal()))
523                 {
524                         ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
525                         if (a->maxconnwarn)
526                                 ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString().c_str());
527                         return;
528                 }
529         }
530
531         this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
532 }
533
534 bool LocalUser::CheckLines(bool doZline)
535 {
536         const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL };
537
538         if (!this->exempt)
539         {
540                 for (int n = 0; check[n]; ++n)
541                 {
542                         XLine *r = ServerInstance->XLines->MatchesLine(check[n], this);
543
544                         if (r)
545                         {
546                                 r->Apply(this);
547                                 return true;
548                         }
549                 }
550         }
551
552         return false;
553 }
554
555 void LocalUser::FullConnect()
556 {
557         ServerInstance->stats->statsConnects++;
558         this->idle_lastmsg = ServerInstance->Time();
559
560         /*
561          * You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT.
562          * At the time AddClient is called, we don't have a resolved host, by here we probably do - which
563          * may put the user into a totally seperate class with different restrictions! so we *must* check again.
564          * Don't remove this! -- w00t
565          */
566         MyClass = NULL;
567         SetClass();
568         CheckClass();
569         CheckLines();
570
571         if (quitting)
572                 return;
573
574         this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), GetFullRealHost().c_str());
575         this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version %s",this->nick.c_str(),ServerInstance->Config->ServerName.c_str(),BRANCH);
576         this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__);
577
578         const std::string& modelist = ServerInstance->Modes->GetModeListFor004Numeric();
579         this->WriteNumeric(RPL_SERVERVERSION, "%s %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), BRANCH, modelist.c_str());
580
581         ServerInstance->ISupport.SendTo(this);
582         this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str());
583
584         /* Now registered */
585         if (ServerInstance->Users->unregistered_count)
586                 ServerInstance->Users->unregistered_count--;
587
588         /* Trigger MOTD and LUSERS output, give modules a chance too */
589         ModResult MOD_RESULT;
590         std::string command("LUSERS");
591         std::vector<std::string> parameters;
592         FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
593         if (!MOD_RESULT)
594                 ServerInstance->Parser->CallHandler(command, parameters, this);
595
596         MOD_RESULT = MOD_RES_PASSTHRU;
597         command = "MOTD";
598         FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, command));
599         if (!MOD_RESULT)
600                 ServerInstance->Parser->CallHandler(command, parameters, this);
601
602         if (ServerInstance->Config->RawLog)
603                 WriteServ("PRIVMSG %s :*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.", nick.c_str());
604
605         /*
606          * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
607          * for a user that doesn't exist yet.
608          */
609         FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
610
611         this->registered = REG_ALL;
612
613         FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
614
615         ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d (class %s): %s (%s) [%s]",
616                 this->GetServerPort(), this->MyClass->name.c_str(), GetFullRealHost().c_str(), this->GetIPString().c_str(), this->fullname.c_str());
617         ServerInstance->Logs->Log("BANCACHE", LOG_DEBUG, "BanCache: Adding NEGATIVE hit for " + this->GetIPString());
618         ServerInstance->BanCache->AddHit(this->GetIPString(), "", "");
619         // reset the flood penalty (which could have been raised due to things like auto +x)
620         CommandFloodPenalty = 0;
621 }
622
623 void User::InvalidateCache()
624 {
625         /* Invalidate cache */
626         cached_fullhost.clear();
627         cached_hostip.clear();
628         cached_makehost.clear();
629         cached_fullrealhost.clear();
630 }
631
632 bool User::ChangeNick(const std::string& newnick, bool force)
633 {
634         if (quitting)
635         {
636                 ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick);
637                 return false;
638         }
639
640         if (!force)
641         {
642                 ModResult MOD_RESULT;
643                 FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick));
644
645                 if (MOD_RESULT == MOD_RES_DENY)
646                 {
647                         ServerInstance->stats->statsCollisions++;
648                         return false;
649                 }
650         }
651
652         if (assign(newnick) == assign(nick))
653         {
654                 // case change, don't need to check Q:lines and such
655                 // and, if it's identical including case, we can leave right now
656                 if (newnick == nick)
657                         return true;
658         }
659         else
660         {
661                 /*
662                  * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some fucking *moron*
663                  * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be.
664                  * Thanks Kein for finding this. -- w00t
665                  *
666                  * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves.
667                  *              -- w00t
668                  */
669                 if (IS_LOCAL(this) && !force)
670                 {
671                         XLine* mq = ServerInstance->XLines->MatchesLine("Q",newnick);
672                         if (mq)
673                         {
674                                 if (this->registered == REG_ALL)
675                                 {
676                                         ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s: %s",
677                                                 newnick.c_str(), GetFullRealHost().c_str(), mq->reason.c_str());
678                                 }
679                                 this->WriteNumeric(432, "%s %s :Invalid nickname: %s",this->nick.c_str(), newnick.c_str(), mq->reason.c_str());
680                                 return false;
681                         }
682
683                         if (ServerInstance->Config->RestrictBannedUsers)
684                         {
685                                 for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
686                                 {
687                                         Channel *chan = *i;
688                                         if (chan->GetPrefixValue(this) < VOICE_VALUE && chan->IsBanned(this))
689                                         {
690                                                 this->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", this->nick.c_str(), chan->name.c_str());
691                                                 return false;
692                                         }
693                                 }
694                         }
695                 }
696
697                 /*
698                  * Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) --
699                  * then we have a potential collide. Check whether someone else is camping on the nick
700                  * (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the
701                  * camper to their UID, and allow the incoming nick change.
702                  *
703                  * If the guy using the nick is already using it, tell the incoming nick change to gtfo,
704                  * because the nick is already (rightfully) in use. -- w00t
705                  */
706                 User* InUse = ServerInstance->FindNickOnly(newnick);
707                 if (InUse && (InUse != this))
708                 {
709                         if (InUse->registered != REG_ALL)
710                         {
711                                 /* force the camper to their UUID, and ask them to re-send a NICK. */
712                                 InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str());
713                                 InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str());
714
715                                 ServerInstance->Users->clientlist->erase(InUse->nick);
716                                 (*(ServerInstance->Users->clientlist))[InUse->uuid] = InUse;
717
718                                 InUse->nick = InUse->uuid;
719                                 InUse->InvalidateCache();
720                                 InUse->registered &= ~REG_NICK;
721                         }
722                         else
723                         {
724                                 /* No camping, tell the incoming user  to stop trying to change nick ;p */
725                                 this->WriteNumeric(433, "%s %s :Nickname is already in use.", this->registered >= REG_NICK ? this->nick.c_str() : "*", newnick.c_str());
726                                 return false;
727                         }
728                 }
729         }
730
731         if (this->registered == REG_ALL)
732                 this->WriteCommon("NICK %s",newnick.c_str());
733         std::string oldnick = nick;
734         nick = newnick;
735
736         InvalidateCache();
737         ServerInstance->Users->clientlist->erase(oldnick);
738         (*(ServerInstance->Users->clientlist))[newnick] = this;
739
740         if (registered == REG_ALL)
741                 FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(this,oldnick));
742
743         return true;
744 }
745
746 int LocalUser::GetServerPort()
747 {
748         switch (this->server_sa.sa.sa_family)
749         {
750                 case AF_INET6:
751                         return htons(this->server_sa.in6.sin6_port);
752                 case AF_INET:
753                         return htons(this->server_sa.in4.sin_port);
754         }
755         return 0;
756 }
757
758 const std::string& User::GetIPString()
759 {
760         int port;
761         if (cachedip.empty())
762         {
763                 irc::sockets::satoap(client_sa, cachedip, port);
764                 /* IP addresses starting with a : on irc are a Bad Thing (tm) */
765                 if (cachedip[0] == ':')
766                         cachedip.insert(0,1,'0');
767         }
768
769         return cachedip;
770 }
771
772 irc::sockets::cidr_mask User::GetCIDRMask()
773 {
774         int range = 0;
775         switch (client_sa.sa.sa_family)
776         {
777                 case AF_INET6:
778                         range = ServerInstance->Config->c_ipv6_range;
779                         break;
780                 case AF_INET:
781                         range = ServerInstance->Config->c_ipv4_range;
782                         break;
783         }
784         return irc::sockets::cidr_mask(client_sa, range);
785 }
786
787 bool User::SetClientIP(const char* sip, bool recheck_eline)
788 {
789         cachedip.clear();
790         cached_hostip.clear();
791         return irc::sockets::aptosa(sip, 0, client_sa);
792 }
793
794 void User::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_eline)
795 {
796         cachedip.clear();
797         cached_hostip.clear();
798         memcpy(&client_sa, &sa, sizeof(irc::sockets::sockaddrs));
799 }
800
801 bool LocalUser::SetClientIP(const char* sip, bool recheck_eline)
802 {
803         irc::sockets::sockaddrs sa;
804         if (!irc::sockets::aptosa(sip, 0, sa))
805                 // Invalid
806                 return false;
807
808         LocalUser::SetClientIP(sa, recheck_eline);
809         return true;
810 }
811
812 void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa, bool recheck_eline)
813 {
814         if (sa != client_sa)
815         {
816                 User::SetClientIP(sa);
817                 if (recheck_eline)
818                         this->exempt = (ServerInstance->XLines->MatchesLine("E", this) != NULL);
819
820                 FOREACH_MOD(I_OnSetUserIP,OnSetUserIP(this));
821         }
822 }
823
824 static std::string wide_newline("\r\n");
825
826 void User::Write(const std::string& text)
827 {
828 }
829
830 void User::Write(const char *text, ...)
831 {
832 }
833
834 void LocalUser::Write(const std::string& text)
835 {
836         if (!ServerInstance->SE->BoundsCheckFd(&eh))
837                 return;
838
839         if (text.length() > ServerInstance->Config->Limits.MaxLine - 2)
840         {
841                 // this should happen rarely or never. Crop the string at 512 and try again.
842                 std::string try_again = text.substr(0, ServerInstance->Config->Limits.MaxLine - 2);
843                 Write(try_again);
844                 return;
845         }
846
847         ServerInstance->Logs->Log("USEROUTPUT", LOG_RAWIO, "C[%s] O %s", uuid.c_str(), text.c_str());
848
849         eh.AddWriteBuf(text);
850         eh.AddWriteBuf(wide_newline);
851
852         ServerInstance->stats->statsSent += text.length() + 2;
853         this->bytes_out += text.length() + 2;
854         this->cmds_out++;
855 }
856
857 /** Write()
858  */
859 void LocalUser::Write(const char *text, ...)
860 {
861         std::string textbuffer;
862         VAFORMAT(textbuffer, text, text);
863         this->Write(textbuffer);
864 }
865
866 void User::WriteServ(const std::string& text)
867 {
868         this->Write(":%s %s",ServerInstance->Config->ServerName.c_str(),text.c_str());
869 }
870
871 /** WriteServ()
872  *  Same as Write(), except `text' is prefixed with `:server.name '.
873  */
874 void User::WriteServ(const char* text, ...)
875 {
876         std::string textbuffer;
877         VAFORMAT(textbuffer, text, text);
878         this->WriteServ(textbuffer);
879 }
880
881 void User::WriteNotice(const std::string& text)
882 {
883         this->WriteServ("NOTICE " + (this->registered == REG_ALL ? this->nick : "*") + " :" + text);
884 }
885
886 void User::WriteNumeric(unsigned int numeric, const char* text, ...)
887 {
888         std::string textbuffer;
889         VAFORMAT(textbuffer, text, text);
890         this->WriteNumeric(numeric, textbuffer);
891 }
892
893 void User::WriteNumeric(unsigned int numeric, const std::string &text)
894 {
895         ModResult MOD_RESULT;
896
897         FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric, text));
898
899         if (MOD_RESULT == MOD_RES_DENY)
900                 return;
901         
902         const std::string message = InspIRCd::Format(":%s %03u %s", ServerInstance->Config->ServerName.c_str(),
903                 numeric, text.c_str());
904         this->Write(message);
905 }
906
907 void User::WriteFrom(User *user, const std::string &text)
908 {
909         const std::string message = ":" + user->GetFullHost() + " " + text;
910         this->Write(message);
911 }
912
913
914 /* write text from an originating user to originating user */
915
916 void User::WriteFrom(User *user, const char* text, ...)
917 {
918         std::string textbuffer;
919         VAFORMAT(textbuffer, text, text);
920         this->WriteFrom(user, textbuffer);
921 }
922
923
924 /* write text to an destination user from a source user (e.g. user privmsg) */
925
926 void User::WriteTo(User *dest, const char *data, ...)
927 {
928         std::string textbuffer;
929         VAFORMAT(textbuffer, data, data);
930         this->WriteTo(dest, textbuffer);
931 }
932
933 void User::WriteTo(User *dest, const std::string &data)
934 {
935         dest->WriteFrom(this, data);
936 }
937
938 void User::WriteCommon(const char* text, ...)
939 {
940         if (this->registered != REG_ALL || quitting)
941                 return;
942
943         std::string textbuffer;
944         VAFORMAT(textbuffer, text, text);
945         textbuffer = ":" + this->GetFullHost() + " " + textbuffer;
946         this->WriteCommonRaw(textbuffer, true);
947 }
948
949 void User::WriteCommonExcept(const char* text, ...)
950 {
951         if (this->registered != REG_ALL || quitting)
952                 return;
953
954         std::string textbuffer;
955         VAFORMAT(textbuffer, text, text);
956         textbuffer = ":" + this->GetFullHost() + " " + textbuffer;
957         this->WriteCommonRaw(textbuffer, false);
958 }
959
960 void User::WriteCommonRaw(const std::string &line, bool include_self)
961 {
962         if (this->registered != REG_ALL || quitting)
963                 return;
964
965         LocalUser::already_sent_id++;
966
967         UserChanList include_c(chans);
968         std::map<User*,bool> exceptions;
969
970         exceptions[this] = include_self;
971
972         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
973
974         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
975         {
976                 LocalUser* u = IS_LOCAL(i->first);
977                 if (u && !u->quitting)
978                 {
979                         u->already_sent = LocalUser::already_sent_id;
980                         if (i->second)
981                                 u->Write(line);
982                 }
983         }
984         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
985         {
986                 Channel* c = *v;
987                 const UserMembList* ulist = c->GetUsers();
988                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
989                 {
990                         LocalUser* u = IS_LOCAL(i->first);
991                         if (u && !u->quitting && u->already_sent != LocalUser::already_sent_id)
992                         {
993                                 u->already_sent = LocalUser::already_sent_id;
994                                 u->Write(line);
995                         }
996                 }
997         }
998 }
999
1000 void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
1001 {
1002         if (this->registered != REG_ALL)
1003                 return;
1004
1005         already_sent_t uniq_id = ++LocalUser::already_sent_id;
1006
1007         const std::string normalMessage = ":" + this->GetFullHost() + " QUIT :" + normal_text;
1008         const std::string operMessage = ":" + this->GetFullHost() + " QUIT :" + oper_text;
1009
1010         UserChanList include_c(chans);
1011         std::map<User*,bool> exceptions;
1012
1013         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1014
1015         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1016         {
1017                 LocalUser* u = IS_LOCAL(i->first);
1018                 if (u && !u->quitting)
1019                 {
1020                         u->already_sent = uniq_id;
1021                         if (i->second)
1022                                 u->Write(u->IsOper() ? operMessage : normalMessage);
1023                 }
1024         }
1025         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1026         {
1027                 const UserMembList* ulist = (*v)->GetUsers();
1028                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1029                 {
1030                         LocalUser* u = IS_LOCAL(i->first);
1031                         if (u && !u->quitting && (u->already_sent != uniq_id))
1032                         {
1033                                 u->already_sent = uniq_id;
1034                                 u->Write(u->IsOper() ? operMessage : normalMessage);
1035                         }
1036                 }
1037         }
1038 }
1039
1040 void LocalUser::SendText(const std::string& line)
1041 {
1042         Write(line);
1043 }
1044
1045 void RemoteUser::SendText(const std::string& line)
1046 {
1047         ServerInstance->PI->PushToClient(this, line);
1048 }
1049
1050 void FakeUser::SendText(const std::string& line)
1051 {
1052 }
1053
1054 void User::SendText(const char *text, ...)
1055 {
1056         std::string line;
1057         VAFORMAT(line, text, text);
1058         SendText(line);
1059 }
1060
1061 void User::SendText(const std::string& linePrefix, std::stringstream& textStream)
1062 {
1063         std::string line;
1064         std::string word;
1065         while (textStream >> word)
1066         {
1067                 size_t lineLength = linePrefix.length() + line.length() + word.length() + 3; // "\s\n\r"
1068                 if (lineLength > ServerInstance->Config->Limits.MaxLine)
1069                 {
1070                         SendText(linePrefix + line);
1071                         line.clear();
1072                 }
1073                 line += " " + word;
1074         }
1075         SendText(linePrefix + line);
1076 }
1077
1078 /* return 0 or 1 depending if users u and u2 share one or more common channels
1079  * (used by QUIT, NICK etc which arent channel specific notices)
1080  *
1081  * The old algorithm in 1.0 for this was relatively inefficient, iterating over
1082  * the first users channels then the second users channels within the outer loop,
1083  * therefore it was a maximum of x*y iterations (upon returning 0 and checking
1084  * all possible iterations). However this new function instead checks against the
1085  * channel's userlist in the inner loop which is a std::map<User*,User*>
1086  * and saves us time as we already know what pointer value we are after.
1087  * Don't quote me on the maths as i am not a mathematician or computer scientist,
1088  * but i believe this algorithm is now x+(log y) maximum iterations instead.
1089  */
1090 bool User::SharesChannelWith(User *other)
1091 {
1092         if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))
1093                 return false;
1094
1095         /* Outer loop */
1096         for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1097         {
1098                 /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
1099                  * by replacing it with a map::find which *should* be more efficient
1100                  */
1101                 if ((*i)->HasUser(other))
1102                         return true;
1103         }
1104         return false;
1105 }
1106
1107 bool User::ChangeName(const char* gecos)
1108 {
1109         if (!this->fullname.compare(gecos))
1110                 return true;
1111
1112         if (IS_LOCAL(this))
1113         {
1114                 ModResult MOD_RESULT;
1115                 FIRST_MOD_RESULT(OnChangeLocalUserGECOS, MOD_RESULT, (IS_LOCAL(this),gecos));
1116                 if (MOD_RESULT == MOD_RES_DENY)
1117                         return false;
1118                 FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));
1119         }
1120         this->fullname.assign(gecos, 0, ServerInstance->Config->Limits.MaxGecos);
1121
1122         return true;
1123 }
1124
1125 void User::DoHostCycle(const std::string &quitline)
1126 {
1127         if (!ServerInstance->Config->CycleHosts)
1128                 return;
1129
1130         already_sent_t silent_id = ++LocalUser::already_sent_id;
1131         already_sent_t seen_id = ++LocalUser::already_sent_id;
1132
1133         UserChanList include_c(chans);
1134         std::map<User*,bool> exceptions;
1135
1136         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1137
1138         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1139         {
1140                 LocalUser* u = IS_LOCAL(i->first);
1141                 if (u && !u->quitting)
1142                 {
1143                         if (i->second)
1144                         {
1145                                 u->already_sent = seen_id;
1146                                 u->Write(quitline);
1147                         }
1148                         else
1149                         {
1150                                 u->already_sent = silent_id;
1151                         }
1152                 }
1153         }
1154         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1155         {
1156                 Channel* c = *v;
1157                 Membership* memb = c->GetUser(this);
1158                 const std::string joinline = ":" + GetFullHost() + " JOIN " + c->name;
1159                 std::string modeline;
1160
1161                 if (!memb->modes.empty())
1162                 {
1163                         modeline = ":" + (ServerInstance->Config->CycleHostsFromUser ? GetFullHost() : ServerInstance->Config->ServerName)
1164                                 + " MODE " + c->name + " +" + memb->modes;
1165
1166                         for (size_t i = 0; i < memb->modes.length(); i++)
1167                                 modeline.append(" ").append(nick);
1168                 }
1169
1170                 const UserMembList *ulist = c->GetUsers();
1171                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1172                 {
1173                         LocalUser* u = IS_LOCAL(i->first);
1174                         if (u == NULL || u == this)
1175                                 continue;
1176                         if (u->already_sent == silent_id)
1177                                 continue;
1178
1179                         if (u->already_sent != seen_id)
1180                         {
1181                                 u->Write(quitline);
1182                                 u->already_sent = seen_id;
1183                         }
1184                         u->Write(joinline);
1185                         if (!memb->modes.empty())
1186                                 u->Write(modeline);
1187                 }
1188         }
1189 }
1190
1191 bool User::ChangeDisplayedHost(const char* shost)
1192 {
1193         if (dhost == shost)
1194                 return true;
1195
1196         if (IS_LOCAL(this))
1197         {
1198                 ModResult MOD_RESULT;
1199                 FIRST_MOD_RESULT(OnChangeLocalUserHost, MOD_RESULT, (IS_LOCAL(this),shost));
1200                 if (MOD_RESULT == MOD_RES_DENY)
1201                         return false;
1202         }
1203
1204         FOREACH_MOD(I_OnChangeHost, OnChangeHost(this,shost));
1205
1206         std::string quitstr = ":" + GetFullHost() + " QUIT :Changing host";
1207
1208         /* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */
1209         this->dhost.assign(shost, 0, 64);
1210
1211         this->InvalidateCache();
1212
1213         this->DoHostCycle(quitstr);
1214
1215         if (IS_LOCAL(this))
1216                 this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s %s :is now your displayed host",this->nick.c_str(),this->dhost.c_str());
1217
1218         return true;
1219 }
1220
1221 bool User::ChangeIdent(const char* newident)
1222 {
1223         if (this->ident == newident)
1224                 return true;
1225
1226         FOREACH_MOD(I_OnChangeIdent, OnChangeIdent(this,newident));
1227
1228         std::string quitstr = ":" + GetFullHost() + " QUIT :Changing ident";
1229
1230         this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax);
1231
1232         this->InvalidateCache();
1233
1234         this->DoHostCycle(quitstr);
1235
1236         return true;
1237 }
1238
1239 void User::SendAll(const char* command, const char* text, ...)
1240 {
1241         std::string textbuffer;
1242         VAFORMAT(textbuffer, text, text);
1243         const std::string message = ":" + this->GetFullHost() + " " + command + " $* :" + textbuffer;
1244
1245         for (LocalUserList::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
1246         {
1247                 if ((*i)->registered == REG_ALL)
1248                         (*i)->Write(message);
1249         }
1250 }
1251
1252 /*
1253  * Sets a user's connection class.
1254  * If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc.
1255  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1256  * then their ip will be taken as 'priority' anyway, so for example,
1257  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1258  */
1259 void LocalUser::SetClass(const std::string &explicit_name)
1260 {
1261         ConnectClass *found = NULL;
1262
1263         ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Setting connect class for UID %s", this->uuid.c_str());
1264
1265         if (!explicit_name.empty())
1266         {
1267                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1268                 {
1269                         ConnectClass* c = *i;
1270
1271                         if (explicit_name == c->name)
1272                         {
1273                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Explicitly set to %s", explicit_name.c_str());
1274                                 found = c;
1275                         }
1276                 }
1277         }
1278         else
1279         {
1280                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1281                 {
1282                         ConnectClass* c = *i;
1283                         ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Checking %s", c->GetName().c_str());
1284
1285                         ModResult MOD_RESULT;
1286                         FIRST_MOD_RESULT(OnSetConnectClass, MOD_RESULT, (this,c));
1287                         if (MOD_RESULT == MOD_RES_DENY)
1288                                 continue;
1289                         if (MOD_RESULT == MOD_RES_ALLOW)
1290                         {
1291                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class forced by module to %s", c->GetName().c_str());
1292                                 found = c;
1293                                 break;
1294                         }
1295
1296                         if (c->type == CC_NAMED)
1297                                 continue;
1298
1299                         bool regdone = (registered != REG_NONE);
1300                         if (c->config->getBool("registered", regdone) != regdone)
1301                                 continue;
1302
1303                         /* check if host matches.. */
1304                         if (!InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) &&
1305                             !InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL))
1306                         {
1307                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "No host match (for %s)", c->GetHost().c_str());
1308                                 continue;
1309                         }
1310
1311                         /*
1312                          * deny change if change will take class over the limit check it HERE, not after we found a matching class,
1313                          * because we should attempt to find another class if this one doesn't match us. -- w00t
1314                          */
1315                         if (c->limit && (c->GetReferenceCount() >= c->limit))
1316                         {
1317                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit);
1318                                 continue;
1319                         }
1320
1321                         /* if it requires a port ... */
1322                         int port = c->config->getInt("port");
1323                         if (port)
1324                         {
1325                                 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Requires port (%d)", port);
1326
1327                                 /* and our port doesn't match, fail. */
1328                                 if (this->GetServerPort() != port)
1329                                         continue;
1330                         }
1331
1332                         if (regdone && !c->config->getString("password").empty())
1333                         {
1334                                 if (ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash")))
1335                                 {
1336                                         ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping");
1337                                         continue;
1338                                 }
1339                         }
1340
1341                         /* we stop at the first class that meets ALL critera. */
1342                         found = c;
1343                         break;
1344                 }
1345         }
1346
1347         /*
1348          * Okay, assuming we found a class that matches.. switch us into that class, keeping refcounts up to date.
1349          */
1350         if (found)
1351         {
1352                 MyClass = found;
1353         }
1354 }
1355
1356 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1357  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1358  * then their ip will be taken as 'priority' anyway, so for example,
1359  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1360  */
1361 ConnectClass* LocalUser::GetClass()
1362 {
1363         return MyClass;
1364 }
1365
1366 ConnectClass* User::GetClass()
1367 {
1368         return NULL;
1369 }
1370
1371 void User::PurgeEmptyChannels()
1372 {
1373         // firstly decrement the count on each channel
1374         for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
1375         {
1376                 Channel* c = *f;
1377                 c->DelUser(this);
1378         }
1379
1380         this->UnOper();
1381 }
1382
1383 const std::string& FakeUser::GetFullHost()
1384 {
1385         if (!ServerInstance->Config->HideWhoisServer.empty())
1386                 return ServerInstance->Config->HideWhoisServer;
1387         return server;
1388 }
1389
1390 const std::string& FakeUser::GetFullRealHost()
1391 {
1392         if (!ServerInstance->Config->HideWhoisServer.empty())
1393                 return ServerInstance->Config->HideWhoisServer;
1394         return server;
1395 }
1396
1397 ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask)
1398         : config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask),
1399         pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0),
1400         penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(0),
1401         limit(0), nouserdns(false)
1402 {
1403 }
1404
1405 ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask, const ConnectClass& parent)
1406         : config(tag), type(t), fakelag(parent.fakelag), name("unnamed"),
1407         registration_timeout(parent.registration_timeout), host(mask), pingtime(parent.pingtime),
1408         softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax), recvqmax(parent.recvqmax),
1409         penaltythreshold(parent.penaltythreshold), commandrate(parent.commandrate),
1410         maxlocal(parent.maxlocal), maxglobal(parent.maxglobal), maxconnwarn(parent.maxconnwarn), maxchans(parent.maxchans),
1411         limit(parent.limit), nouserdns(parent.nouserdns)
1412 {
1413 }
1414
1415 void ConnectClass::Update(const ConnectClass* src)
1416 {
1417         config = src->config;
1418         type = src->type;
1419         fakelag = src->fakelag;
1420         name = src->name;
1421         registration_timeout = src->registration_timeout;
1422         host = src->host;
1423         pingtime = src->pingtime;
1424         softsendqmax = src->softsendqmax;
1425         hardsendqmax = src->hardsendqmax;
1426         recvqmax = src->recvqmax;
1427         penaltythreshold = src->penaltythreshold;
1428         commandrate = src->commandrate;
1429         maxlocal = src->maxlocal;
1430         maxglobal = src->maxglobal;
1431         maxconnwarn = src->maxconnwarn;
1432         maxchans = src->maxchans;
1433         limit = src->limit;
1434         nouserdns = src->nouserdns;
1435 }