The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

users.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 /* $Core */
00015 
00016 #include "inspircd.h"
00017 #include <stdarg.h>
00018 #include "socketengine.h"
00019 #include "xline.h"
00020 #include "bancache.h"
00021 #include "commands/cmd_whowas.h"
00022 
00023 /* XXX: Used for speeding up WriteCommon operations */
00024 unsigned long uniq_id = 1;
00025 
00026 static unsigned long* already_sent = NULL;
00027 
00028 
00029 void InitializeAlreadySent(SocketEngine* SE)
00030 {
00031         already_sent = new unsigned long[SE->GetMaxFds()];
00032         memset(already_sent, 0, SE->GetMaxFds() * sizeof(unsigned long));
00033 }
00034 
00035 
00036 std::string User::ProcessNoticeMasks(const char *sm)
00037 {
00038         bool adding = true, oldadding = false;
00039         const char *c = sm;
00040         std::string output;
00041 
00042         while (c && *c)
00043         {
00044                 switch (*c)
00045                 {
00046                         case '+':
00047                                 adding = true;
00048                         break;
00049                         case '-':
00050                                 adding = false;
00051                         break;
00052                         case '*':
00053                                 for (unsigned char d = 'A'; d <= 'z'; d++)
00054                                 {
00055                                         if (ServerInstance->SNO->IsEnabled(d))
00056                                         {
00057                                                 if ((!IsNoticeMaskSet(d) && adding) || (IsNoticeMaskSet(d) && !adding))
00058                                                 {
00059                                                         if ((oldadding != adding) || (!output.length()))
00060                                                                 output += (adding ? '+' : '-');
00061 
00062                                                         this->SetNoticeMask(d, adding);
00063 
00064                                                         output += d;
00065                                                 }
00066                                         }
00067                                         oldadding = adding;
00068                                 }
00069                         break;
00070                         default:
00071                                 if ((*c >= 'A') && (*c <= 'z') && (ServerInstance->SNO->IsEnabled(*c)))
00072                                 {
00073                                         if ((!IsNoticeMaskSet(*c) && adding) || (IsNoticeMaskSet(*c) && !adding))
00074                                         {
00075                                                 if ((oldadding != adding) || (!output.length()))
00076                                                         output += (adding ? '+' : '-');
00077 
00078                                                 this->SetNoticeMask(*c, adding);
00079 
00080                                                 output += *c;
00081                                         }
00082                                 }
00083                                 else
00084                                         this->WriteNumeric(ERR_UNKNOWNSNOMASK, "%s %c :is unknown snomask char to me", this->nick.c_str(), *c);
00085 
00086                                 oldadding = adding;
00087                         break;
00088                 }
00089 
00090                 *c++;
00091         }
00092 
00093         return output;
00094 }
00095 
00096 void User::StartDNSLookup()
00097 {
00098         try
00099         {
00100                 bool cached = false;
00101                 const char* sip = this->GetIPString(false);
00102 
00103                 /* Special case for 4in6 (Have i mentioned i HATE 4in6?) */
00104                 if (!strncmp(sip, "0::ffff:", 8))
00105                         res_reverse = new UserResolver(this->ServerInstance, this, sip + 8, DNS_QUERY_PTR4, cached);
00106                 else
00107                         res_reverse = new UserResolver(this->ServerInstance, this, sip, this->GetProtocolFamily() == AF_INET ? DNS_QUERY_PTR4 : DNS_QUERY_PTR6, cached);
00108 
00109                 this->ServerInstance->AddResolver(res_reverse, cached);
00110         }
00111         catch (CoreException& e)
00112         {
00113                 ServerInstance->Logs->Log("USERS", DEBUG,"Error in resolver: %s",e.GetReason());
00114         }
00115 }
00116 
00117 bool User::IsNoticeMaskSet(unsigned char sm)
00118 {
00119         if (!isalpha(sm))
00120                 return false;
00121         return (snomasks[sm-65]);
00122 }
00123 
00124 void User::SetNoticeMask(unsigned char sm, bool value)
00125 {
00126         if (!isalpha(sm))
00127                 return;
00128         snomasks[sm-65] = value;
00129 }
00130 
00131 const char* User::FormatNoticeMasks()
00132 {
00133         static char data[MAXBUF];
00134         int offset = 0;
00135 
00136         for (int n = 0; n < 64; n++)
00137         {
00138                 if (snomasks[n])
00139                         data[offset++] = n+65;
00140         }
00141 
00142         data[offset] = 0;
00143         return data;
00144 }
00145 
00146 bool User::IsModeSet(unsigned char m)
00147 {
00148         if (!isalpha(m))
00149                 return false;
00150         return (modes[m-65]);
00151 }
00152 
00153 void User::SetMode(unsigned char m, bool value)
00154 {
00155         if (!isalpha(m))
00156                 return;
00157         modes[m-65] = value;
00158 }
00159 
00160 const char* User::FormatModes()
00161 {
00162         static char data[MAXBUF];
00163         int offset = 0;
00164         for (int n = 0; n < 64; n++)
00165         {
00166                 if (modes[n])
00167                         data[offset++] = n+65;
00168         }
00169         data[offset] = 0;
00170         return data;
00171 }
00172 
00173 void User::DecrementModes()
00174 {
00175         ServerInstance->Logs->Log("USERS", DEBUG, "DecrementModes()");
00176         for (unsigned char n = 'A'; n <= 'z'; n++)
00177         {
00178                 if (modes[n-65])
00179                 {
00180                         ServerInstance->Logs->Log("USERS", DEBUG,"DecrementModes() found mode %c", n);
00181                         ModeHandler* mh = ServerInstance->Modes->FindMode(n, MODETYPE_USER);
00182                         if (mh)
00183                         {
00184                                 ServerInstance->Logs->Log("USERS", DEBUG,"Found handler %c and call ChangeCount", n);
00185                                 mh->ChangeCount(-1);
00186                         }
00187                 }
00188         }
00189 }
00190 
00191 User::User(InspIRCd* Instance, const std::string &uid) : ServerInstance(Instance)
00192 {
00193         server = (char*)Instance->FindServerNamePtr(Instance->Config->ServerName);
00194         reset_due = ServerInstance->Time();
00195         age = ServerInstance->Time();
00196         Penalty = 0;
00197         lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;
00198         bytes_in = bytes_out = cmds_in = cmds_out = 0;
00199         quietquit = OverPenalty = ExemptFromPenalty = quitting = exempt = haspassed = dns_done = false;
00200         fd = -1;
00201         recvq.clear();
00202         sendq.clear();
00203         res_forward = res_reverse = NULL;
00204         Visibility = NULL;
00205         ip = NULL;
00206         MyClass = NULL;
00207         io = NULL;
00208         AllowedUserModes = NULL;
00209         AllowedChanModes = NULL;
00210         AllowedOperCommands = NULL;
00211         chans.clear();
00212         invites.clear();
00213 
00214         if (uid.empty())
00215                 uuid.assign(Instance->GetUID(), 0, UUID_LENGTH - 1);
00216         else
00217                 uuid.assign(uid, 0, UUID_LENGTH - 1);
00218 
00219         ServerInstance->Logs->Log("USERS", DEBUG,"New UUID for user: %s (%s)", uuid.c_str(), uid.empty() ? "allocated new" : "used remote");
00220 
00221         user_hash::iterator finduuid = Instance->Users->uuidlist->find(uuid);
00222         if (finduuid == Instance->Users->uuidlist->end())
00223                 (*Instance->Users->uuidlist)[uuid] = this;
00224         else
00225                 throw CoreException("Duplicate UUID "+std::string(uuid)+" in User constructor");
00226 }
00227 
00228 User::~User()
00229 {
00230         /* NULL for remote users :) */
00231         if (this->MyClass)
00232         {
00233                 this->MyClass->RefCount--;
00234                 ServerInstance->Logs->Log("USERS", DEBUG, "User destructor -- connect refcount now: %lu", this->MyClass->RefCount);
00235         }
00236         if (this->AllowedOperCommands)
00237         {
00238                 delete AllowedOperCommands;
00239                 AllowedOperCommands = NULL;
00240         }
00241 
00242         if (this->AllowedUserModes)
00243         {
00244                 delete[] AllowedUserModes;
00245                 AllowedUserModes = NULL;
00246         }
00247 
00248         if (this->AllowedChanModes)
00249         {
00250                 delete[] AllowedChanModes;
00251                 AllowedChanModes = NULL;
00252         }
00253 
00254         this->InvalidateCache();
00255         this->DecrementModes();
00256 
00257         if (ip)
00258         {
00259                 ServerInstance->Users->RemoveCloneCounts(this);
00260 
00261                 if (this->GetProtocolFamily() == AF_INET)
00262                 {
00263                         delete (sockaddr_in*)ip;
00264                 }
00265 #ifdef SUPPORT_IP6LINKS
00266                 else
00267                 {
00268                         delete (sockaddr_in6*)ip;
00269                 }
00270 #endif
00271         }
00272 
00273         ServerInstance->Users->uuidlist->erase(uuid);
00274 }
00275 
00276 const std::string& User::MakeHost()
00277 {
00278         if (!this->cached_makehost.empty())
00279                 return this->cached_makehost;
00280 
00281         char nhost[MAXBUF];
00282         /* This is much faster than snprintf */
00283         char* t = nhost;
00284         for(const char* n = ident.c_str(); *n; n++)
00285                 *t++ = *n;
00286         *t++ = '@';
00287         for(const char* n = host.c_str(); *n; n++)
00288                 *t++ = *n;
00289         *t = 0;
00290 
00291         this->cached_makehost.assign(nhost);
00292 
00293         return this->cached_makehost;
00294 }
00295 
00296 const std::string& User::MakeHostIP()
00297 {
00298         if (!this->cached_hostip.empty())
00299                 return this->cached_hostip;
00300 
00301         char ihost[MAXBUF];
00302         /* This is much faster than snprintf */
00303         char* t = ihost;
00304         for(const char* n = ident.c_str(); *n; n++)
00305                 *t++ = *n;
00306         *t++ = '@';
00307         for(const char* n = this->GetIPString(); *n; n++)
00308                 *t++ = *n;
00309         *t = 0;
00310 
00311         this->cached_hostip = ihost;
00312 
00313         return this->cached_hostip;
00314 }
00315 
00316 void User::CloseSocket()
00317 {
00318         if (this->fd > -1)
00319         {
00320                 ServerInstance->SE->Shutdown(this, 2);
00321                 ServerInstance->SE->Close(this);
00322         }
00323 }
00324 
00325 const std::string& User::GetFullHost()
00326 {
00327         if (!this->cached_fullhost.empty())
00328                 return this->cached_fullhost;
00329 
00330         char result[MAXBUF];
00331         char* t = result;
00332         for(const char* n = nick.c_str(); *n; n++)
00333                 *t++ = *n;
00334         *t++ = '!';
00335         for(const char* n = ident.c_str(); *n; n++)
00336                 *t++ = *n;
00337         *t++ = '@';
00338         for(const char* n = dhost.c_str(); *n; n++)
00339                 *t++ = *n;
00340         *t = 0;
00341 
00342         this->cached_fullhost = result;
00343 
00344         return this->cached_fullhost;
00345 }
00346 
00347 char* User::MakeWildHost()
00348 {
00349         static char nresult[MAXBUF];
00350         char* t = nresult;
00351         *t++ = '*';     *t++ = '!';
00352         *t++ = '*';     *t++ = '@';
00353         for(const char* n = dhost.c_str(); *n; n++)
00354                 *t++ = *n;
00355         *t = 0;
00356         return nresult;
00357 }
00358 
00359 int User::ReadData(void* buffer, size_t size)
00360 {
00361         if (IS_LOCAL(this))
00362         {
00363 #ifndef WIN32
00364                 return read(this->fd, buffer, size);
00365 #else
00366                 return recv(this->fd, (char*)buffer, size, 0);
00367 #endif
00368         }
00369         else
00370                 return 0;
00371 }
00372 
00373 
00374 const std::string& User::GetFullRealHost()
00375 {
00376         if (!this->cached_fullrealhost.empty())
00377                 return this->cached_fullrealhost;
00378 
00379         char fresult[MAXBUF];
00380         char* t = fresult;
00381         for(const char* n = nick.c_str(); *n; n++)
00382                 *t++ = *n;
00383         *t++ = '!';
00384         for(const char* n = ident.c_str(); *n; n++)
00385                 *t++ = *n;
00386         *t++ = '@';
00387         for(const char* n = host.c_str(); *n; n++)
00388                 *t++ = *n;
00389         *t = 0;
00390 
00391         this->cached_fullrealhost = fresult;
00392 
00393         return this->cached_fullrealhost;
00394 }
00395 
00396 bool User::IsInvited(const irc::string &channel)
00397 {
00398         time_t now = time(NULL);
00399         InvitedList::iterator safei;
00400         for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
00401         {
00402                 if (channel == i->first)
00403                 {
00404                         if (i->second != 0 && now > i->second)
00405                         {
00406                                 /* Expired invite, remove it. */
00407                                 safei = i;
00408                                 --i;
00409                                 invites.erase(safei);
00410                                 continue;
00411                         }
00412                         return true;
00413                 }
00414         }
00415         return false;
00416 }
00417 
00418 InvitedList* User::GetInviteList()
00419 {
00420         time_t now = time(NULL);
00421         /* Weed out expired invites here. */
00422         InvitedList::iterator safei;
00423         for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
00424         {
00425                 if (i->second != 0 && now > i->second)
00426                 {
00427                         /* Expired invite, remove it. */
00428                         safei = i;
00429                         --i;
00430                         invites.erase(safei);
00431                 }
00432         }
00433         return &invites;
00434 }
00435 
00436 void User::InviteTo(const irc::string &channel, time_t invtimeout)
00437 {
00438         time_t now = time(NULL);
00439         if (invtimeout != 0 && now > invtimeout) return; /* Don't add invites that are expired from the get-go. */
00440         for (InvitedList::iterator i = invites.begin(); i != invites.end(); ++i)
00441         {
00442                 if (channel == i->first)
00443                 {
00444                         if (i->second != 0 && invtimeout > i->second)
00445                         {
00446                                 i->second = invtimeout;
00447                         }
00448 
00449                         return;
00450                 }
00451         }
00452         invites.push_back(std::make_pair(channel, invtimeout));
00453 }
00454 
00455 void User::RemoveInvite(const irc::string &channel)
00456 {
00457         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
00458         {
00459                 if (channel == i->first)
00460                 {
00461                         invites.erase(i);
00462                         return;
00463                 }
00464         }
00465 }
00466 
00467 bool User::HasModePermission(unsigned char mode, ModeType type)
00468 {
00469         if (!IS_LOCAL(this))
00470                 return true;
00471 
00472         if (!IS_OPER(this))
00473                 return false;
00474 
00475         if (!AllowedUserModes || !AllowedChanModes)
00476                 return false;
00477 
00478         return ((type == MODETYPE_USER ? AllowedUserModes : AllowedChanModes))[(mode - 'A')];
00479         
00480 }
00481 
00482 bool User::HasPermission(const std::string &command)
00483 {
00484         /*
00485          * users on remote servers can completely bypass all permissions based checks.
00486          * This prevents desyncs when one server has different type/class tags to another.
00487          * That having been said, this does open things up to the possibility of source changes
00488          * allowing remote kills, etc - but if they have access to the src, they most likely have
00489          * access to the conf - so it's an end to a means either way.
00490          */
00491         if (!IS_LOCAL(this))
00492                 return true;
00493 
00494         // are they even an oper at all?
00495         if (!IS_OPER(this))
00496         {
00497                 return false;
00498         }
00499 
00500         if (!AllowedOperCommands)
00501                 return false;
00502 
00503         if (AllowedOperCommands->find(command) != AllowedOperCommands->end())
00504                 return true;
00505         else if (AllowedOperCommands->find("*") != AllowedOperCommands->end())
00506                 return true;
00507 
00508         return false;
00509 }
00510 
00511 bool User::AddBuffer(const std::string &a)
00512 {
00513         std::string::size_type start = 0;
00514         std::string::size_type i = a.find('\r');
00515 
00516         /*
00517          * The old implementation here took a copy, and rfind() on \r, removing as it found them, before
00518          * copying a second time onto the recvq. That's ok, but involves three copies minimum (recv() to buffer,
00519          * buffer to here, here to recvq) - The new method now copies twice (recv() to buffer, buffer to recvq).
00520          *
00521          * We use find() instead of rfind() for clarity, however unlike the old code, our scanning of the string is
00522          * contiguous: as we specify a startpoint, we never see characters we have scanned previously, making this
00523          * marginally faster in cases with a number of \r hidden early on in the buffer.
00524          *
00525          * How it works:
00526          * Start at first pos of string, find first \r, append everything in the chunk (excluding \r) to recvq. Set
00527          * i ahead of the \r, search for next \r, add next chunk to buffer... repeat.
00528          *              -- w00t (7 may, 2008)
00529          */
00530         if (i == std::string::npos)
00531         {
00532                 // no \r that we need to dance around, just add to buffer
00533                 recvq.append(a);
00534         }
00535         else
00536         {
00537                 // While we can find the end of a chunk to add
00538                 while (i != std::string::npos)
00539                 {
00540                         // Append the chunk that we have
00541                         recvq.append(a, start, (i - start));
00542 
00543                         // Start looking for the next one
00544                         start = i + 1;
00545                         i = a.find('\r', start);
00546                 }
00547 
00548                 if (start != a.length())
00549                 {
00550                         /*
00551                          * This is here to catch a corner case when we get something like:
00552                          * NICK w0
00553                          * 0t\r\nU
00554                          * SER ...
00555                          * in successive calls to us.
00556                          *
00557                          * Without this conditional, the 'U' on the second case will be dropped,
00558                          * which is most *certainly* not the behaviour we want!
00559                          *              -- w00t
00560                          */
00561                         recvq.append(a, start, (a.length() - start));
00562                 }
00563         }
00564 
00565         if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
00566         {
00567                 ServerInstance->Users->QuitUser(this, "RecvQ exceeded");
00568                 ServerInstance->SNO->WriteToSnoMask('A', "User %s RecvQ of %lu exceeds connect class maximum of %lu",this->nick.c_str(),(unsigned long int)recvq.length(),this->MyClass->GetRecvqMax());
00569                 return false;
00570         }
00571 
00572         return true;
00573 }
00574 
00575 bool User::BufferIsReady()
00576 {
00577         return (recvq.find('\n') != std::string::npos);
00578 }
00579 
00580 void User::ClearBuffer()
00581 {
00582         recvq.clear();
00583 }
00584 
00585 std::string User::GetBuffer()
00586 {
00587         try
00588         {
00589                 if (recvq.empty())
00590                         return "";
00591 
00592                 /* Strip any leading \r or \n off the string.
00593                  * Usually there are only one or two of these,
00594                  * so its is computationally cheap to do.
00595                  */
00596                 std::string::iterator t = recvq.begin();
00597                 while (t != recvq.end() && (*t == '\r' || *t == '\n'))
00598                 {
00599                         recvq.erase(t);
00600                         t = recvq.begin();
00601                 }
00602 
00603                 for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++)
00604                 {
00605                         /* Find the first complete line, return it as the
00606                          * result, and leave the recvq as whats left
00607                          */
00608                         if (*x == '\n')
00609                         {
00610                                 std::string ret = std::string(recvq.begin(), x);
00611                                 recvq.erase(recvq.begin(), x + 1);
00612                                 return ret;
00613                         }
00614                 }
00615                 return "";
00616         }
00617 
00618         catch (...)
00619         {
00620                 ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::GetBuffer()");
00621                 return "";
00622         }
00623 }
00624 
00625 void User::AddWriteBuf(const std::string &data)
00626 {
00627         if (this->quitting)
00628                 return;
00629 
00630         if (this->MyClass && (sendq.length() + data.length() > this->MyClass->GetSendqMax()))
00631         {
00632                 /*
00633                  * Fix by brain - Set the error text BEFORE calling, because
00634                  * if we dont it'll recursively  call here over and over again trying
00635                  * to repeatedly add the text to the sendq!
00636                  */
00637                 ServerInstance->Users->QuitUser(this, "SendQ exceeded");
00638                 ServerInstance->SNO->WriteToSnoMask('A', "User %s SendQ of %lu exceeds connect class maximum of %lu",this->nick.c_str(),(unsigned long int)sendq.length() + data.length(),this->MyClass->GetSendqMax());
00639                 return;
00640         }
00641 
00642         if (data.length() > MAXBUF - 2) /* MAXBUF has a value of 514, to account for line terminators */
00643                 sendq.append(data.substr(0,MAXBUF - 4)).append("\r\n"); /* MAXBUF-4 = 510 */
00644         else
00645                 sendq.append(data);
00646 }
00647 
00648 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
00649 void User::FlushWriteBuf()
00650 {
00651         if (this->fd == FD_MAGIC_NUMBER)
00652         {
00653                 sendq.clear();
00654                 return;
00655         }
00656 
00657         if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
00658         {
00659                 int old_sendq_length = sendq.length();
00660                 int n_sent = ServerInstance->SE->Send(this, this->sendq.data(), this->sendq.length(), 0);
00661 
00662                 if (n_sent == -1)
00663                 {
00664                         if (errno == EAGAIN)
00665                         {
00666                                 /* The socket buffer is full. This isnt fatal,
00667                                  * try again later.
00668                                  */
00669                                 ServerInstance->SE->WantWrite(this);
00670                         }
00671                         else
00672                         {
00673                                 /* Fatal error, set write error and bail */
00674                                 ServerInstance->Users->QuitUser(this, errno ? strerror(errno) : "Write error");
00675                                 return;
00676                         }
00677                 }
00678                 else
00679                 {
00680                         /* advance the queue */
00681                         if (n_sent)
00682                                 this->sendq = this->sendq.substr(n_sent);
00683                         /* update the user's stats counters */
00684                         this->bytes_out += n_sent;
00685                         this->cmds_out++;
00686                         if (n_sent != old_sendq_length)
00687                                 this->ServerInstance->SE->WantWrite(this);
00688                 }
00689         }
00690 
00691         /* note: NOT else if! */
00692         if (this->sendq.empty())
00693         {
00694                 FOREACH_MOD(I_OnBufferFlushed,OnBufferFlushed(this));
00695         }
00696 }
00697 
00698 void User::Oper(const std::string &opertype, const std::string &opername)
00699 {
00700         char* mycmd;
00701         char* savept;
00702         char* savept2;
00703 
00704         if (this->IsModeSet('o'))
00705                 this->UnOper();
00706 
00707         this->modes[UM_OPERATOR] = 1;
00708         this->WriteServ("MODE %s :+o", this->nick.c_str());
00709         FOREACH_MOD(I_OnOper, OnOper(this, opertype));
00710 
00711         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());
00712         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()));
00713 
00714         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());
00715         this->oper.assign(opertype, 0, 512);
00716         ServerInstance->Users->all_opers.push_back(this);
00717 
00718         opertype_t::iterator iter_opertype = ServerInstance->Config->opertypes.find(this->oper.c_str());
00719         if (iter_opertype != ServerInstance->Config->opertypes.end())
00720         {
00721 
00722                 if (AllowedOperCommands)
00723                         AllowedOperCommands->clear();
00724                 else
00725                         AllowedOperCommands = new std::map<std::string, bool>;
00726 
00727                 if (!AllowedChanModes)
00728                         AllowedChanModes = new bool[64];
00729 
00730                 if (!AllowedUserModes)
00731                         AllowedUserModes = new bool[64];
00732 
00733                 memset(AllowedUserModes, 0, 64);
00734                 memset(AllowedChanModes, 0, 64);
00735 
00736                 char* Classes = strdup(iter_opertype->second);
00737                 char* myclass = strtok_r(Classes," ",&savept);
00738                 while (myclass)
00739                 {
00740                         operclass_t::iterator iter_operclass = ServerInstance->Config->operclass.find(myclass);
00741                         if (iter_operclass != ServerInstance->Config->operclass.end())
00742                         {
00743                                 char* CommandList = strdup(iter_operclass->second.commandlist);
00744                                 mycmd = strtok_r(CommandList," ",&savept2);
00745                                 while (mycmd)
00746                                 {
00747                                         this->AllowedOperCommands->insert(std::make_pair(mycmd, true));
00748                                         mycmd = strtok_r(NULL," ",&savept2);
00749                                 }
00750                                 free(CommandList);
00751                                 this->AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want.
00752                                 for (unsigned char* c = (unsigned char*)iter_operclass->second.umodelist; *c; ++c)
00753                                 {
00754                                         if (*c == '*')
00755                                         {
00756                                                 memset(this->AllowedUserModes, (int)(true), 64);
00757                                         }
00758                                         else
00759                                         {
00760                                                 this->AllowedUserModes[*c - 'A'] = true;
00761                                         }
00762                                 }
00763                                 for (unsigned char* c = (unsigned char*)iter_operclass->second.cmodelist; *c; ++c)
00764                                 {
00765                                         if (*c == '*')
00766                                         {
00767                                                 memset(this->AllowedChanModes, (int)(true), 64);
00768                                         }
00769                                         else
00770                                         {
00771                                                 this->AllowedChanModes[*c - 'A'] = true;
00772                                         }
00773                                 }
00774                         }
00775                         myclass = strtok_r(NULL," ",&savept);
00776                 }
00777                 free(Classes);
00778         }
00779 
00780         FOREACH_MOD(I_OnPostOper,OnPostOper(this, opertype, opername));
00781 }
00782 
00783 void User::UnOper()
00784 {
00785         if (IS_OPER(this))
00786         {
00787                 /*
00788                  * unset their oper type (what IS_OPER checks).
00789                  * note, order is important - this must come before modes as -o attempts
00790                  * to call UnOper. -- w00t
00791                  */
00792                 this->oper.clear();
00793 
00794                 /* Remove all oper only modes from the user when the deoper - Bug #466*/
00795                 std::string moderemove("-");
00796 
00797                 for (unsigned char letter = 'A'; letter <= 'z'; letter++)
00798                 {
00799                         ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_USER);
00800                         if (mh && mh->NeedsOper())
00801                                 moderemove += letter;
00802                 }
00803 
00804                 std::vector<std::string> parameters;
00805                 parameters.push_back(this->nick);
00806                 parameters.push_back(moderemove);
00807 
00808                 ServerInstance->Parser->CallHandler("MODE", parameters, this);
00809                         
00810                 /* remove the user from the oper list. Will remove multiple entries as a safeguard against bug #404 */
00811                 ServerInstance->Users->all_opers.remove(this);
00812 
00813                 if (AllowedOperCommands)
00814                 {
00815                         delete AllowedOperCommands;
00816                         AllowedOperCommands = NULL;
00817                 }
00818                 if (AllowedUserModes)
00819                 {
00820                         delete[] AllowedUserModes;
00821                         AllowedUserModes = NULL;
00822                 }
00823                 if (AllowedChanModes)
00824                 {
00825                         delete[] AllowedChanModes;
00826                         AllowedChanModes = NULL;
00827                 }
00828 
00829         }
00830 }
00831 
00832 /* adds or updates an entry in the whowas list */
00833 void User::AddToWhoWas()
00834 {
00835         Command* whowas_command = ServerInstance->Parser->GetHandler("WHOWAS");
00836         if (whowas_command)
00837         {
00838                 std::deque<classbase*> params;
00839                 params.push_back(this);
00840                 whowas_command->HandleInternal(WHOWAS_ADD, params);
00841         }
00842 }
00843 
00844 /*
00845  * Check class restrictions
00846  */
00847 void User::CheckClass()
00848 {
00849         ConnectClass* a = this->MyClass;
00850 
00851         if ((!a) || (a->GetType() == CC_DENY))
00852         {
00853                 ServerInstance->Users->QuitUser(this, "Unauthorised connection");
00854                 return;
00855         }
00856         else if ((a->GetMaxLocal()) && (ServerInstance->Users->LocalCloneCount(this) > a->GetMaxLocal()))
00857         {
00858                 ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (local)");
00859                 ServerInstance->SNO->WriteToSnoMask('A', "WARNING: maximum LOCAL connections (%ld) exceeded for IP %s", a->GetMaxLocal(), this->GetIPString());
00860                 return;
00861         }
00862         else if ((a->GetMaxGlobal()) && (ServerInstance->Users->GlobalCloneCount(this) > a->GetMaxGlobal()))
00863         {
00864                 ServerInstance->Users->QuitUser(this, "No more connections allowed from your host via this connect class (global)");
00865                 ServerInstance->SNO->WriteToSnoMask('A', "WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s", a->GetMaxGlobal(), this->GetIPString());
00866                 return;
00867         }
00868 
00869         this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
00870 }
00871 
00872 bool User::CheckLines()
00873 {
00874         const char* check[] = { "G" , "K", NULL };
00875 
00876         if (!this->exempt)
00877         {
00878                 for (int n = 0; check[n]; ++n)
00879                 {
00880                         XLine *r = ServerInstance->XLines->MatchesLine(check[n], this);
00881 
00882                         if (r)
00883                         {
00884                                 r->Apply(this);
00885                                 return true;
00886                         }
00887                 }
00888         }
00889 
00890         return false;
00891 }
00892 
00893 void User::FullConnect()
00894 {
00895         ServerInstance->stats->statsConnects++;
00896         this->idle_lastmsg = ServerInstance->Time();
00897 
00898         /*
00899          * You may be thinking "wtf, we checked this in User::AddClient!" - and yes, we did, BUT.
00900          * At the time AddClient is called, we don't have a resolved host, by here we probably do - which
00901          * may put the user into a totally seperate class with different restrictions! so we *must* check again.
00902          * Don't remove this! -- w00t
00903          */
00904         this->SetClass();
00905         
00906         /* Check the password, if one is required by the user's connect class.
00907          * This CANNOT be in CheckClass(), because that is called prior to PASS as well!
00908          */
00909         if (this->MyClass && !this->MyClass->GetPass().empty() && !this->haspassed)
00910         {
00911                 ServerInstance->Users->QuitUser(this, "Invalid password");
00912                 return;
00913         }
00914 
00915         if (this->CheckLines())
00916                 return;
00917 
00918         this->WriteServ("NOTICE Auth :Welcome to \002%s\002!",ServerInstance->Config->Network);
00919         this->WriteNumeric(RPL_WELCOME, "%s :Welcome to the %s IRC Network %s!%s@%s",this->nick.c_str(), ServerInstance->Config->Network, this->nick.c_str(), this->ident.c_str(), this->host.c_str());
00920         this->WriteNumeric(RPL_YOURHOSTIS, "%s :Your host is %s, running version InspIRCd-1.2",this->nick.c_str(),ServerInstance->Config->ServerName);
00921         this->WriteNumeric(RPL_SERVERCREATED, "%s :This server was created %s %s", this->nick.c_str(), __TIME__, __DATE__);
00922         this->WriteNumeric(RPL_SERVERVERSION, "%s %s InspIRCd-1.2 %s %s %s", this->nick.c_str(), ServerInstance->Config->ServerName, ServerInstance->Modes->UserModeList().c_str(), ServerInstance->Modes->ChannelModeList().c_str(), ServerInstance->Modes->ParaModeList().c_str());
00923 
00924         ServerInstance->Config->Send005(this);
00925         this->WriteNumeric(RPL_YOURUUID, "%s %s :your unique ID", this->nick.c_str(), this->uuid.c_str());
00926 
00927 
00928         this->ShowMOTD();
00929 
00930         /* Now registered */
00931         if (ServerInstance->Users->unregistered_count)
00932                 ServerInstance->Users->unregistered_count--;
00933 
00934         /* Trigger LUSERS output, give modules a chance too */
00935         int MOD_RESULT = 0;
00936         std::string command("LUSERS");
00937         std::vector<std::string> parameters;
00938         FOREACH_RESULT(I_OnPreCommand, OnPreCommand(command, parameters, this, true, "LUSERS"));
00939         if (!MOD_RESULT)
00940                 ServerInstance->CallCommandHandler(command, parameters, this);
00941 
00942         /*
00943          * We don't set REG_ALL until triggering OnUserConnect, so some module events don't spew out stuff
00944          * for a user that doesn't exist yet.
00945          */
00946         FOREACH_MOD(I_OnUserConnect,OnUserConnect(this));
00947 
00948         this->registered = REG_ALL;
00949 
00950         ServerInstance->PI->Introduce(this);
00951 
00952         FOREACH_MOD(I_OnPostConnect,OnPostConnect(this));
00953 
00954         ServerInstance->SNO->WriteToSnoMask('c',"Client connecting on port %d: %s!%s@%s [%s] [%s]", this->GetPort(), this->nick.c_str(), this->ident.c_str(), this->host.c_str(), this->GetIPString(), this->fullname.c_str());
00955         ServerInstance->Logs->Log("BANCACHE", DEBUG, "BanCache: Adding NEGATIVE hit for %s", this->GetIPString());
00956         ServerInstance->BanCache->AddHit(this->GetIPString(), "", "");
00957 }
00958 
00963 User* User::UpdateNickHash(const char* New)
00964 {
00965         //user_hash::iterator newnick;
00966         user_hash::iterator oldnick = ServerInstance->Users->clientlist->find(this->nick);
00967 
00968         if (!irc::string(this->nick.c_str()).compare(New))
00969                 return oldnick->second;
00970 
00971         if (oldnick == ServerInstance->Users->clientlist->end())
00972                 return NULL; /* doesnt exist */
00973 
00974         User* olduser = oldnick->second;
00975         (*(ServerInstance->Users->clientlist))[New] = olduser;
00976         ServerInstance->Users->clientlist->erase(oldnick);
00977         return olduser;
00978 }
00979 
00980 void User::InvalidateCache()
00981 {
00982         /* Invalidate cache */
00983         cached_fullhost.clear();
00984         cached_hostip.clear();
00985         cached_makehost.clear();
00986         cached_fullrealhost.clear();
00987 }
00988 
00989 bool User::ForceNickChange(const char* newnick)
00990 {
00991         int MOD_RESULT = 0;
00992 
00993         this->InvalidateCache();
00994 
00995         FOREACH_RESULT(I_OnUserPreNick,OnUserPreNick(this, newnick));
00996 
00997         if (MOD_RESULT)
00998         {
00999                 ServerInstance->stats->statsCollisions++;
01000                 return false;
01001         }
01002 
01003         std::deque<classbase*> dummy;
01004         Command* nickhandler = ServerInstance->Parser->GetHandler("NICK");
01005         if (nickhandler) // wtfbbq, when would this not be here
01006         {
01007                 std::vector<std::string> parameters;
01008                 nickhandler->HandleInternal(1, dummy);
01009