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