]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/users.cpp
Tons of comments!
[user/henk/code/inspircd.git] / src / users.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include <stdarg.h>
16 #include "socketengine.h"
17 #include "wildcard.h"
18 #include "xline.h"
19 #include "commands/cmd_whowas.h"
20
21 static unsigned long already_sent[MAX_DESCRIPTORS] = {0};
22
23 /* XXX: Used for speeding up WriteCommon operations */
24 unsigned long uniq_id = 0;
25
26 std::string User::ProcessNoticeMasks(const char *sm)
27 {
28         bool adding = true, oldadding = false;
29         const char *c = sm;
30         std::string output;
31
32         while (c && *c)
33         {
34                 switch (*c)
35                 {
36                         case '+':
37                                 adding = true;
38                         break;
39                         case '-':
40                                 adding = false;
41                         break;
42                         case '*':
43                                 for (unsigned char d = 'A'; d <= 'z'; d++)
44                                 {
45                                         if (ServerInstance->SNO->IsEnabled(d))
46                                         {
47                                                 if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))
48                                                 {
49                                                         if ((oldadding != adding) || (!output.length()))
50                                                                 output += (adding ? '+' : '-');
51
52                                                         this->SetNoticeMask(d, adding);
53
54                                                         output += d;
55                                                 }
56                                         }
57                                         oldadding = adding;
58                                 }
59                         break;
60                         default:
61                                 if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c)))
62                                 {
63                                         if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding))
64                                         {
65                                                 if ((oldadding != adding) || (!output.length()))
66                                                         output += (adding ? '+' : '-');
67
68                                                 this->SetNoticeMask(*c, adding);
69
70                                                 output += *c;
71                                         }
72                                 }
73                                 oldadding = adding;
74                         break;
75                 }
76
77                 *c++;
78         }
79
80         return output;
81 }
82
83 void User::StartDNSLookup()
84 {
85         try
86         {
87                 bool cached;
88                 const char* ip = this->GetIPString();
89
90                 /* Special case for 4in6 (Have i mentioned i HATE 4in6?) */
91                 if (!strncmp(ip, "0::ffff:", 8))
92                         res_reverse = new UserResolver(this->ServerInstance, this, ip + 8, DNS_QUERY_PTR4, cached);
93                 else
94                         res_reverse = new UserResolver(this->ServerInstance, this, ip, this->GetProtocolFamily() == AF_INET ? DNS_QUERY_PTR4 : DNS_QUERY_PTR6, cached);
95
96                 this->ServerInstance->AddResolver(res_reverse, cached);
97         }
98         catch (CoreException& e)
99         {
100                 ServerInstance->Log(DEBUG,"Error in resolver: %s",e.GetReason());
101         }
102 }
103
104 bool User::IsNoticeMaskSet(unsigned char sm)
105 {
106         return (snomasks[sm-65]);
107 }
108
109 void User::SetNoticeMask(unsigned char sm, bool value)
110 {
111         snomasks[sm-65] = value;
112 }
113
114 const char* User::FormatNoticeMasks()
115 {
116         static char data[MAXBUF];
117         int offset = 0;
118
119         for (int n = 0; n < 64; n++)
120         {
121                 if (snomasks[n])
122                         data[offset++] = n+65;
123         }
124
125         data[offset] = 0;
126         return data;
127 }
128
129
130
131 bool User::IsModeSet(unsigned char m)
132 {
133         return (modes[m-65]);
134 }
135
136 void User::SetMode(unsigned char m, bool value)
137 {
138         modes[m-65] = value;
139 }
140
141 const char* User::FormatModes()
142 {
143         static char data[MAXBUF];
144         int offset = 0;
145         for (int n = 0; n < 64; n++)
146         {
147                 if (modes[n])
148                         data[offset++] = n+65;
149         }
150         data[offset] = 0;
151         return data;
152 }
153
154 void User::DecrementModes()
155 {
156         ServerInstance->Log(DEBUG,"DecrementModes()");
157         for (unsigned char n = 'A'; n <= 'z'; n++)
158         {
159                 if (modes[n-65])
160                 {
161                         ServerInstance->Log(DEBUG,"DecrementModes() found mode %c", n);
162                         ModeHandler* mh = ServerInstance->Modes->FindMode(n, MODETYPE_USER);
163                         if (mh)
164                         {
165                                 ServerInstance->Log(DEBUG,"Found handler %c and call ChangeCount", n);
166                                 mh->ChangeCount(-1);
167                         }
168                 }
169         }
170 }
171
172 User::User(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance)
173 {
174         *password = *nick = *ident = *host = *dhost = *fullname = *awaymsg = *oper = *uuid = 0;
175         server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);
176         reset_due = ServerInstance->Time();
177         age = ServerInstance->Time(true);
178         lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;
179         ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;
180         muted = exempt = haspassed = dns_done = false;
181         fd = -1;
182         recvq.clear();
183         sendq.clear();
184         WriteError.clear();
185         res_forward = res_reverse = NULL;
186         Visibility = NULL;
187         ip = NULL;
188         chans.clear();
189         invites.clear();
190         memset(modes,0,sizeof(modes));
191         memset(snomasks,0,sizeof(snomasks));
192         /* Invalidate cache */
193         operquit = cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL;
194
195         if (uid.empty())
196                 strlcpy(uuid, Instance->GetUID().c_str(), UUID_LENGTH);
197         else
198                 strlcpy(uuid, uid.c_str(), UUID_LENGTH);
199
200         ServerInstance->Log(DEBUG,"New UUID for user: %s (%s)", uuid, uid.empty() ? "allocated new" : "used remote");
201
202         user_hash::iterator finduuid = Instance->uuidlist->find(uuid);
203         if (finduuid == Instance->uuidlist->end())
204                 (*Instance->uuidlist)[uuid] = this;
205         else
206                 throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor");
207 }
208
209 void User::RemoveCloneCounts()
210 {
211         clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());
212         if (x != ServerInstance->local_clones.end())
213         {
214                 x->second--;
215                 if (!x->second)
216                 {
217                         ServerInstance->local_clones.erase(x);
218                 }
219         }
220         
221         clonemap::iterator y = ServerInstance->global_clones.find(this->GetIPString());
222         if (y != ServerInstance->global_clones.end())
223         {
224                 y->second--;
225                 if (!y->second)
226                 {
227                         ServerInstance->global_clones.erase(y);
228                 }
229         }
230 }
231
232 User::~User()
233 {
234         this->InvalidateCache();
235         this->DecrementModes();
236         if (operquit)
237                 free(operquit);
238         if (ip)
239         {
240                 this->RemoveCloneCounts();
241
242                 if (this->GetProtocolFamily() == AF_INET)
243                 {
244                         delete (sockaddr_in*)ip;
245                 }
246 #ifdef SUPPORT_IP6LINKS
247                 else
248                 {
249                         delete (sockaddr_in6*)ip;
250                 }
251 #endif
252         }
253
254         ServerInstance->uuidlist->erase(uuid);
255 }
256
257 char* User::MakeHost()
258 {
259         if (this->cached_makehost)
260                 return this->cached_makehost;
261
262         char nhost[MAXBUF];
263         /* This is much faster than snprintf */
264         char* t = nhost;
265         for(char* n = ident; *n; n++)
266                 *t++ = *n;
267         *t++ = '@';
268         for(char* n = host; *n; n++)
269                 *t++ = *n;
270         *t = 0;
271
272         this->cached_makehost = strdup(nhost);
273
274         return this->cached_makehost;
275 }
276
277 char* User::MakeHostIP()
278 {
279         if (this->cached_hostip)
280                 return this->cached_hostip;
281
282         char ihost[MAXBUF];
283         /* This is much faster than snprintf */
284         char* t = ihost;
285         for(char* n = ident; *n; n++)
286                 *t++ = *n;
287         *t++ = '@';
288         for(const char* n = this->GetIPString(); *n; n++)
289                 *t++ = *n;
290         *t = 0;
291
292         this->cached_hostip = strdup(ihost);
293
294         return this->cached_hostip;
295 }
296
297 void User::CloseSocket()
298 {
299         ServerInstance->SE->Shutdown(this, 2);
300         ServerInstance->SE->Close(this);
301 }
302
303 char* User::GetFullHost()
304 {
305         if (this->cached_fullhost)
306                 return this->cached_fullhost;
307
308         char result[MAXBUF];
309         char* t = result;
310         for(char* n = nick; *n; n++)
311                 *t++ = *n;
312         *t++ = '!';
313         for(char* n = ident; *n; n++)
314                 *t++ = *n;
315         *t++ = '@';
316         for(char* n = dhost; *n; n++)
317                 *t++ = *n;
318         *t = 0;
319
320         this->cached_fullhost = strdup(result);
321
322         return this->cached_fullhost;
323 }
324
325 char* User::MakeWildHost()
326 {
327         static char nresult[MAXBUF];
328         char* t = nresult;
329         *t++ = '*';     *t++ = '!';
330         *t++ = '*';     *t++ = '@';
331         for(char* n = dhost; *n; n++)
332                 *t++ = *n;
333         *t = 0;
334         return nresult;
335 }
336
337 int User::ReadData(void* buffer, size_t size)
338 {
339         if (IS_LOCAL(this))
340         {
341 #ifndef WIN32
342                 return read(this->fd, buffer, size);
343 #else
344                 return recv(this->fd, (char*)buffer, size, 0);
345 #endif
346         }
347         else
348                 return 0;
349 }
350
351
352 char* User::GetFullRealHost()
353 {
354         if (this->cached_fullrealhost)
355                 return this->cached_fullrealhost;
356
357         char fresult[MAXBUF];
358         char* t = fresult;
359         for(char* n = nick; *n; n++)
360                 *t++ = *n;
361         *t++ = '!';
362         for(char* n = ident; *n; n++)
363                 *t++ = *n;
364         *t++ = '@';
365         for(char* n = host; *n; n++)
366                 *t++ = *n;
367         *t = 0;
368
369         this->cached_fullrealhost = strdup(fresult);
370
371         return this->cached_fullrealhost;
372 }
373
374 bool User::IsInvited(const irc::string &channel)
375 {
376         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
377         {
378                 if (channel == *i)
379                 {
380                         return true;
381                 }
382         }
383         return false;
384 }
385
386 InvitedList* User::GetInviteList()
387 {
388         return &invites;
389 }
390
391 void User::InviteTo(const irc::string &channel)
392 {
393         invites.push_back(channel);
394 }
395
396 void User::RemoveInvite(const irc::string &channel)
397 {
398         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
399         {
400                 if (channel == *i)
401                 {
402                         invites.erase(i);
403                         return;
404                 }
405         }
406 }
407
408 bool User::HasPermission(const std::string &command)
409 {
410         char* mycmd;
411         char* savept;
412         char* savept2;
413
414         /*
415          * users on remote servers can completely bypass all permissions based checks.
416          * This prevents desyncs when one server has different type/class tags to another.
417          * That having been said, this does open things up to the possibility of source changes
418          * allowing remote kills, etc - but if they have access to the src, they most likely have
419          * access to the conf - so it's an end to a means either way.
420          */
421         if (!IS_LOCAL(this))
422                 return true;
423
424         // are they even an oper at all?
425         if (!IS_OPER(this))
426         {
427                 return false;
428         }
429
430         // check their opertype exists (!). This won't affect local users, of course.
431         opertype_t::iterator iter_opertype = ServerInstance->Config->opertypes.find(this->oper);
432         if (iter_opertype == ServerInstance->Config->opertypes.end())
433         {
434                 return false;
435         }
436
437         /* XXX all this strtok/strdup stuff is a bit ick and horrid -- w00t */
438         char* Classes = strdup(iter_opertype->second);
439         char* myclass = strtok_r(Classes," ",&savept);
440         while (myclass)
441         {
442                 operclass_t::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass);
443                 if (iter_operclass != ServerInstance->Config->operclass.end())
444                 {
445                         char* CommandList = strdup(iter_operclass->second);
446                         mycmd = strtok_r(CommandList," ",&savept2);
447                         while (mycmd)
448                         {
449                                 if ((!strcasecmp(mycmd,command.c_str())) || (*mycmd == '*'))
450                                 {
451                                         free(Classes);
452                                         free(CommandList);
453                                         return true;
454                                 }
455                                 mycmd = strtok_r(NULL," ",&savept2);
456                         }
457                         free(CommandList);
458                 }
459                 myclass = strtok_r(NULL," ",&savept);
460         }
461         free(Classes);
462
463         return false;
464 }
465
466 /** NOTE: We cannot pass a const reference to this method.
467  * The string is changed by the workings of the method,
468  * so that if we pass const ref, we end up copying it to
469  * something we can change anyway. Makes sense to just let
470  * the compiler do that copy for us.
471  */
472 bool User::AddBuffer(std::string a)
473 {
474         try
475         {
476                 std::string::size_type i = a.rfind('\r');
477
478                 while (i != std::string::npos)
479                 {
480                         a.erase(i, 1);
481                         i = a.rfind('\r');
482                 }
483
484                 if (a.length())
485                         recvq.append(a);
486
487                 if (recvq.length() > (unsigned)this->recvqmax)
488                 {
489                         this->SetWriteError("RecvQ exceeded");
490                         ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
491                         return false;
492                 }
493
494                 return true;
495         }
496
497         catch (...)
498         {
499                 ServerInstance->Log(DEBUG,"Exception in User::AddBuffer()");
500                 return false;
501         }
502 }
503
504 bool User::BufferIsReady()
505 {
506         return (recvq.find('\n') != std::string::npos);
507 }
508
509 void User::ClearBuffer()
510 {
511         recvq.clear();
512 }
513
514 std::string User::GetBuffer()
515 {
516         try
517         {
518                 if (!recvq.length())
519                         return "";
520
521                 /* Strip any leading \r or \n off the string.
522                  * Usually there are only one or two of these,
523                  * so its is computationally cheap to do.
524                  */
525                 std::string::iterator t = recvq.begin();
526                 while (t != recvq.end() && (*t == '\r' || *t == '\n'))
527                 {
528                         recvq.erase(t);
529                         t = recvq.begin();
530                 }
531
532                 for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++)
533                 {
534                         /* Find the first complete line, return it as the
535                          * result, and leave the recvq as whats left
536                          */
537                         if (*x == '\n')
538                         {
539                                 std::string ret = std::string(recvq.begin(), x);
540                                 recvq.erase(recvq.begin(), x + 1);
541                                 return ret;
542                         }
543                 }
544                 return "";
545         }
546
547         catch (...)
548         {
549                 ServerInstance->Log(DEBUG,"Exception in User::GetBuffer()");
550                 return "";
551         }
552 }
553
554 void User::AddWriteBuf(const std::string &data)
555 {
556         if (*this->GetWriteError())
557                 return;
558
559         if (sendq.length() + data.length() > (unsigned)this->sendqmax)
560         {
561                 /*
562                  * Fix by brain - Set the error text BEFORE calling writeopers, because
563                  * if we dont it'll recursively  call here over and over again trying
564                  * to repeatedly add the text to the sendq!
565                  */
566                 this->SetWriteError("SendQ exceeded");
567                 ServerInstance->WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
568                 return;
569         }
570
571         try
572         {
573                 if (data.length() > MAXBUF - 2) /* MAXBUF has a value of 514, to account for line terminators */
574                         sendq.append(data.substr(0,MAXBUF - 4)).append("\r\n"); /* MAXBUF-4 = 510 */
575                 else
576                         sendq.append(data);
577         }
578         catch (...)
579         {
580                 this->SetWriteError("SendQ exceeded");
581                 ServerInstance->WriteOpers("*** User %s SendQ got an exception",this->nick);
582         }
583 }
584
585 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
586 void User::FlushWriteBuf()
587 {
588         try
589         {
590                 if ((this->fd == FD_MAGIC_NUMBER) || (*this->GetWriteError()))
591                 {
592                         sendq.clear();
593                 }
594                 if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
595                 {
596                         int old_sendq_length = sendq.length();
597                         int n_sent = ServerInstance->SE->Send(this, this->sendq.data(), this->sendq.length(), 0);
598
599                         if (n_sent == -1)
600                         {
601                                 if (errno == EAGAIN)
602                                 {
603                                         /* The socket buffer is full. This isnt fatal,
604                                          * try again later.
605                                          */
606                                         this->ServerInstance->SE->WantWrite(this);
607                                 }
608                                 else
609                                 {
610                                         /* Fatal error, set write error and bail
611                                          */
612                                         this->SetWriteError(errno ? strerror(errno) : "EOF from client");
613                                         return;
614                                 }
615                         }
616                         else
617                         {
618                                 /* advance the queue */
619                                 if (n_sent)
620                                         this->sendq = this->sendq.substr(n_sent);
621                                 /* update the user's stats counters */
622                                 this->bytes_out += n_sent;
623                                 this->cmds_out++;
624                                 if (n_sent != old_sendq_length)
625                                         this->ServerInstance->SE->WantWrite(this);
626                         }
627                 }
628         }
629
630         catch (...)
631         {
632                 ServerInstance->Log(DEBUG,"Exception in User::FlushWriteBuf()");
633         }
634
635         if (this->sendq.empty())
636         {
637                 FOREACH_MOD(I_OnBufferFlushed,OnBufferFlushed(this));
638         }
639 }
640
641 void User::SetWriteError(const std::string &error)
642 {
643         try
644         {
645                 // don't try to set the error twice, its already set take the first string.
646                 if (this->WriteError.empty())
647                         this->WriteError = error;
648         }
649
650         catch (...)
651         {
652                 ServerInstance->Log(DEBUG,"Exception in User::SetWriteError()");
653         }
654 }
655
656 const char* User::GetWriteError()
657 {
658         return this->WriteError.c_str();
659 }
660
661 void User::Oper(const std::string &opertype)
662 {
663         try
664         {
665                 this->modes[UM_OPERATOR] = 1;
666                 this->WriteServ("MODE %s :+o", this->nick);
667                 FOREACH_MOD(I_OnOper, OnOper(this, opertype));
668                 ServerInstance->Log(DEFAULT,"OPER: %s!%s@%s opered as type: %s", this->nick, this->ident, this->host, opertype.c_str());
669                 strlcpy(this->oper, opertype.c_str(), NICKMAX - 1);
670                 ServerInstance->all_opers.push_back(this);
671                 FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype));
672         }
673
674         catch (...)
675         {
676                 ServerInstance->Log(DEBUG,"Exception in User::Oper()");
677         }
678 }
679
680 void User::UnOper()
681 {
682         try
683         {
684                 if (IS_OPER(this))
685                 {
686                         // unset their oper type (what IS_OPER checks), and remove +o
687                         *this->oper = 0;
688                         this->modes[UM_OPERATOR] = 0;
689                         
690                         // remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404
691                         ServerInstance->all_opers.remove(this);
692                 }
693         }
694
695         catch (...)
696         {
697                 ServerInstance->Log(DEBUG,"Exception in User::UnOper()");
698         }
699 }
700
701 void User::QuitUser(InspIRCd* Instance, User *user, const std::string &quitreason, const char* operreason)
702 {
703         Instance->Log(DEBUG,"QuitUser: %s", user->nick);
704         user->Write("ERROR :Closing link (%s@%s) [%s]", user->ident, user->host, operreason);
705         user->muted = true;
706         Instance->GlobalCulls.AddItem(user, quitreason.c_str(), operreason);
707 }
708
709 /* adds or updates an entry in the whowas list */
710 void User::AddToWhoWas()
711 {
712         Command* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
713         if (whowas_command)
714         {
715                 std::deque<classbase*> params;
716                 params.push_back(this);
717                 whowas_command->HandleInternal(WHOWAS_ADD, params);
718         }
719 }
720
721 /* add a client connection to the sockets list */
722 void User::AddClient(InspIRCd* Instance, int socket, int port, bool iscached, int socketfamily, sockaddr* ip)
723 {
724         /* NOTE: Calling this one parameter constructor for User automatically
725          * allocates a new UUID and places it in the hash_map.
726          */
727         User* New = NULL;
728         try
729         {
730                 New = new User(Instance);
731         }
732         catch (...)
733         {
734                 Instance->Log(DEFAULT,"*** WTF *** Duplicated UUID! -- Crack smoking monkies have been unleashed.");
735                 Instance->WriteOpers("*** WARNING *** Duplicate UUID allocated!");
736                 return;
737         }
738
739         Instance->Log(DEBUG,"New user fd: %d", socket);
740
741         int j = 0;
742
743         Instance->unregistered_count++;
744
745         char ipaddr[MAXBUF];
746 #ifdef IPV6
747         if (socketfamily == AF_INET6)
748                 inet_ntop(AF_INET6, &((const sockaddr_in6*)ip)->sin6_addr, ipaddr, sizeof(ipaddr));
749         else
750 #endif
751         inet_ntop(AF_INET, &((const sockaddr_in*)ip)->sin_addr, ipaddr, sizeof(ipaddr));
752
753         (*(Instance->clientlist))[New->uuid] = New;
754         New->SetFd(socket);
755
756         /* The users default nick is their UUID */
757         strlcpy(New->nick, New->uuid, NICKMAX - 1);
758
759         New->server = Instance->FindServerNamePtr(Instance->Config->ServerName);
760         /* We don't need range checking here, we KNOW 'unknown\0' will fit into the ident field. */
761         strcpy(New->ident, "unknown");
762
763         New->registered = REG_NONE;
764         New->signon = Instance->Time() + Instance->Config->dns_timeout;
765         New->lastping = 1;
766
767         New->SetSockAddr(socketfamily, ipaddr, port);
768
769         /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
770         for (const char* temp = New->GetIPString(); *temp && j < 64; temp++, j++)
771                 New->dhost[j] = New->host[j] = *temp;
772         New->dhost[j] = New->host[j] = 0;
773
774         Instance->AddLocalClone(New);
775         Instance->AddGlobalClone(New);
776
777         /*
778          * First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
779          * See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
780          */
781         ConnectClass* i = New->GetClass();
782
783         if (!i)
784         {
785                 User::QuitUser(Instance, New, "Access denied by configuration");
786                 return;
787         }
788
789         /*
790          * Check connect class settings and initialise settings into User.
791          * This will be done again after DNS resolution. -- w00t
792          */
793         New->CheckClass();
794
795         Instance->local_users.push_back(New);
796
797         if ((Instance->local_users.size() > Instance->Config->SoftLimit) || (Instance->local_users.size() >= MAXCLIENTS))
798         {
799                 Instance->WriteOpers("*** Warning: softlimit value has been reached: %d clients", Instance->Config->SoftLimit);
800                 User::QuitUser(Instance, New,"No more connections allowed");
801                 return;
802         }
803
804         /*
805          * XXX -
806          * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
807          * its a pretty big but for the moment valid assumption:
808          * file descriptors are handed out starting at 0, and are recycled as theyre freed.
809          * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
810          * irc server at once (or the irc server otherwise initiating this many connections, files etc)
811          * which for the time being is a physical impossibility (even the largest networks dont have more
812          * than about 10,000 users on ONE server!)
813          */
814 #ifndef WINDOWS
815         if ((unsigned int)socket >= MAX_DESCRIPTORS)
816         {
817                 User::QuitUser(Instance, New, "Server is full");
818                 return;
819         }
820 #endif
821
822         New->exempt = (Instance->XLines->matches_exception(New) != NULL);
823         if (!New->exempt)
824         {
825                 ZLine* r = Instance->XLines->matches_zline(ipaddr);
826                 if (r)
827                 {
828                         char reason[MAXBUF];
829                         if (*Instance->Config->MoronBanner)
830                                 New->WriteServ("NOTICE %s :*** %s", New->nick, Instance->Config->MoronBanner);
831                         snprintf(reason,MAXBUF,"Z-Lined: %s",r->reason);
832                         User::QuitUser(Instance, New, reason);
833                         return;
834                 }
835         }
836
837         if (socket > -1)
838         {
839                 if (!Instance->SE->AddFd(New))
840                 {
841                         Instance->Log(DEBUG,"Internal error on new connection");
842                         User::QuitUser(Instance, New, "Internal error handling connection");
843                 }
844         }
845
846         /* NOTE: even if dns lookups are *off*, we still need to display this.
847          * BOPM and other stuff requires it.
848          */
849         New->WriteServ("NOTICE Auth :*** Looking up your hostname...");
850 }
851
852 unsigned long User::GlobalCloneCount()
853 {
854         clonemap::iterator x = ServerInstance->global_clones.find(this->GetIPString());
855         if (x != ServerInstance->global_clones.end())
856                 return x->second;
857         else
858                 return 0;
859 }
860
861 unsigned long User::LocalCloneCount()
862 {
863         clonemap::iterator x = ServerInstance->local_clones.find(this->GetIPString());
864         if (x != ServerInstance->local_clones.end())
865                 return x->second;
866         else
867                 return 0;
868 }
869
870 /*
871  * Check class restrictions
872  */
873 void User::CheckClass(const std::string &explicit_class)
874 {
875         ConnectClass* a = this->GetClass(explicit_class);
876
877         if ((!a) || (a->GetType() == CC_DENY))
878         {
879                 User::QuitUser(ServerInstance, this, "Unauthorised connection");
880                 return;
881         }
882         else if ((a->GetMaxLocal()) && (this->LocalCloneCount() > a->GetMaxLocal()))
883         {
884                 User::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (local)");
885                 ServerInstance->WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString());
886                 return;
887         }
888         else if ((a->GetMaxGlobal()) && (this->GlobalCloneCount() > a->GetMaxGlobal()))
889         {
890                 User::QuitUser(ServerInstance, this, "No more connections allowed from your host via this connect class (global)");
891                 ServerInstance->WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString());
892                 return;
893         }
894
895         this->pingmax = a->GetPingTime();
896         this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
897         this->timeout = ServerInstance->Time() + a->GetRegTimeout();
898         this->flood = a->GetFlood();
899         this->threshold = a->GetThreshold();
900         this->sendqmax = a->GetSendqMax();
901         this->recvqmax = a->GetRecvqMax();
902         this->MaxChans = a->GetMaxChans();
903 }
904
905 void User::FullConnect()
906 {
907         ServerInstance->stats->statsConnects++;
908         this->idle_lastmsg = ServerInstance->Time();
909
910         /*
911          * You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT.
912          * At the time AddClient is called, we don't have a resolved host, by here we probably do - which
913          * may put the user into a totally seperate class with different restrictions! so we *must* check again.
914          * Don't remove this! -- w00t
915          */
916         this->CheckClass();
917         
918         /* Check the password, if one is required by the user's connect class.
919          * This CANNOT be in CheckClass(), because that is called prior to PASS as well!
920          */
921         if ((!this->GetClass()->GetPass().empty()) && (!this->haspassed))
922         {
923                 User::QuitUser(ServerInstance, this, "Invalid password");
924                 return;
925         }
926         
927         if (!this->exempt)
928         {
929                 GLine* r = ServerInstance->XLines->matches_gline(this);
930
931                 if (r)
932                 {
933                         this->muted = true;
934                         char reason[MAXBUF];
935                         if (*ServerInstance->Config->MoronBanner)
936                                 this->WriteServ("NOTICE %s :*** %s", this->nick, ServerInstance->Config->MoronBanner);
937                         snprintf(reason,MAXBUF,"G-Lined: %s",r->reason);
938                         User::QuitUser(ServerInstance, this, reason);
939                         return;
940                 }
941
942                 KLine* n = ServerInstance->XLines->matches_kline(this);
943
944                 if (n)
945                 {
946                         this->muted = true;
947                         char reason[MAXBUF];
948                         if (*ServerInstance->Config->MoronBanner)
949                                 this->WriteServ("NOTICE %s :*** %s", this, ServerInstance->Config->MoronBanner);
950                         snprintf(reason,MAXBUF,"K-Lined: %s",n->reason);
951                         User::QuitUser(ServerInstance, this, reason);
952                         return;
953                 }
954         }
955
956         this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network);
957         this->WriteServ("001 %s :Welcome to the %s IRC Network %s!%s@%s",this->nick, ServerInstance->Config->Network, this->nick, this->ident, this->host);
958         this->WriteServ("002 %s :Your host is %s, running version %s",this->nick,ServerInstance->Config->ServerName,VERSION);
959         this->WriteServ("003 %s :This server was created %s %s", this->nick, __TIME__, __DATE__);
960         this->WriteServ("004 %s %s %s %s %s %s", this->nick, ServerInstance->Config->ServerName, VERSION, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());
961
962         ServerInstance->Config->Send005(this);
963
964         this->WriteServ("042 %s %s :your unique ID", this->nick, this->uuid);
965
966
967         this->ShowMOTD();
968
969         /* Now registered */
970         if (ServerInstance->unregistered_count)
971                 ServerInstance->unregistered_count--;
972
973         /* Trigger LUSERS output, give modules a chance too */
974         int MOD_RESULT = 0;
975         FOREACH_RESULT(I_OnPreCommand, OnPreCommand("LUSERS", NULL, 0, this, true, "LUSERS"));
976         if (!MOD_RESULT)
977                 ServerInstance->CallCommandHandler("LUSERS", NULL, 0, this);
978
979         /*
980          * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
981          * for a user that doesn't exist yet.
982          */
983         FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
984
985         this->registered = REG_ALL;
986
987         FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
988
989         ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s] [%s]", this->GetPort(), this->nick, this->ident, this->host, this->GetIPString(), this->fullname);
990 }
991
992 /** User::UpdateNick()
993  * re-allocates a nick in the user_hash after they change nicknames,
994  * returns a pointer to the new user as it may have moved
995  */
996 User* User::UpdateNickHash(const char* New)
997 {
998         try
999         {
1000                 //user_hash::iterator newnick;
1001                 user_hash::iterator oldnick = ServerInstance->clientlist->find(this->nick);
1002
1003                 if (!strcasecmp(this->nick,New))
1004                         return oldnick->second;
1005
1006                 if (oldnick == ServerInstance->clientlist->end())
1007                         return NULL; /* doesnt exist */
1008
1009                 User* olduser = oldnick->second;
1010                 (*(ServerInstance->clientlist))[New] = olduser;
1011                 ServerInstance->clientlist->erase(oldnick);
1012                 return olduser;
1013         }
1014
1015         catch (...)
1016         {
1017                 ServerInstance->Log(DEBUG,"Exception in User::UpdateNickHash()");
1018                 return NULL;
1019         }
1020 }
1021
1022 void User::InvalidateCache()
1023 {
1024         /* Invalidate cache */
1025         if (cached_fullhost)
1026                 free(cached_fullhost);
1027         if (cached_hostip)
1028                 free(cached_hostip);
1029         if (cached_makehost)
1030                 free(cached_makehost);
1031         if (cached_fullrealhost)
1032                 free(cached_fullrealhost);
1033         cached_fullhost = cached_hostip = cached_makehost = cached_fullrealhost = NULL;
1034 }
1035
1036 bool User::ForceNickChange(const char* newnick)
1037 {
1038         try
1039         {
1040                 int MOD_RESULT = 0;
1041
1042                 this->InvalidateCache();
1043
1044                 FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick));
1045
1046                 if (MOD_RESULT)
1047                 {
1048                         ServerInstance->stats->statsCollisions++;
1049                         return false;
1050                 }
1051
1052                 if (ServerInstance->XLines->matches_qline(newnick))
1053                 {
1054                         ServerInstance->stats->statsCollisions++;
1055                         return false;
1056                 }
1057
1058                 if (this->registered == REG_ALL)
1059                 {
1060                         std::deque<classbase*> dummy;
1061                         Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
1062                         if (nickhandler)
1063                         {
1064                                 nickhandler->HandleInternal(1, dummy);
1065                                 bool result = (ServerInstance->Parser->CallHandler("NICK", &newnick, 1, this) == CMD_SUCCESS);
1066                                 nickhandler->HandleInternal(0, dummy);
1067                                 return result;
1068                         }
1069                 }
1070                 return false;
1071         }
1072
1073         catch (...)
1074         {
1075                 ServerInstance->Log(DEBUG,"Exception in User::ForceNickChange()");
1076                 return false;
1077         }
1078 }
1079
1080 void User::SetSockAddr(int protocol_family, const char* ip, int port)
1081 {
1082         switch (protocol_family)
1083         {
1084 #ifdef SUPPORT_IP6LINKS
1085                 case AF_INET6:
1086                 {
1087                         sockaddr_in6* sin = new sockaddr_in6;
1088                         sin->sin6_family = AF_INET6;
1089                         sin->sin6_port = port;
1090                         inet_pton(AF_INET6, ip, &sin->sin6_addr);
1091                         this->ip = (sockaddr*)sin;
1092                 }
1093                 break;
1094 #endif
1095                 case AF_INET:
1096                 {
1097                         sockaddr_in* sin = new sockaddr_in;
1098                         sin->sin_family = AF_INET;
1099                         sin->sin_port = port;
1100                         inet_pton(AF_INET, ip, &sin->sin_addr);
1101                         this->ip = (sockaddr*)sin;
1102                 }
1103                 break;
1104                 default:
1105                         ServerInstance->Log(DEBUG,"Uh oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick);
1106                 break;
1107         }
1108 }
1109
1110 int User::GetPort()
1111 {
1112         if (this->ip == NULL)
1113                 return 0;
1114
1115         switch (this->GetProtocolFamily())
1116         {
1117 #ifdef SUPPORT_IP6LINKS
1118                 case AF_INET6:
1119                 {
1120                         sockaddr_in6* sin = (sockaddr_in6*)this->ip;
1121                         return sin->sin6_port;
1122                 }
1123                 break;
1124 #endif
1125                 case AF_INET:
1126                 {
1127                         sockaddr_in* sin = (sockaddr_in*)this->ip;
1128                         return sin->sin_port;
1129                 }
1130                 break;
1131                 default:
1132                 break;
1133         }
1134         return 0;
1135 }
1136
1137 int User::GetProtocolFamily()
1138 {
1139         if (this->ip == NULL)
1140                 return 0;
1141
1142         sockaddr_in* sin = (sockaddr_in*)this->ip;
1143         return sin->sin_family;
1144 }
1145
1146 /*
1147  * XXX the duplication here is horrid..
1148  * do we really need two methods doing essentially the same thing?
1149  */
1150 const char* User::GetIPString()
1151 {
1152         static char buf[1024];
1153
1154         if (this->ip == NULL)
1155                 return "";
1156
1157         switch (this->GetProtocolFamily())
1158         {
1159 #ifdef SUPPORT_IP6LINKS
1160                 case AF_INET6:
1161                 {
1162                         static char temp[1024];
1163
1164                         sockaddr_in6* sin = (sockaddr_in6*)this->ip;
1165                         inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));
1166                         /* IP addresses starting with a : on irc are a Bad Thing (tm) */
1167                         if (*buf == ':')
1168                         {
1169                                 strlcpy(&temp[1], buf, sizeof(temp) - 1);
1170                                 *temp = '0';
1171                                 return temp;
1172                         }
1173                         return buf;
1174                 }
1175                 break;
1176 #endif
1177                 case AF_INET:
1178                 {
1179                         sockaddr_in* sin = (sockaddr_in*)this->ip;
1180                         inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));
1181                         return buf;
1182                 }
1183                 break;
1184                 default:
1185                 break;
1186         }
1187         return "";
1188 }
1189
1190 /** NOTE: We cannot pass a const reference to this method.
1191  * The string is changed by the workings of the method,
1192  * so that if we pass const ref, we end up copying it to
1193  * something we can change anyway. Makes sense to just let
1194  * the compiler do that copy for us.
1195  */
1196 void User::Write(std::string text)
1197 {
1198         if (!ServerInstance->SE->BoundsCheckFd(this))
1199                 return;
1200
1201         try
1202         {
1203                 /* ServerInstance->Log(DEBUG,"C[%d] O %s", this->GetFd(), text.c_str());
1204                  * WARNING: The above debug line is VERY loud, do NOT
1205                  * enable it till we have a good way of filtering it
1206                  * out of the logs (e.g. 1.2 would be good).
1207                  */
1208                 text.append("\r\n");
1209         }
1210         catch (...)
1211         {
1212                 ServerInstance->Log(DEBUG,"Exception in User::Write() std::string::append");
1213                 return;
1214         }
1215
1216         if (ServerInstance->Config->GetIOHook(this->GetPort()))
1217         {
1218                 try
1219                 {
1220                         /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
1221                          * implement their own buffering mechanisms
1222                          */
1223                         ServerInstance->Config->GetIOHook(this->GetPort())->OnRawSocketWrite(this->fd, text.data(), text.length());
1224                 }
1225                 catch (CoreException& modexcept)
1226                 {
1227                         ServerInstance->Log(DEBUG, "%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
1228                 }
1229         }
1230         else
1231         {
1232                 this->AddWriteBuf(text);
1233         }
1234         ServerInstance->stats->statsSent += text.length();
1235         this->ServerInstance->SE->WantWrite(this);
1236 }
1237
1238 /** Write()
1239  */
1240 void User::Write(const char *text, ...)
1241 {
1242         va_list argsPtr;
1243         char textbuffer[MAXBUF];
1244
1245         va_start(argsPtr, text);
1246         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1247         va_end(argsPtr);
1248
1249         this->Write(std::string(textbuffer));
1250 }
1251
1252 void User::WriteServ(const std::string& text)
1253 {
1254         char textbuffer[MAXBUF];
1255
1256         snprintf(textbuffer,MAXBUF,":%s %s",ServerInstance->Config->ServerName,text.c_str());
1257         this->Write(std::string(textbuffer));
1258 }
1259
1260 /** WriteServ()
1261  *  Same as Write(), except `text' is prefixed with `:server.name '.
1262  */
1263 void User::WriteServ(const char* text, ...)
1264 {
1265         va_list argsPtr;
1266         char textbuffer[MAXBUF];
1267
1268         va_start(argsPtr, text);
1269         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1270         va_end(argsPtr);
1271
1272         this->WriteServ(std::string(textbuffer));
1273 }
1274
1275
1276 void User::WriteFrom(User *user, const std::string &text)
1277 {
1278         char tb[MAXBUF];
1279
1280         snprintf(tb,MAXBUF,":%s %s",user->GetFullHost(),text.c_str());
1281
1282         this->Write(std::string(tb));
1283 }
1284
1285
1286 /* write text from an originating user to originating user */
1287
1288 void User::WriteFrom(User *user, const char* text, ...)
1289 {
1290         va_list argsPtr;
1291         char textbuffer[MAXBUF];
1292
1293         va_start(argsPtr, text);
1294         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1295         va_end(argsPtr);
1296
1297         this->WriteFrom(user, std::string(textbuffer));
1298 }
1299
1300
1301 /* write text to an destination user from a source user (e.g. user privmsg) */
1302
1303 void User::WriteTo(User *dest, const char *data, ...)
1304 {
1305         char textbuffer[MAXBUF];
1306         va_list argsPtr;
1307
1308         va_start(argsPtr, data);
1309         vsnprintf(textbuffer, MAXBUF, data, argsPtr);
1310         va_end(argsPtr);
1311
1312         this->WriteTo(dest, std::string(textbuffer));
1313 }
1314
1315 void User::WriteTo(User *dest, const std::string &data)
1316 {
1317         dest->WriteFrom(this, data);
1318 }
1319
1320
1321 void User::WriteCommon(const char* text, ...)
1322 {
1323         char textbuffer[MAXBUF];
1324         va_list argsPtr;
1325
1326         if (this->registered != REG_ALL)
1327                 return;
1328
1329         va_start(argsPtr, text);
1330         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1331         va_end(argsPtr);
1332
1333         this->WriteCommon(std::string(textbuffer));
1334 }
1335
1336 void User::WriteCommon(const std::string &text)
1337 {
1338         try
1339         {
1340                 bool sent_to_at_least_one = false;
1341                 char tb[MAXBUF];
1342
1343                 if (this->registered != REG_ALL)
1344                         return;
1345
1346                 uniq_id++;
1347
1348                 /* We dont want to be doing this n times, just once */
1349                 snprintf(tb,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());
1350                 std::string out = tb;
1351
1352                 for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)
1353                 {
1354                         CUList* ulist = v->first->GetUsers();
1355                         for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1356                         {
1357                                 if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))
1358                                 {
1359                                         already_sent[i->first->fd] = uniq_id;
1360                                         i->first->Write(out);
1361                                         sent_to_at_least_one = true;
1362                                 }
1363                         }
1364                 }
1365
1366                 /*
1367                  * if the user was not in any channels, no users will receive the text. Make sure the user
1368                  * receives their OWN message for WriteCommon
1369                  */
1370                 if (!sent_to_at_least_one)
1371                 {
1372                         this->Write(std::string(tb));
1373                 }
1374         }
1375
1376         catch (...)
1377         {
1378                 ServerInstance->Log(DEBUG,"Exception in User::WriteCommon()");
1379         }
1380 }
1381
1382
1383 /* write a formatted string to all users who share at least one common
1384  * channel, NOT including the source user e.g. for use in QUIT
1385  */
1386
1387 void User::WriteCommonExcept(const char* text, ...)
1388 {
1389         char textbuffer[MAXBUF];
1390         va_list argsPtr;
1391
1392         va_start(argsPtr, text);
1393         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1394         va_end(argsPtr);
1395
1396         this->WriteCommonExcept(std::string(textbuffer));
1397 }
1398
1399 void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
1400 {
1401         char tb1[MAXBUF];
1402         char tb2[MAXBUF];
1403
1404         if (this->registered != REG_ALL)
1405                 return;
1406
1407         uniq_id++;
1408         snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost(),normal_text.c_str());
1409         snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost(),oper_text.c_str());
1410         std::string out1 = tb1;
1411         std::string out2 = tb2;
1412
1413         for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)
1414         {
1415                 CUList *ulist = v->first->GetUsers();
1416                 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1417                 {
1418                         if (this != i->first)
1419                         {
1420                                 if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))
1421                                 {
1422                                         already_sent[i->first->fd] = uniq_id;
1423                                         i->first->Write(IS_OPER(i->first) ? out2 : out1);
1424                                 }
1425                         }
1426                 }
1427         }
1428 }
1429
1430 void User::WriteCommonExcept(const std::string &text)
1431 {
1432         char tb1[MAXBUF];
1433         std::string out1;
1434
1435         if (this->registered != REG_ALL)
1436                 return;
1437
1438         uniq_id++;
1439         snprintf(tb1,MAXBUF,":%s %s",this->GetFullHost(),text.c_str());
1440         out1 = tb1;
1441
1442         for (UCListIter v = this->chans.begin(); v != this->chans.end(); v++)
1443         {
1444                 CUList *ulist = v->first->GetUsers();
1445                 for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
1446                 {
1447                         if (this != i->first)
1448                         {
1449                                 if ((IS_LOCAL(i->first)) && (already_sent[i->first->fd] != uniq_id))
1450                                 {
1451                                         already_sent[i->first->fd] = uniq_id;
1452                                         i->first->Write(out1);
1453                                 }
1454                         }
1455                 }
1456         }
1457
1458 }
1459
1460 void User::WriteWallOps(const std::string &text)
1461 {
1462         if (!IS_OPER(this) && IS_LOCAL(this))
1463                 return;
1464
1465         std::string wallop("WALLOPS :");
1466         wallop.append(text);
1467
1468         for (std::vector<User*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
1469         {
1470                 User* t = *i;
1471                 if (t->IsModeSet('w'))
1472                         this->WriteTo(t,wallop);
1473         }
1474 }
1475
1476 void User::WriteWallOps(const char* text, ...)
1477 {
1478         char textbuffer[MAXBUF];
1479         va_list argsPtr;
1480
1481         va_start(argsPtr, text);
1482         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1483         va_end(argsPtr);
1484
1485         this->WriteWallOps(std::string(textbuffer));
1486 }
1487
1488 /* return 0 or 1 depending if users u and u2 share one or more common channels
1489  * (used by QUIT, NICK etc which arent channel specific notices)
1490  *
1491  * The old algorithm in 1.0 for this was relatively inefficient, iterating over
1492  * the first users channels then the second users channels within the outer loop,
1493  * therefore it was a maximum of x*y iterations (upon returning 0 and checking
1494  * all possible iterations). However this new function instead checks against the
1495  * channel's userlist in the inner loop which is a std::map<User*,User*>
1496  * and saves us time as we already know what pointer value we are after.
1497  * Don't quote me on the maths as i am not a mathematician or computer scientist,
1498  * but i believe this algorithm is now x+(log y) maximum iterations instead.
1499  */
1500 bool User::SharesChannelWith(User *other)
1501 {
1502         if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))
1503                 return false;
1504
1505         /* Outer loop */
1506         for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1507         {
1508                 /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
1509                  * by replacing it with a map::find which *should* be more efficient
1510                  */
1511                 if (i->first->HasUser(other))
1512                         return true;
1513         }
1514         return false;
1515 }
1516
1517 bool User::ChangeName(const char* gecos)
1518 {
1519         if (!strcmp(gecos, this->fullname))
1520                 return true;
1521
1522         if (IS_LOCAL(this))
1523         {
1524                 int MOD_RESULT = 0;
1525                 FOREACH_RESULT(I_OnChangeLocalUserGECOS,OnChangeLocalUserGECOS(this,gecos));
1526                 if (MOD_RESULT)
1527                         return false;
1528                 FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));
1529         }
1530         strlcpy(this->fullname,gecos,MAXGECOS+1);
1531
1532         return true;
1533 }
1534
1535 bool User::ChangeDisplayedHost(const char* host)
1536 {
1537         if (!strcmp(host, this->dhost))
1538                 return true;
1539
1540         if (IS_LOCAL(this))
1541         {
1542                 int MOD_RESULT = 0;
1543                 FOREACH_RESULT(I_OnChangeLocalUserHost,OnChangeLocalUserHost(this,host));
1544                 if (MOD_RESULT)
1545                         return false;
1546                 FOREACH_MOD(I_OnChangeHost,OnChangeHost(this,host));
1547         }
1548         if (this->ServerInstance->Config->CycleHosts)
1549                 this->WriteCommonExcept("QUIT :Changing hosts");
1550
1551         /* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */
1552         strlcpy(this->dhost,host,64);
1553
1554         this->InvalidateCache();
1555
1556         if (this->ServerInstance->Config->CycleHosts)
1557         {
1558                 for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1559                 {
1560                         i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);
1561                         std::string n = this->ServerInstance->Modes->ModeString(this, i->first);
1562                         if (n.length() > 0)
1563                                 i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());
1564                 }
1565         }
1566
1567         if (IS_LOCAL(this))
1568                 this->WriteServ("396 %s %s :is now your displayed host",this->nick,this->dhost);
1569
1570         return true;
1571 }
1572
1573 bool User::ChangeIdent(const char* newident)
1574 {
1575         if (!strcmp(newident, this->ident))
1576                 return true;
1577
1578         if (this->ServerInstance->Config->CycleHosts)
1579                 this->WriteCommonExcept("%s","QUIT :Changing ident");
1580
1581         strlcpy(this->ident, newident, IDENTMAX+2);
1582
1583         this->InvalidateCache();
1584
1585         if (this->ServerInstance->Config->CycleHosts)
1586         {
1587                 for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1588                 {
1589                         i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);
1590                         std::string n = this->ServerInstance->Modes->ModeString(this, i->first);
1591                         if (n.length() > 0)
1592                                 i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());
1593                 }
1594         }
1595
1596         return true;
1597 }
1598
1599 void User::SendAll(const char* command, char* text, ...)
1600 {
1601         char textbuffer[MAXBUF];
1602         char formatbuffer[MAXBUF];
1603         va_list argsPtr;
1604
1605         va_start(argsPtr, text);
1606         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1607         va_end(argsPtr);
1608
1609         snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost(), command, textbuffer);
1610         std::string fmt = formatbuffer;
1611
1612         for (std::vector<User*>::const_iterator i = ServerInstance->local_users.begin(); i != ServerInstance->local_users.end(); i++)
1613         {
1614                 (*i)->Write(fmt);
1615         }
1616 }
1617
1618
1619 std::string User::ChannelList(User* source)
1620 {
1621         try
1622         {
1623                 std::string list;
1624                 for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1625                 {
1626                         /* If the target is the same as the sender, let them see all their channels.
1627                          * If the channel is NOT private/secret OR the user shares a common channel
1628                          * If the user is an oper, and the <options:operspywhois> option is set.
1629                          */
1630                         if ((source == this) || (IS_OPER(source) && ServerInstance->Config->OperSpyWhois) || (((!i->first->IsModeSet('p')) && (!i->first->IsModeSet('s'))) || (i->first->HasUser(source))))
1631                         {
1632                                 list.append(i->first->GetPrefixChar(this)).append(i->first->name).append(" ");
1633                         }
1634                 }
1635                 return list;
1636         }
1637         catch (...)
1638         {
1639                 ServerInstance->Log(DEBUG,"Exception in User::ChannelList()");
1640                 return "";
1641         }
1642 }
1643
1644 void User::SplitChanList(User* dest, const std::string &cl)
1645 {
1646         std::string line;
1647         std::ostringstream prefix;
1648         std::string::size_type start, pos, length;
1649
1650         try
1651         {
1652                 prefix << this->nick << " " << dest->nick << " :";
1653                 line = prefix.str();
1654                 int namelen = strlen(ServerInstance->Config->ServerName) + 6;
1655
1656                 for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
1657                 {
1658                         length = (pos == std::string::npos) ? cl.length() : pos;
1659
1660                         if (line.length() + namelen + length - start > 510)
1661                         {
1662                                 ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
1663                                 line = prefix.str();
1664                         }
1665
1666                         if(pos == std::string::npos)
1667                         {
1668                                 line.append(cl.substr(start, length - start));
1669                                 break;
1670                         }
1671                         else
1672                         {
1673                                 line.append(cl.substr(start, length - start + 1));
1674                         }
1675                 }
1676
1677                 if (line.length())
1678                 {
1679                         ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
1680                 }
1681         }
1682
1683         catch (...)
1684         {
1685                 ServerInstance->Log(DEBUG,"Exception in User::SplitChanList()");
1686         }
1687 }
1688
1689 unsigned int User::GetMaxChans()
1690 {
1691         return this->MaxChans;
1692 }
1693
1694 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1695  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1696  * then their ip will be taken as 'priority' anyway, so for example,
1697  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1698  */
1699 ConnectClass* User::GetClass(const std::string &explicit_name)
1700 {
1701         if (!explicit_name.empty())
1702         {
1703                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1704                 {
1705                         if (explicit_name == i->GetName())
1706                                 return &(*i);
1707                 }
1708         }
1709         else
1710         {
1711                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1712                 {
1713                         if (((match(this->GetIPString(),i->GetHost().c_str(),true)) || (match(this->host,i->GetHost().c_str()))))
1714                         {
1715                                 if (i->GetPort())
1716                                 {
1717                                         if (this->GetPort() == i->GetPort())
1718                                                 return &(*i);
1719                                         else
1720                                                 continue;
1721                                 }
1722                                 else
1723                                         return &(*i);
1724                         }
1725                 }
1726         }
1727         return NULL;
1728 }
1729
1730 void User::PurgeEmptyChannels()
1731 {
1732         std::vector<Channel*> to_delete;
1733
1734         // firstly decrement the count on each channel
1735         for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
1736         {
1737                 f->first->RemoveAllPrefixes(this);
1738                 if (f->first->DelUser(this) == 0)
1739                 {
1740                         /* No users left in here, mark it for deletion */
1741                         try
1742                         {
1743                                 to_delete.push_back(f->first);
1744                         }
1745                         catch (...)
1746                         {
1747                                 ServerInstance->Log(DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()");
1748                         }
1749                 }
1750         }
1751
1752         for (std::vector<Channel*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
1753         {
1754                 Channel* thischan = *n;
1755                 chan_hash::iterator i2 = ServerInstance->chanlist->find(thischan->name);
1756                 if (i2 != ServerInstance->chanlist->end())
1757                 {
1758                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
1759                         DELETE(i2->second);
1760                         ServerInstance->chanlist->erase(i2);
1761                         this->chans.erase(*n);
1762                 }
1763         }
1764
1765         this->UnOper();
1766 }
1767
1768 void User::ShowMOTD()
1769 {
1770         if (!ServerInstance->Config->MOTD.size())
1771         {
1772                 this->WriteServ("422 %s :Message of the day file is missing.",this->nick);
1773                 return;
1774         }
1775         this->WriteServ("375 %s :%s message of the day", this->nick, ServerInstance->Config->ServerName);
1776
1777         for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++)
1778                 this->WriteServ("372 %s :- %s",this->nick,i->c_str());
1779
1780         this->WriteServ("376 %s :End of message of the day.", this->nick);
1781 }
1782
1783 void User::ShowRULES()
1784 {
1785         if (!ServerInstance->Config->RULES.size())
1786         {
1787                 this->WriteServ("434 %s :RULES File is missing",this->nick);
1788                 return;
1789         }
1790
1791         this->WriteServ("308 %s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName);
1792
1793         for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++)
1794                 this->WriteServ("232 %s :- %s",this->nick,i->c_str());
1795
1796         this->WriteServ("309 %s :End of RULES command.",this->nick);
1797 }
1798
1799 void User::HandleEvent(EventType et, int errornum)
1800 {
1801         /* WARNING: May delete this user! */
1802         int thisfd = this->GetFd();
1803
1804         try
1805         {
1806                 switch (et)
1807                 {
1808                         case EVENT_READ:
1809                                 ServerInstance->ProcessUser(this);
1810                         break;
1811                         case EVENT_WRITE:
1812                                 this->FlushWriteBuf();
1813                         break;
1814                         case EVENT_ERROR:
1815                                 /** This should be safe, but dont DARE do anything after it -- Brain */
1816                                 this->SetWriteError(errornum ? strerror(errornum) : "EOF from client");
1817                         break;
1818                 }
1819         }
1820         catch (...)
1821         {
1822                 ServerInstance->Log(DEBUG,"Exception in User::HandleEvent intercepted");
1823         }
1824
1825         /* If the user has raised an error whilst being processed, quit them now we're safe to */
1826         if ((ServerInstance->SE->GetRef(thisfd) == this))
1827         {
1828                 if (!WriteError.empty())
1829                 {
1830                         User::QuitUser(ServerInstance, this, GetWriteError());
1831                 }
1832         }
1833 }
1834
1835 void User::SetOperQuit(const std::string &oquit)
1836 {
1837         if (operquit)
1838                 return;
1839
1840         operquit = strdup(oquit.c_str());
1841 }
1842
1843 const char* User::GetOperQuit()
1844 {
1845         return operquit ? operquit : "";
1846 }
1847
1848 VisData::VisData()
1849 {
1850 }
1851
1852 VisData::~VisData()
1853 {
1854 }
1855
1856 bool VisData::VisibleTo(User* user)
1857 {
1858         return true;
1859 }
1860