]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/users.cpp
4b668697779c5be9034be6d9dc2fc903bd5c1183
[user/henk/code/inspircd.git] / src / users.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/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 "xline.h"
18 #include "bancache.h"
19 #include "commands/cmd_whowas.h"
20
21 typedef unsigned int uniq_id_t;
22 class sent
23 {
24         uniq_id_t uniq_id;
25         uniq_id_t* array;
26         void init()
27         {
28                 if (!array)
29                         array = new uniq_id_t[ServerInstance->SE->GetMaxFds()];
30                 memset(array, 0, ServerInstance->SE->GetMaxFds() * sizeof(uniq_id_t));
31                 uniq_id++;
32         }
33  public:
34         sent() : uniq_id(static_cast<uniq_id_t>(-1)), array(NULL) {}
35         inline uniq_id_t operator++()
36         {
37                 if (++uniq_id == 0)
38                         init();
39                 return uniq_id;
40         }
41         inline uniq_id_t& operator[](int i)
42         {
43                 return array[i];
44         }
45         ~sent()
46         {
47                 delete array;
48         }
49 };
50
51 static sent already_sent;
52
53 std::string User::ProcessNoticeMasks(const char *sm)
54 {
55         bool adding = true, oldadding = false;
56         const char *c = sm;
57         std::string output;
58
59         while (c && *c)
60         {
61                 switch (*c)
62                 {
63                         case '+':
64                                 adding = true;
65                         break;
66                         case '-':
67                                 adding = false;
68                         break;
69                         case '*':
70                                 for (unsigned char d = 'A'; d <= 'z'; d++)
71                                 {
72                                         if (ServerInstance->SNO->IsEnabled(d))
73                                         {
74                                                 if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))
75                                                 {
76                                                         if ((oldadding != adding) || (!output.length()))
77                                                                 output += (adding ? '+' : '-');
78
79                                                         this->SetNoticeMask(d, adding);
80
81                                                         output += d;
82                                                 }
83                                         }
84                                         oldadding = adding;
85                                 }
86                         break;
87                         default:
88                                 if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c)))
89                                 {
90                                         if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding))
91                                         {
92                                                 if ((oldadding != adding) || (!output.length()))
93                                                         output += (adding ? '+' : '-');
94
95                                                 this->SetNoticeMask(*c, adding);
96
97                                                 output += *c;
98                                         }
99                                 }
100                                 else
101                                         this->WriteNumeric(ERR_UNKNOWNSNOMASK, "%s %c :is unknown snomask char to me", this->nick.c_str(), *c);
102
103                                 oldadding = adding;
104                         break;
105                 }
106
107                 *c++;
108         }
109
110         std::string s = this->FormatNoticeMasks();
111         if (s.length() == 0)
112         {
113                 this->modes[UM_SNOMASK] = false;
114         }
115
116         return output;
117 }
118
119 void User::StartDNSLookup()
120 {
121         try
122         {
123                 bool cached = false;
124                 const char* sip = this->GetIPString();
125                 UserResolver *res_reverse;
126
127                 QueryType resolvtype = this->client_sa.sa.sa_family == AF_INET6 ? DNS_QUERY_PTR6 : DNS_QUERY_PTR4;
128                 res_reverse = new UserResolver(this, sip, resolvtype, cached);
129
130                 ServerInstance->AddResolver(res_reverse, cached);
131         }
132         catch (CoreException& e)
133         {
134                 ServerInstance->Logs->Log("USERS", DEBUG,"Error in resolver: %s",e.GetReason());
135         }
136 }
137
138 bool User::IsNoticeMaskSet(unsigned char sm)
139 {
140         if (!isalpha(sm))
141                 return false;
142         return (snomasks[sm-65]);
143 }
144
145 void User::SetNoticeMask(unsigned char sm, bool value)
146 {
147         if (!isalpha(sm))
148                 return;
149         snomasks[sm-65] = value;
150 }
151
152 const char* User::FormatNoticeMasks()
153 {
154         static char data[MAXBUF];
155         int offset = 0;
156
157         for (int n = 0; n < 64; n++)
158         {
159                 if (snomasks[n])
160                         data[offset++] = n+65;
161         }
162
163         data[offset] = 0;
164         return data;
165 }
166
167 bool User::IsModeSet(unsigned char m)
168 {
169         if (!isalpha(m))
170                 return false;
171         return (modes[m-65]);
172 }
173
174 void User::SetMode(unsigned char m, bool value)
175 {
176         if (!isalpha(m))
177                 return;
178         modes[m-65] = value;
179 }
180
181 const char* User::FormatModes(bool showparameters)
182 {
183         static char data[MAXBUF];
184         std::string params;
185         int offset = 0;
186
187         for (unsigned char n = 0; n < 64; n++)
188         {
189                 if (modes[n])
190                 {
191                         data[offset++] = n + 65;
192                         ModeHandler* mh = ServerInstance->Modes->FindMode(n + 65, MODETYPE_USER);
193                         if (showparameters && mh && mh->GetNumParams(true))
194                         {
195                                 std::string p = mh->GetUserParameter(this);
196                                 if (p.length())
197                                         params.append(" ").append(p);
198                         }
199                 }
200         }
201         data[offset] = 0;
202         strlcat(data, params.c_str(), MAXBUF);
203         return data;
204 }
205
206 void User::DecrementModes()
207 {
208         ServerInstance->Logs->Log("USERS", DEBUG, "DecrementModes()");
209         for (unsigned char n = 'A'; n <= 'z'; n++)
210         {
211                 if (modes[n-65])
212                 {
213                         ServerInstance->Logs->Log("USERS", DEBUG,"DecrementModes() found mode %c", n);
214                         ModeHandler* mh = ServerInstance->Modes->FindMode(n, MODETYPE_USER);
215                         if (mh)
216                         {
217                                 ServerInstance->Logs->Log("USERS", DEBUG,"Found handler %c and call ChangeCount", n);
218                                 mh->ChangeCount(-1);
219                         }
220                 }
221         }
222 }
223
224 User::User(const std::string &uid)
225 {
226         server = ServerInstance->Config->ServerName;
227         age = ServerInstance->Time();
228         Penalty = 0;
229         lastping = signon = idle_lastmsg = nping = registered = 0;
230         bytes_in = bytes_out = cmds_in = cmds_out = 0;
231         quietquit = quitting = exempt = haspassed = dns_done = false;
232         fd = -1;
233         server_sa.sa.sa_family = AF_UNSPEC;
234         client_sa.sa.sa_family = AF_UNSPEC;
235         MyClass = NULL;
236         AllowedPrivs = AllowedOperCommands = NULL;
237
238         if (uid.empty())
239                 uuid.assign(ServerInstance->GetUID(), 0, UUID_LENGTH - 1);
240         else
241                 uuid.assign(uid, 0, UUID_LENGTH - 1);
242
243         ServerInstance->Logs->Log("USERS", DEBUG,"New UUID for user: %s (%s)", uuid.c_str(), uid.empty() ? "allocated new" : "used remote");
244
245         user_hash::iterator finduuid = ServerInstance->Users->uuidlist->find(uuid);
246         if (finduuid == ServerInstance->Users->uuidlist->end())
247                 (*ServerInstance->Users->uuidlist)[uuid] = this;
248         else
249                 throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor");
250 }
251
252 User::~User()
253 {
254         if (uuid.length())
255                 ServerInstance->Logs->Log("USERS", ERROR, "User destructor for %s called without cull", uuid.c_str());
256 }
257
258 const std::string& User::MakeHost()
259 {
260         if (!this->cached_makehost.empty())
261                 return this->cached_makehost;
262
263         char nhost[MAXBUF];
264         /* This is much faster than snprintf */
265         char* t = nhost;
266         for(const char* n = ident.c_str(); *n; n++)
267                 *t++ = *n;
268         *t++ = '@';
269         for(const char* n = host.c_str(); *n; n++)
270                 *t++ = *n;
271         *t = 0;
272
273         this->cached_makehost.assign(nhost);
274
275         return this->cached_makehost;
276 }
277
278 const std::string& User::MakeHostIP()
279 {
280         if (!this->cached_hostip.empty())
281                 return this->cached_hostip;
282
283         char ihost[MAXBUF];
284         /* This is much faster than snprintf */
285         char* t = ihost;
286         for(const char* n = ident.c_str(); *n; n++)
287                 *t++ = *n;
288         *t++ = '@';
289         for(const char* n = this->GetIPString(); *n; n++)
290                 *t++ = *n;
291         *t = 0;
292
293         this->cached_hostip = ihost;
294
295         return this->cached_hostip;
296 }
297
298 const std::string User::GetFullHost()
299 {
300         if (!this->cached_fullhost.empty())
301                 return this->cached_fullhost;
302
303         char result[MAXBUF];
304         char* t = result;
305         for(const char* n = nick.c_str(); *n; n++)
306                 *t++ = *n;
307         *t++ = '!';
308         for(const char* n = ident.c_str(); *n; n++)
309                 *t++ = *n;
310         *t++ = '@';
311         for(const char* n = dhost.c_str(); *n; n++)
312                 *t++ = *n;
313         *t = 0;
314
315         this->cached_fullhost = result;
316
317         return this->cached_fullhost;
318 }
319
320 char* User::MakeWildHost()
321 {
322         static char nresult[MAXBUF];
323         char* t = nresult;
324         *t++ = '*';     *t++ = '!';
325         *t++ = '*';     *t++ = '@';
326         for(const char* n = dhost.c_str(); *n; n++)
327                 *t++ = *n;
328         *t = 0;
329         return nresult;
330 }
331
332 const std::string User::GetFullRealHost()
333 {
334         if (!this->cached_fullrealhost.empty())
335                 return this->cached_fullrealhost;
336
337         char fresult[MAXBUF];
338         char* t = fresult;
339         for(const char* n = nick.c_str(); *n; n++)
340                 *t++ = *n;
341         *t++ = '!';
342         for(const char* n = ident.c_str(); *n; n++)
343                 *t++ = *n;
344         *t++ = '@';
345         for(const char* n = host.c_str(); *n; n++)
346                 *t++ = *n;
347         *t = 0;
348
349         this->cached_fullrealhost = fresult;
350
351         return this->cached_fullrealhost;
352 }
353
354 bool User::IsInvited(const irc::string &channel)
355 {
356         time_t now = ServerInstance->Time();
357         InvitedList::iterator safei;
358         for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
359         {
360                 if (channel == i->first)
361                 {
362                         if (i->second != 0 && now > i->second)
363                         {
364                                 /* Expired invite, remove it. */
365                                 safei = i;
366                                 --i;
367                                 invites.erase(safei);
368                                 continue;
369                         }
370                         return true;
371                 }
372         }
373         return false;
374 }
375
376 InvitedList* User::GetInviteList()
377 {
378         time_t now = ServerInstance->Time();
379         /* Weed out expired invites here. */
380         InvitedList::iterator safei;
381         for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
382         {
383                 if (i->second != 0 && now > i->second)
384                 {
385                         /* Expired invite, remove it. */
386                         safei = i;
387                         --i;
388                         invites.erase(safei);
389                 }
390         }
391         return &invites;
392 }
393
394 void User::InviteTo(const irc::string &channel, time_t invtimeout)
395 {
396         time_t now = ServerInstance->Time();
397         if (invtimeout != 0 && now > invtimeout) return; /* Don't add invites that are expired from the get-go. */
398         for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
399         {
400                 if (channel == i->first)
401                 {
402                         if (i->second != 0 && invtimeout > i->second)
403                         {
404                                 i->second = invtimeout;
405                         }
406
407                         return;
408                 }
409         }
410         invites.push_back(std::make_pair(channel, invtimeout));
411 }
412
413 void User::RemoveInvite(const irc::string &channel)
414 {
415         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
416         {
417                 if (channel == i->first)
418                 {
419                         invites.erase(i);
420                         return;
421                 }
422         }
423 }
424
425 bool User::HasModePermission(unsigned char mode, ModeType type)
426 {
427         if (!IS_LOCAL(this))
428                 return true;
429
430         if (!IS_OPER(this))
431                 return false;
432
433         if (mode < 'A' || mode > ('A' + 64)) return false;
434
435         return ((type == MODETYPE_USER ? AllowedUserModes : AllowedChanModes))[(mode - 'A')];
436
437 }
438
439 bool User::HasPermission(const std::string &command)
440 {
441         /*
442          * users on remote servers can completely bypass all permissions based checks.
443          * This prevents desyncs when one server has different type/class tags to another.
444          * That having been said, this does open things up to the possibility of source changes
445          * allowing remote kills, etc - but if they have access to the src, they most likely have
446          * access to the conf - so it's an end to a means either way.
447          */
448         if (!IS_LOCAL(this))
449                 return true;
450
451         // are they even an oper at all?
452         if (!IS_OPER(this))
453         {
454                 return false;
455         }
456
457         if (!AllowedOperCommands)
458                 return false;
459
460         if (AllowedOperCommands->find(command) != AllowedOperCommands->end())
461                 return true;
462         else if (AllowedOperCommands->find("*") != AllowedOperCommands->end())
463                 return true;
464
465         return false;
466 }
467
468
469 bool User::HasPrivPermission(const std::string &privstr, bool noisy)
470 {
471         if (!IS_LOCAL(this))
472         {
473                 ServerInstance->Logs->Log("PRIVS", DEBUG, "Remote (yes)");
474                 return true;
475         }
476
477         if (!IS_OPER(this))
478         {
479                 if (noisy)
480                         this->WriteServ("NOTICE %s :You are not an oper", this->nick.c_str());
481                 return false;
482         }
483
484         if (!AllowedPrivs)
485         {
486                 if (noisy)
487                         this->WriteServ("NOTICE %s :Privset empty(!?)", this->nick.c_str());
488                 return false;
489         }
490
491         if (AllowedPrivs->find(privstr) != AllowedPrivs->end())
492         {
493                 return true;
494         }
495         else if (AllowedPrivs->find("*") != AllowedPrivs->end())
496         {
497                 return true;
498         }
499
500         if (noisy)
501                 this->WriteServ("NOTICE %s :Oper type %s does not have access to priv %s", this->nick.c_str(), this->oper.c_str(), privstr.c_str());
502         return false;
503 }
504
505 void User::OnDataReady()
506 {
507         if (quitting)
508                 return;
509
510         if (MyClass && recvq.length() > MyClass->GetRecvqMax() && !HasPrivPermission("users/flood/increased-buffers"))
511         {
512                 ServerInstance->Users->QuitUser(this, "RecvQ exceeded");
513                 ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu",
514                         nick.c_str(), (unsigned long)recvq.length(), MyClass->GetRecvqMax());
515         }
516         unsigned long sendqmax = ULONG_MAX;
517         if (MyClass && !HasPrivPermission("users/flood/increased-buffers"))
518                 sendqmax = MyClass->GetSendqSoftMax();
519
520         while (Penalty < 10 && getSendQSize() < sendqmax)
521         {
522                 std::string line;
523                 line.reserve(MAXBUF);
524                 std::string::size_type qpos = 0;
525                 while (qpos < recvq.length())
526                 {
527                         char c = recvq[qpos++];
528                         switch (c)
529                         {
530                         case '\0':
531                                 c = ' ';
532                                 break;
533                         case '\r':
534                                 continue;
535                         case '\n':
536                                 goto eol_found;
537                         }
538                         if (line.length() < MAXBUF - 2)
539                                 line.push_back(c);
540                 }
541                 // if we got here, the recvq ran out before we found a newline
542                 return;
543 eol_found:
544                 // just found a newline. Terminate the string, and pull it out of recvq
545                 recvq = recvq.substr(qpos);
546
547                 // TODO should this be moved to when it was inserted in recvq?
548                 ServerInstance->stats->statsRecv += qpos;
549                 this->bytes_in += qpos;
550                 this->cmds_in++;
551
552                 ServerInstance->Parser->ProcessBuffer(line, this);
553         }
554         // Add pseudo-penalty so that we continue processing after sendq recedes
555         if (Penalty == 0 && getSendQSize() >= sendqmax)
556                 Penalty++;
557 }
558
559 void User::AddWriteBuf(const std::string &data)
560 {
561         // Don't bother sending text to remote users!
562         if (IS_REMOTE(this))
563                 return;
564         if (!quitting && MyClass && getSendQSize() + data.length() > MyClass->GetSendqHardMax() && !HasPrivPermission("users/flood/increased-buffers"))
565         {
566                 /*
567                  * Quit the user FIRST, because otherwise we could recurse
568                  * here and hit the same limit.
569                  */
570                 ServerInstance->Users->QuitUser(this, "SendQ exceeded");
571                 ServerInstance->SNO->WriteToSnoMask('a', "User %s SendQ exceeds connect class maximum of %lu",
572                         nick.c_str(), MyClass->GetSendqHardMax());
573                 return;
574         }
575
576         // We still want to append data to the sendq of a quitting user,
577         // e.g. their ERROR message that says 'closing link'
578
579         WriteData(data);
580 }
581
582 void User::OnError(BufferedSocketError)
583 {
584         ServerInstance->Users->QuitUser(this, getError());
585 }
586
587 bool User::cull()
588 {
589         if (!quitting)
590                 ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
591         if (uuid.empty())
592         {
593                 ServerInstance->Logs->Log("USERS", DEBUG, "User culled twice? UUID empty");
594                 return true;
595         }
596         PurgeEmptyChannels();
597         if (IS_LOCAL(this))
598         {
599                 if (fd != INT_MAX)
600                         Close();
601
602                 std::vector<User*>::iterator x = find(ServerInstance->Users->local_users.begin(),ServerInstance->Users->local_users.end(),this);
603                 if (x != ServerInstance->Users->local_users.end())
604                         ServerInstance->Users->local_users.erase(x);
605                 else
606                         ServerInstance->Logs->Log("USERS", DEBUG, "Failed to remove user from vector");
607         }
608
609         if (this->AllowedOperCommands)
610         {
611                 delete AllowedOperCommands;
612                 AllowedOperCommands = NULL;
613         }
614
615         if (this->AllowedPrivs)
616         {
617                 delete AllowedPrivs;
618                 AllowedPrivs = NULL;
619         }
620
621         this->InvalidateCache();
622         this->DecrementModes();
623
624         if (client_sa.sa.sa_family != AF_UNSPEC)
625                 ServerInstance->Users->RemoveCloneCounts(this);
626
627         ServerInstance->Users->uuidlist->erase(uuid);
628         uuid.clear();
629         return true;
630 }
631
632 void User::Oper(const std::string &opertype, const std::string &opername)
633 {
634         if (this->IsModeSet('o'))
635                 this->UnOper();
636
637         this->modes[UM_OPERATOR] = 1;
638         this->WriteServ("MODE %s :+o", this->nick.c_str());
639         FOREACH_MOD(I_OnOper, OnOper(this, opertype));
640
641         ServerInstance->SNO->WriteToSnoMask('o',"%s (%s@%s) is now an IRC operator of type %s (using oper '%s')", this->nick.c_str(), this->ident.c_str(), this->host.c_str(), irc::Spacify(opertype.c_str()), opername.c_str());
642         this->WriteNumeric(381, "%s :You are now %s %s", this->nick.c_str(), strchr("aeiouAEIOU", *opertype.c_str()) ? "an" : "a", irc::Spacify(opertype.c_str()));
643
644         ServerInstance->Logs->Log("OPER", DEFAULT, "%s!%s@%s opered as type: %s", this->nick.c_str(), this->ident.c_str(), this->host.c_str(), opertype.c_str());
645         this->oper.assign(opertype, 0, 512);
646         ServerInstance->Users->all_opers.push_back(this);
647
648         /*
649          * This might look like it's in the wrong place.
650          * It is *not*!
651          *
652          * For multi-network servers, we may not have the opertypes of the remote server, but we still want to mark the user as an oper of that type.
653          * -- w00t
654          */
655         TagIndex::iterator iter_opertype = ServerInstance->Config->opertypes.find(this->oper.c_str());
656         if (iter_opertype != ServerInstance->Config->opertypes.end())
657         {
658                 if (AllowedOperCommands)
659                         AllowedOperCommands->clear();
660                 else
661                         AllowedOperCommands = new std::set<std::string>;
662
663                 if (AllowedPrivs)
664                         AllowedPrivs->clear();
665                 else
666                         AllowedPrivs = new std::set<std::string>;
667
668                 AllowedUserModes.reset();
669                 AllowedChanModes.reset();
670                 this->AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want.
671
672                 std::string myclass, mycmd, mypriv;
673                 irc::spacesepstream Classes(iter_opertype->second->getString("classes"));
674                 while (Classes.GetToken(myclass))
675                 {
676                         TagIndex::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass.c_str());
677                         if (iter_operclass != ServerInstance->Config->operclass.end())
678                         {
679                                 /* Process commands */
680                                 irc::spacesepstream CommandList(iter_operclass->second->getString("commands"));
681                                 while (CommandList.GetToken(mycmd))
682                                 {
683                                         this->AllowedOperCommands->insert(mycmd);
684                                 }
685
686                                 irc::spacesepstream PrivList(iter_operclass->second->getString("privs"));
687                                 while (PrivList.GetToken(mypriv))
688                                 {
689                                         this->AllowedPrivs->insert(mypriv);
690                                 }
691
692                                 for (unsigned char* c = (unsigned char*)iter_operclass->second->getString("usermodes").c_str(); *c; ++c)
693                                 {
694                                         if (*c == '*')
695                                         {
696                                                 this->AllowedUserModes.set();
697                                         }
698                                         else
699                                         {
700                                                 this->AllowedUserModes[*c - 'A'] = true;
701                                         }
702                                 }
703
704                                 for (unsigned char* c = (unsigned char*)iter_operclass->second->getString("chanmodes").c_str(); *c; ++c)
705                                 {
706                                         if (*c == '*')
707                                         {
708                                                 this->AllowedChanModes.set();
709                                         }
710                                         else
711                                         {
712                                                 this->AllowedChanModes[*c - 'A'] = true;
713                                         }
714                                 }
715                         }
716                 }
717         }
718
719         FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype, opername));
720 }
721
722 void User::UnOper()
723 {
724         if (IS_OPER(this))
725         {
726                 /*
727                  * unset their oper type (what IS_OPER checks).
728                  * note, order is important - this must come before modes as -o attempts
729                  * to call UnOper. -- w00t
730                  */
731                 this->oper.clear();
732
733
734                 /* Remove all oper only modes from the user when the deoper - Bug #466*/
735                 std::string moderemove("-");
736
737                 for (unsigned char letter = 'A'; letter <= 'z'; letter++)
738                 {
739                         ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER);
740                         if (mh && mh->NeedsOper())
741                                 moderemove += letter;
742                 }
743
744
745                 std::vector<std::string> parameters;
746                 parameters.push_back(this->nick);
747                 parameters.push_back(moderemove);
748
749                 ServerInstance->Parser->CallHandler("MODE", parameters, this);
750
751                 /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
752                 ServerInstance->Users->all_opers.remove(this);
753
754                 if (AllowedOperCommands)
755                 {
756                         delete AllowedOperCommands;
757                         AllowedOperCommands = NULL;
758                 }
759
760                 if (AllowedPrivs)
761                 {
762                         delete AllowedPrivs;
763                         AllowedPrivs = NULL;
764                 }
765
766                 AllowedUserModes.reset();
767                 AllowedChanModes.reset();
768                 this->modes[UM_OPERATOR] = 0;
769         }
770 }
771
772 /* adds or updates an entry in the whowas list */
773 void User::AddToWhoWas()
774 {
775         Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so");
776         if (whowas)
777         {
778                 WhowasRequest req(NULL, whowas, WhowasRequest::WHOWAS_ADD);
779                 req.user = this;
780                 req.Send();
781         }
782 }
783
784 /*
785  * Check class restrictions
786  */
787 void User::CheckClass()
788 {
789         ConnectClass* a = this->MyClass;
790
791         if ((!a) || (a->type == CC_DENY))
792         {
793                 ServerInstance->Users->QuitUser(this, "Unauthorised connection");
794                 return;
795         }
796         else if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal()))
797         {
798                 ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
799                 ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString());
800                 return;
801         }
802         else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal()))
803         {
804                 ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
805                 ServerInstance->SNO->WriteToSnoMask('a', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString());
806                 return;
807         }
808
809         this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
810 }
811
812 bool User::CheckLines(bool doZline)
813 {
814         const char* check[] = { "G" , "K", (doZline) ? "Z" : NULL, NULL };
815
816         if (!this->exempt)
817         {
818                 for (int n = 0; check[n]; ++n)
819                 {
820                         XLine *r = ServerInstance->XLines->MatchesLine(check[n], this);
821
822                         if (r)
823                         {
824                                 r->Apply(this);
825                                 return true;
826                         }
827                 }
828         }
829
830         return false;
831 }
832
833 void User::FullConnect()
834 {
835         ServerInstance->stats->statsConnects++;
836         this->idle_lastmsg = ServerInstance->Time();
837
838         /*
839          * You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT.
840          * At the time AddClient is called, we don't have a resolved host, by here we probably do - which
841          * may put the user into a totally seperate class with different restrictions! so we *must* check again.
842          * Don't remove this! -- w00t
843          */
844         this->SetClass();
845
846         /* Check the password, if one is required by the user's connect class.
847          * This CANNOT be in CheckClass(), because that is called prior to PASS as well!
848          */
849         if (this->MyClass && !this->MyClass->GetPass().empty() && !this->haspassed)
850         {
851                 ServerInstance->Users->QuitUser(this, "Invalid password");
852                 return;
853         }
854
855         if (this->CheckLines())
856                 return;
857
858         this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network.c_str());
859         this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick.c_str(), ServerInstance->Config->Network.c_str(), this->nick.c_str(), this->ident.c_str(), this->host.c_str());
860         this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version InspIRCd-2.0",this->nick.c_str(),ServerInstance->Config->ServerName.c_str());
861         this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__);
862         this->WriteNumeric(RPL_SERVERVERSION, "%s %s InspIRCd-2.0 %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName.c_str(), ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());
863
864         ServerInstance->Config->Send005(this);
865         this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str());
866
867
868         this->ShowMOTD();
869
870         /* Now registered */
871         if (ServerInstance->Users->unregistered_count)
872                 ServerInstance->Users->unregistered_count--;
873
874         /* Trigger LUSERS output, give modules a chance too */
875         ModResult MOD_RESULT;
876         std::string command("LUSERS");
877         std::vector<std::string> parameters;
878         FIRST_MOD_RESULT(OnPreCommand, MOD_RESULT, (command, parameters, this, true, "LUSERS"));
879         if (!MOD_RESULT)
880                 ServerInstance->CallCommandHandler(command, parameters, this);
881
882         /*
883          * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
884          * for a user that doesn't exist yet.
885          */
886         FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
887
888         this->registered = REG_ALL;
889
890         FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
891
892         ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s] [%s]",
893                 this->GetServerPort(), this->nick.c_str(), this->ident.c_str(), this->host.c_str(), this->GetIPString(), this->fullname.c_str());
894         ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding NEGATIVE hit for %s", this->GetIPString());
895         ServerInstance->BanCache->AddHit(this->GetIPString(), "", "");
896 }
897
898 /** User::UpdateNick()
899  * re-allocates a nick in the user_hash after they change nicknames,
900  * returns a pointer to the new user as it may have moved
901  */
902 User* User::UpdateNickHash(const char* New)
903 {
904         //user_hash::iterator newnick;
905         user_hash::iterator oldnick = ServerInstance->Users->clientlist->find(this->nick);
906
907         if (!irc::string(this->nick.c_str()).compare(New))
908                 return oldnick->second;
909
910         if (oldnick == ServerInstance->Users->clientlist->end())
911                 return NULL; /* doesnt exist */
912
913         User* olduser = oldnick->second;
914         ServerInstance->Users->clientlist->erase(oldnick);
915         (*(ServerInstance->Users->clientlist))[New] = olduser;
916         return olduser;
917 }
918
919 void User::InvalidateCache()
920 {
921         /* Invalidate cache */
922         cached_fullhost.clear();
923         cached_hostip.clear();
924         cached_makehost.clear();
925         cached_fullrealhost.clear();
926 }
927
928 bool User::ForceNickChange(const char* newnick)
929 {
930         ModResult MOD_RESULT;
931
932         this->InvalidateCache();
933
934         ServerInstance->NICKForced.set(this, 1);
935         FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (this, newnick));
936         ServerInstance->NICKForced.set(this, 0);
937
938         if (MOD_RESULT == MOD_RES_DENY)
939         {
940                 ServerInstance->stats->statsCollisions++;
941                 return false;
942         }
943
944         std::deque<classbase*> dummy;
945         Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
946         if (nickhandler) // wtfbbq, when would this not be here
947         {
948                 std::vector<std::string> parameters;
949                 parameters.push_back(newnick);
950                 ServerInstance->NICKForced.set(this, 1);
951                 bool result = (ServerInstance->Parser->CallHandler("NICK", parameters, this) == CMD_SUCCESS);
952                 ServerInstance->NICKForced.set(this, 0);
953                 return result;
954         }
955
956         // Unreachable, we hope
957         return false;
958 }
959
960 int User::GetServerPort()
961 {
962         switch (this->server_sa.sa.sa_family)
963         {
964                 case AF_INET6:
965                         return htons(this->server_sa.in6.sin6_port);
966                 case AF_INET:
967                         return htons(this->server_sa.in4.sin_port);
968         }
969         return 0;
970 }
971
972 const char* User::GetCIDRMask(int range)
973 {
974         static char buf[44];
975
976         if (range < 0)
977                 throw "Negative range, sorry, no.";
978
979         /*
980          * Original code written by Oliver Lupton (Om).
981          * Integrated by me. Thanks. :) -- w00t
982          */
983         switch (this->client_sa.sa.sa_family)
984         {
985                 case AF_INET6:
986                 {
987                         /* unsigned char s6_addr[16]; */
988                         struct in6_addr v6;
989                         int i, bytestozero, extrabits;
990                         char buffer[40];
991
992                         if(range > 128)
993                                 throw "CIDR mask width greater than address width (IPv6, 128 bit)";
994
995                         /* To create the CIDR mask we want to set all the bits after 'range' bits of the address
996                          * to zero. This means the last (128 - range) bits of the address must be set to zero.
997                          * Hence this number divided by 8 is the number of whole bytes from the end of the address
998                          * which must be set to zero.
999                          */
1000                         bytestozero = (128 - range) / 8;
1001
1002                         /* Some of the least significant bits of the next most significant byte may also have to
1003                          * be zeroed. The number of bits is the remainder of the above division.
1004                          */
1005                         extrabits = (128 - range) % 8;
1006
1007                         /* Populate our working struct with the parts of the user's IP which are required in the
1008                          * final CIDR mask. Set all the subsequent bytes to zero.
1009                          * (16 - bytestozero) is the number of bytes which must be populated with actual IP data.
1010                          */
1011                         for(i = 0; i < (16 - bytestozero); i++)
1012                         {
1013                                 v6.s6_addr[i] = client_sa.in6.sin6_addr.s6_addr[i];
1014                         }
1015
1016                         /* And zero all the remaining bytes in the IP. */
1017                         for(; i < 16; i++)
1018                         {
1019                                 v6.s6_addr[i] = 0;
1020                         }
1021
1022                         /* And finally, zero the extra bits required. */
1023                         v6.s6_addr[15 - bytestozero] = (v6.s6_addr[15 - bytestozero] >> extrabits) << extrabits;
1024
1025                         snprintf(buf, 44, "%s/%d", inet_ntop(AF_INET6, &v6, buffer, 40), range);
1026                         return buf;
1027                 }
1028                 break;
1029                 case AF_INET:
1030                 {
1031                         struct in_addr v4;
1032                         char buffer[16];
1033
1034                         if (range > 32)
1035                                 throw "CIDR mask width greater than address width (IPv4, 32 bit)";
1036
1037                         /* Users already have a sockaddr* pointer (User::ip) which contains either a v4 or v6 structure */
1038                         v4.s_addr = client_sa.in4.sin_addr.s_addr;
1039
1040                         /* To create the CIDR mask we want to set all the bits after 'range' bits of the address
1041                          * to zero. This means the last (32 - range) bits of the address must be set to zero.
1042                          * This is done by shifting the value right and then back left by (32 - range) bits.
1043                          */
1044                         if(range > 0)
1045                         {
1046                                 v4.s_addr = ntohl(v4.s_addr);
1047                                 v4.s_addr = (v4.s_addr >> (32 - range)) << (32 - range);
1048                                 v4.s_addr = htonl(v4.s_addr);
1049                         }
1050                         else
1051                         {
1052                                 /* a range of zero would cause a 32 bit value to be shifted by 32 bits.
1053                                  * this has undefined behaviour, but for CIDR purposes the resulting mask
1054                                  * from a.b.c.d/0 is 0.0.0.0/0
1055                                  */
1056                                 v4.s_addr = 0;
1057                         }
1058
1059                         snprintf(buf, 44, "%s/%d", inet_ntop(AF_INET, &v4, buffer, 16), range);
1060                         return buf;
1061                 }
1062                 break;
1063         }
1064
1065         return ""; // unused, but oh well
1066 }
1067
1068 const char* User::GetIPString()
1069 {
1070         int port;
1071         if (cachedip.empty())
1072         {
1073                 irc::sockets::satoap(&client_sa, cachedip, port);
1074                 /* IP addresses starting with a : on irc are a Bad Thing (tm) */
1075                 if (cachedip.c_str()[0] == ':')
1076                         cachedip.insert(0,1,'0');
1077         }
1078
1079         return cachedip.c_str();
1080 }
1081
1082 bool User::SetClientIP(const char* sip)
1083 {
1084         this->cachedip = "";
1085         return irc::sockets::aptosa(sip, 0, &client_sa);
1086 }
1087
1088 static std::string wide_newline("\r\n");
1089
1090 void User::Write(const std::string& text)
1091 {
1092         if (!ServerInstance->SE->BoundsCheckFd(this))
1093                 return;
1094
1095         if (text.length() > MAXBUF - 2)
1096         {
1097                 // this should happen rarely or never. Crop the string at 512 and try again.
1098                 std::string try_again = text.substr(0, MAXBUF - 2);
1099                 Write(try_again);
1100                 return;
1101         }
1102
1103         ServerInstance->Logs->Log("USEROUTPUT", DEBUG,"C[%d] O %s", this->GetFd(), text.c_str());
1104
1105         this->AddWriteBuf(text);
1106         this->AddWriteBuf(wide_newline);
1107
1108         ServerInstance->stats->statsSent += text.length() + 2;
1109         this->bytes_out += text.length() + 2;
1110         this->cmds_out++;
1111 }
1112
1113 /** Write()
1114  */
1115 void User::Write(const char *text, ...)
1116 {
1117         va_list argsPtr;
1118         char textbuffer[MAXBUF];
1119
1120         va_start(argsPtr, text);
1121         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1122         va_end(argsPtr);
1123
1124         this->Write(std::string(textbuffer));
1125 }
1126
1127 void User::WriteServ(const std::string& text)
1128 {
1129         this->Write(":%s %s",ServerInstance->Config->ServerName.c_str(),text.c_str());
1130 }
1131
1132 /** WriteServ()
1133  *  Same as Write(), except `text' is prefixed with `:server.name '.
1134  */
1135 void User::WriteServ(const char* text, ...)
1136 {
1137         va_list argsPtr;
1138         char textbuffer[MAXBUF];
1139
1140         va_start(argsPtr, text);
1141         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1142         va_end(argsPtr);
1143
1144         this->WriteServ(std::string(textbuffer));
1145 }
1146
1147
1148 void User::WriteNumeric(unsigned int numeric, const char* text, ...)
1149 {
1150         va_list argsPtr;
1151         char textbuffer[MAXBUF];
1152
1153         va_start(argsPtr, text);
1154         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1155         va_end(argsPtr);
1156
1157         this->WriteNumeric(numeric, std::string(textbuffer));
1158 }
1159
1160 void User::WriteNumeric(unsigned int numeric, const std::string &text)
1161 {
1162         char textbuffer[MAXBUF];
1163         ModResult MOD_RESULT;
1164
1165         FIRST_MOD_RESULT(OnNumeric, MOD_RESULT, (this, numeric, text));
1166
1167         if (MOD_RESULT == MOD_RES_DENY)
1168                 return;
1169
1170         snprintf(textbuffer,MAXBUF,":%s %03u %s",ServerInstance->Config->ServerName.c_str(), numeric, text.c_str());
1171         this->Write(std::string(textbuffer));
1172 }
1173
1174 void User::WriteFrom(User *user, const std::string &text)
1175 {
1176         char tb[MAXBUF];
1177
1178         snprintf(tb,MAXBUF,":%s %s",user->GetFullHost().c_str(),text.c_str());
1179
1180         this->Write(std::string(tb));
1181 }
1182
1183
1184 /* write text from an originating user to originating user */
1185
1186 void User::WriteFrom(User *user, const char* text, ...)
1187 {
1188         va_list argsPtr;
1189         char textbuffer[MAXBUF];
1190
1191         va_start(argsPtr, text);
1192         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1193         va_end(argsPtr);
1194
1195         this->WriteFrom(user, std::string(textbuffer));
1196 }
1197
1198
1199 /* write text to an destination user from a source user (e.g. user privmsg) */
1200
1201 void User::WriteTo(User *dest, const char *data, ...)
1202 {
1203         char textbuffer[MAXBUF];
1204         va_list argsPtr;
1205
1206         va_start(argsPtr, data);
1207         vsnprintf(textbuffer, MAXBUF, data, argsPtr);
1208         va_end(argsPtr);
1209
1210         this->WriteTo(dest, std::string(textbuffer));
1211 }
1212
1213 void User::WriteTo(User *dest, const std::string &data)
1214 {
1215         dest->WriteFrom(this, data);
1216 }
1217
1218 void User::WriteCommon(const char* text, ...)
1219 {
1220         char textbuffer[MAXBUF];
1221         va_list argsPtr;
1222
1223         if (this->registered != REG_ALL || quitting)
1224                 return;
1225
1226         int len = snprintf(textbuffer,MAXBUF,":%s ",this->GetFullHost().c_str());
1227
1228         va_start(argsPtr, text);
1229         vsnprintf(textbuffer + len, MAXBUF - len, text, argsPtr);
1230         va_end(argsPtr);
1231
1232         this->WriteCommonRaw(std::string(textbuffer), true);
1233 }
1234
1235 void User::WriteCommonExcept(const char* text, ...)
1236 {
1237         char textbuffer[MAXBUF];
1238         va_list argsPtr;
1239
1240         if (this->registered != REG_ALL || quitting)
1241                 return;
1242
1243         int len = snprintf(textbuffer,MAXBUF,":%s ",this->GetFullHost().c_str());
1244
1245         va_start(argsPtr, text);
1246         vsnprintf(textbuffer + len, MAXBUF - len, text, argsPtr);
1247         va_end(argsPtr);
1248
1249         this->WriteCommonRaw(std::string(textbuffer), false);
1250 }
1251
1252 void User::WriteCommonRaw(const std::string &line, bool include_self)
1253 {
1254         if (this->registered != REG_ALL || quitting)
1255                 return;
1256
1257         uniq_id_t uniq_id = ++already_sent;
1258
1259         UserChanList include_c(chans);
1260         std::map<User*,bool> exceptions;
1261
1262         exceptions[this] = include_self;
1263
1264         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1265
1266         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1267         {
1268                 User* u = i->first;
1269                 if (IS_LOCAL(u) && !u->quitting)
1270                 {
1271                         already_sent[u->fd] = uniq_id;
1272                         if (i->second)
1273                                 u->Write(line);
1274                 }
1275         }
1276         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1277         {
1278                 Channel* c = *v;
1279                 const UserMembList* ulist = c->GetUsers();
1280                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1281                 {
1282                         User* u = i->first;
1283                         if (IS_LOCAL(u) && !u->quitting && already_sent[u->fd] != uniq_id)
1284                         {
1285                                 already_sent[u->fd] = uniq_id;
1286                                 u->Write(line);
1287                         }
1288                 }
1289         }
1290 }
1291
1292 void User::WriteCommonQuit(const std::string &normal_text, const std::string &oper_text)
1293 {
1294         char tb1[MAXBUF];
1295         char tb2[MAXBUF];
1296
1297         if (this->registered != REG_ALL)
1298                 return;
1299
1300         uniq_id_t uniq_id = ++already_sent;
1301
1302         snprintf(tb1,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),normal_text.c_str());
1303         snprintf(tb2,MAXBUF,":%s QUIT :%s",this->GetFullHost().c_str(),oper_text.c_str());
1304         std::string out1 = tb1;
1305         std::string out2 = tb2;
1306
1307         UserChanList include_c(chans);
1308         std::map<User*,bool> exceptions;
1309
1310         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1311
1312         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1313         {
1314                 User* u = i->first;
1315                 if (IS_LOCAL(u) && !u->quitting)
1316                 {
1317                         already_sent[u->fd] = uniq_id;
1318                         if (i->second)
1319                                 u->Write(IS_OPER(u) ? out2 : out1);
1320                 }
1321         }
1322         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1323         {
1324                 const UserMembList* ulist = (*v)->GetUsers();
1325                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1326                 {
1327                         User* u = i->first;
1328                         if (IS_LOCAL(u) && !u->quitting && (already_sent[u->fd] != uniq_id))
1329                         {
1330                                 already_sent[u->fd] = uniq_id;
1331                                 u->Write(IS_OPER(u) ? out2 : out1);
1332                         }
1333                 }
1334         }
1335 }
1336
1337 void User::WriteWallOps(const std::string &text)
1338 {
1339         std::string wallop("WALLOPS :");
1340         wallop.append(text);
1341
1342         for (std::vector<User*>::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
1343         {
1344                 User* t = *i;
1345                 if (t->IsModeSet('w'))
1346                         this->WriteTo(t,wallop);
1347         }
1348 }
1349
1350 void User::WriteWallOps(const char* text, ...)
1351 {
1352         if (!IS_LOCAL(this))
1353                 return;
1354
1355         char textbuffer[MAXBUF];
1356         va_list argsPtr;
1357
1358         va_start(argsPtr, text);
1359         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1360         va_end(argsPtr);
1361
1362         this->WriteWallOps(std::string(textbuffer));
1363 }
1364
1365 /* return 0 or 1 depending if users u and u2 share one or more common channels
1366  * (used by QUIT, NICK etc which arent channel specific notices)
1367  *
1368  * The old algorithm in 1.0 for this was relatively inefficient, iterating over
1369  * the first users channels then the second users channels within the outer loop,
1370  * therefore it was a maximum of x*y iterations (upon returning 0 and checking
1371  * all possible iterations). However this new function instead checks against the
1372  * channel's userlist in the inner loop which is a std::map<User*,User*>
1373  * and saves us time as we already know what pointer value we are after.
1374  * Don't quote me on the maths as i am not a mathematician or computer scientist,
1375  * but i believe this algorithm is now x+(log y) maximum iterations instead.
1376  */
1377 bool User::SharesChannelWith(User *other)
1378 {
1379         if ((!other) || (this->registered != REG_ALL) || (other->registered != REG_ALL))
1380                 return false;
1381
1382         /* Outer loop */
1383         for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1384         {
1385                 /* Eliminate the inner loop (which used to be ~equal in size to the outer loop)
1386                  * by replacing it with a map::find which *should* be more efficient
1387                  */
1388                 if ((*i)->HasUser(other))
1389                         return true;
1390         }
1391         return false;
1392 }
1393
1394 bool User::ChangeName(const char* gecos)
1395 {
1396         if (!this->fullname.compare(gecos))
1397                 return true;
1398
1399         if (IS_LOCAL(this))
1400         {
1401                 ModResult MOD_RESULT;
1402                 FIRST_MOD_RESULT(OnChangeLocalUserGECOS, MOD_RESULT, (this,gecos));
1403                 if (MOD_RESULT == MOD_RES_DENY)
1404                         return false;
1405                 FOREACH_MOD(I_OnChangeName,OnChangeName(this,gecos));
1406         }
1407         this->fullname.assign(gecos, 0, ServerInstance->Config->Limits.MaxGecos);
1408
1409         return true;
1410 }
1411
1412 void User::DoHostCycle(const std::string &quitline)
1413 {
1414         char buffer[MAXBUF];
1415
1416         if (!ServerInstance->Config->CycleHosts)
1417                 return;
1418
1419         uniq_id_t silent_id = ++already_sent;
1420         uniq_id_t seen_id = ++already_sent;
1421
1422         UserChanList include_c(chans);
1423         std::map<User*,bool> exceptions;
1424
1425         FOREACH_MOD(I_OnBuildNeighborList,OnBuildNeighborList(this, include_c, exceptions));
1426
1427         for (std::map<User*,bool>::iterator i = exceptions.begin(); i != exceptions.end(); ++i)
1428         {
1429                 User* u = i->first;
1430                 if (IS_LOCAL(u) && !u->quitting)
1431                 {
1432                         if (i->second)
1433                         {
1434                                 already_sent[u->fd] = seen_id;
1435                                 u->Write(quitline);
1436                         }
1437                         else
1438                         {
1439                                 already_sent[u->fd] = silent_id;
1440                         }
1441                 }
1442         }
1443         for (UCListIter v = include_c.begin(); v != include_c.end(); ++v)
1444         {
1445                 Channel* c = *v;
1446                 snprintf(buffer, MAXBUF, ":%s JOIN %s", GetFullHost().c_str(), c->name.c_str());
1447                 std::string joinline(buffer);
1448                 std::string modeline = ServerInstance->Modes->ModeString(this, c);
1449                 if (modeline.length() > 0)
1450                 {
1451                         snprintf(buffer, MAXBUF, ":%s MODE %s +%s", GetFullHost().c_str(), c->name.c_str(), modeline.c_str());
1452                         modeline = buffer;
1453                 }
1454
1455                 const UserMembList *ulist = c->GetUsers();
1456                 for (UserMembList::const_iterator i = ulist->begin(); i != ulist->end(); i++)
1457                 {
1458                         User* u = i->first;
1459                         if (u == this || !IS_LOCAL(u))
1460                                 continue;
1461                         if (already_sent[u->fd] == silent_id)
1462                                 continue;
1463
1464                         if (already_sent[u->fd] != seen_id)
1465                         {
1466                                 u->Write(quitline);
1467                                 already_sent[i->first->fd] = seen_id;
1468                         }
1469                         u->Write(joinline);
1470                         if (modeline.length() > 0)
1471                                 u->Write(modeline);
1472                 }
1473         }
1474 }
1475
1476 bool User::ChangeDisplayedHost(const char* shost)
1477 {
1478         if (dhost == shost)
1479                 return true;
1480
1481         if (IS_LOCAL(this))
1482         {
1483                 ModResult MOD_RESULT;
1484                 FIRST_MOD_RESULT(OnChangeLocalUserHost, MOD_RESULT, (this,shost));
1485                 if (MOD_RESULT == MOD_RES_DENY)
1486                         return false;
1487         }
1488
1489         FOREACH_MOD(I_OnChangeHost, OnChangeHost(this,shost));
1490
1491         std::string quitstr = ":" + GetFullHost() + " QUIT :Changing host";
1492
1493         /* Fix by Om: User::dhost is 65 long, this was truncating some long hosts */
1494         this->dhost.assign(shost, 0, 64);
1495
1496         this->InvalidateCache();
1497
1498         this->DoHostCycle(quitstr);
1499
1500         if (IS_LOCAL(this))
1501                 this->WriteNumeric(RPL_YOURDISPLAYEDHOST, "%s %s :is now your displayed host",this->nick.c_str(),this->dhost.c_str());
1502
1503         return true;
1504 }
1505
1506 bool User::ChangeIdent(const char* newident)
1507 {
1508         if (this->ident == newident)
1509                 return true;
1510
1511         FOREACH_MOD(I_OnChangeIdent, OnChangeIdent(this,newident));
1512
1513         std::string quitstr = ":" + GetFullHost() + " QUIT :Changing ident";
1514
1515         this->ident.assign(newident, 0, ServerInstance->Config->Limits.IdentMax + 1);
1516
1517         this->InvalidateCache();
1518
1519         this->DoHostCycle(quitstr);
1520
1521         return true;
1522 }
1523
1524 void User::SendAll(const char* command, const char* text, ...)
1525 {
1526         char textbuffer[MAXBUF];
1527         char formatbuffer[MAXBUF];
1528         va_list argsPtr;
1529
1530         va_start(argsPtr, text);
1531         vsnprintf(textbuffer, MAXBUF, text, argsPtr);
1532         va_end(argsPtr);
1533
1534         snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost().c_str(), command, textbuffer);
1535         std::string fmt = formatbuffer;
1536
1537         for (std::vector<User*>::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
1538         {
1539                 (*i)->Write(fmt);
1540         }
1541 }
1542
1543
1544 std::string User::ChannelList(User* source, bool spy)
1545 {
1546         std::string list;
1547
1548         for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
1549         {
1550                 Channel* c = *i;
1551                 /* If the target is the sender, neither +p nor +s is set, or
1552                  * the channel contains the user, it is not a spy channel
1553                  */
1554                 if (spy != (source == this || !(c->IsModeSet('p') || c->IsModeSet('s')) || c->HasUser(source)))
1555                         list.append(c->GetPrefixChar(this)).append(c->name).append(" ");
1556         }
1557
1558         return list;
1559 }
1560
1561 void User::SplitChanList(User* dest, const std::string &cl)
1562 {
1563         std::string line;
1564         std::ostringstream prefix;
1565         std::string::size_type start, pos, length;
1566
1567         prefix << this->nick << " " << dest->nick << " :";
1568         line = prefix.str();
1569         int namelen = ServerInstance->Config->ServerName.length() + 6;
1570
1571         for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
1572         {
1573                 length = (pos == std::string::npos) ? cl.length() : pos;
1574
1575                 if (line.length() + namelen + length - start > 510)
1576                 {
1577                         ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
1578                         line = prefix.str();
1579                 }
1580
1581                 if(pos == std::string::npos)
1582                 {
1583                         line.append(cl.substr(start, length - start));
1584                         break;
1585                 }
1586                 else
1587                 {
1588                         line.append(cl.substr(start, length - start + 1));
1589                 }
1590         }
1591
1592         if (line.length())
1593         {
1594                 ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
1595         }
1596 }
1597
1598 /*
1599  * Sets a user's connection class.
1600  * If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc.
1601  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1602  * then their ip will be taken as 'priority' anyway, so for example,
1603  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1604  */
1605 ConnectClass* User::SetClass(const std::string &explicit_name)
1606 {
1607         ConnectClass *found = NULL;
1608
1609         if (!IS_LOCAL(this))
1610                 return NULL;
1611
1612         ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Setting connect class for UID %s", this->uuid.c_str());
1613
1614         if (!explicit_name.empty())
1615         {
1616                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1617                 {
1618                         ConnectClass* c = *i;
1619
1620                         if (explicit_name == c->name)
1621                         {
1622                                 ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Explicitly set to %s", explicit_name.c_str());
1623                                 found = c;
1624                         }
1625                 }
1626         }
1627         else
1628         {
1629                 for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
1630                 {
1631                         ConnectClass* c = *i;
1632
1633                         if (c->type == CC_ALLOW)
1634                         {
1635                                 ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "ALLOW %s %d %s", c->host.c_str(), c->GetPort(), c->GetName().c_str());
1636                         }
1637                         else
1638                         {
1639                                 ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "DENY %s %d %s", c->GetHost().c_str(), c->GetPort(), c->GetName().c_str());
1640                         }
1641
1642                         /* check if host matches.. */
1643                         if (c->GetHost().length() && !InspIRCd::MatchCIDR(this->GetIPString(), c->GetHost(), NULL) &&
1644                             !InspIRCd::MatchCIDR(this->host, c->GetHost(), NULL))
1645                         {
1646                                 ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "No host match (for %s)", c->GetHost().c_str());
1647                                 continue;
1648                         }
1649
1650                         /*
1651                          * deny change if change will take class over the limit check it HERE, not after we found a matching class,
1652                          * because we should attempt to find another class if this one doesn't match us. -- w00t
1653                          */
1654                         if (c->limit && (c->GetReferenceCount() >= c->limit))
1655                         {
1656                                 ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "OOPS: Connect class limit (%lu) hit, denying", c->limit);
1657                                 continue;
1658                         }
1659
1660                         /* if it requires a port ... */
1661                         if (c->GetPort())
1662                         {
1663                                 ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Requires port (%d)", c->GetPort());
1664
1665                                 /* and our port doesn't match, fail. */
1666                                 if (this->GetServerPort() != c->GetPort())
1667                                 {
1668                                         ServerInstance->Logs->Log("CONNECTCLASS", DEBUG, "Port match failed (%d)", this->GetServerPort());
1669                                         continue;
1670                                 }
1671                         }
1672
1673                         /* we stop at the first class that meets ALL critera. */
1674                         found = c;
1675                         break;
1676                 }
1677         }
1678
1679         /*
1680          * Okay, assuming we found a class that matches.. switch us into that class, keeping refcounts up to date.
1681          */
1682         if (found)
1683         {
1684                 MyClass = found;
1685         }
1686
1687         return this->MyClass;
1688 }
1689
1690 /* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
1691  * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
1692  * then their ip will be taken as 'priority' anyway, so for example,
1693  * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
1694  */
1695 ConnectClass* User::GetClass()
1696 {
1697         return this->MyClass;
1698 }
1699
1700 void User::PurgeEmptyChannels()
1701 {
1702         std::vector<Channel*> to_delete;
1703
1704         // firstly decrement the count on each channel
1705         for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
1706         {
1707                 Channel* c = *f;
1708                 c->RemoveAllPrefixes(this);
1709                 if (c->DelUser(this) == 0)
1710                 {
1711                         /* No users left in here, mark it for deletion */
1712                         try
1713                         {
1714                                 to_delete.push_back(c);
1715                         }
1716                         catch (...)
1717                         {
1718                                 ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()");
1719                         }
1720                 }
1721         }
1722
1723         for (std::vector<Channel*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
1724         {
1725                 Channel* thischan = *n;
1726                 chan_hash::iterator i2 = ServerInstance->chanlist->find(thischan->name);
1727                 if (i2 != ServerInstance->chanlist->end())
1728                 {
1729                         ModResult MOD_RESULT;
1730                         FIRST_MOD_RESULT(OnChannelPreDelete, MOD_RESULT, (i2->second));
1731                         if (MOD_RESULT == MOD_RES_DENY)
1732                                 continue; // delete halted by module
1733                         FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
1734                         delete i2->second;
1735                         ServerInstance->chanlist->erase(i2);
1736                         this->chans.erase(*n);
1737                 }
1738         }
1739
1740         this->UnOper();
1741 }
1742
1743 void User::ShowMOTD()
1744 {
1745         if (!ServerInstance->Config->MOTD.size())
1746         {
1747                 this->WriteNumeric(ERR_NOMOTD, "%s :Message of the day file is missing.",this->nick.c_str());
1748                 return;
1749         }
1750         this->WriteNumeric(RPL_MOTDSTART, "%s :%s message of the day", this->nick.c_str(), ServerInstance->Config->ServerName.c_str());
1751
1752         for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++)
1753                 this->WriteNumeric(RPL_MOTD, "%s :- %s",this->nick.c_str(),i->c_str());
1754
1755         this->WriteNumeric(RPL_ENDOFMOTD, "%s :End of message of the day.", this->nick.c_str());
1756 }
1757
1758 void User::ShowRULES()
1759 {
1760         if (!ServerInstance->Config->RULES.size())
1761         {
1762                 this->WriteNumeric(ERR_NORULES, "%s :RULES File is missing",this->nick.c_str());
1763                 return;
1764         }
1765
1766         this->WriteNumeric(RPL_RULESTART, "%s :- %s Server Rules -",this->nick.c_str(),ServerInstance->Config->ServerName.c_str());
1767
1768         for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++)
1769                 this->WriteNumeric(RPL_RULES, "%s :- %s",this->nick.c_str(),i->c_str());
1770
1771         this->WriteNumeric(RPL_RULESEND, "%s :End of RULES command.",this->nick.c_str());
1772 }
1773
1774 void User::IncreasePenalty(int increase)
1775 {
1776         this->Penalty += increase;
1777 }
1778
1779 void User::DecreasePenalty(int decrease)
1780 {
1781         this->Penalty -= decrease;
1782 }
1783
1784 void FakeUser::SetFakeServer(std::string name)
1785 {
1786         this->nick = name;
1787         this->server = name;
1788 }
1789
1790 const std::string FakeUser::GetFullHost()
1791 {
1792         if (!ServerInstance->Config->HideWhoisServer.empty())
1793                 return ServerInstance->Config->HideWhoisServer;
1794         return nick;
1795 }
1796
1797 const std::string FakeUser::GetFullRealHost()
1798 {
1799         if (!ServerInstance->Config->HideWhoisServer.empty())
1800                 return ServerInstance->Config->HideWhoisServer;
1801         return nick;
1802 }
1803
1804 ConnectClass::ConnectClass(char t, const std::string& mask)
1805         : type(t), name("unnamed"), registration_timeout(0), host(mask),
1806         pingtime(0), pass(""), hash(""), softsendqmax(0), hardsendqmax(0),
1807         recvqmax(0), maxlocal(0), maxglobal(0), maxchans(0), port(0), limit(0)
1808 {
1809 }
1810
1811 ConnectClass::ConnectClass(char t, const std::string& mask, const ConnectClass& parent)
1812         : type(t), name("unnamed"),
1813         registration_timeout(parent.registration_timeout), host(mask),
1814         pingtime(parent.pingtime), pass(parent.pass), hash(parent.hash),
1815         softsendqmax(parent.softsendqmax), hardsendqmax(parent.hardsendqmax),
1816         recvqmax(parent.recvqmax), maxlocal(parent.maxlocal),
1817         maxglobal(parent.maxglobal), maxchans(parent.maxchans),
1818         port(parent.port), limit(parent.limit)
1819 {
1820 }
1821
1822 void ConnectClass::Update(const ConnectClass* src)
1823 {
1824         name = src->name;
1825         registration_timeout = src->registration_timeout;
1826         host = src->host;
1827         pingtime = src->pingtime;
1828         pass = src->pass;
1829         hash = src->hash;
1830         softsendqmax = src->softsendqmax;
1831         hardsendqmax = src->hardsendqmax;
1832         recvqmax = src->recvqmax;
1833         maxlocal = src->maxlocal;
1834         maxglobal = src->maxglobal;
1835         limit = src->limit;
1836 }