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

helperfuncs.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 "xline.h"
00018 #include "exitcodes.h"
00019 
00020 std::string InspIRCd::GetServerDescription(const char* servername)
00021 {
00022         std::string description;
00023 
00024         FOREACH_MOD_I(this,I_OnGetServerDescription,OnGetServerDescription(servername,description));
00025 
00026         if (!description.empty())
00027         {
00028                 return description;
00029         }
00030         else
00031         {
00032                 // not a remote server that can be found, it must be me.
00033                 return Config->ServerDesc;
00034         }
00035 }
00036 
00037 /* Find a user record by nickname and return a pointer to it */
00038 User* InspIRCd::FindNick(const std::string &nick)
00039 {
00040         if (!nick.empty() && isdigit(*nick.begin()))
00041                 return FindUUID(nick);
00042 
00043         user_hash::iterator iter = this->Users->clientlist->find(nick);
00044 
00045         if (iter == this->Users->clientlist->end())
00046                 /* Couldn't find it */
00047                 return NULL;
00048 
00049         return iter->second;
00050 }
00051 
00052 User* InspIRCd::FindNick(const char* nick)
00053 {
00054         if (isdigit(*nick))
00055                 return FindUUID(nick);
00056 
00057         user_hash::iterator iter = this->Users->clientlist->find(nick);
00058         
00059         if (iter == this->Users->clientlist->end())
00060                 return NULL;
00061 
00062         return iter->second;
00063 }
00064 
00065 User* InspIRCd::FindNickOnly(const std::string &nick)
00066 {
00067         user_hash::iterator iter = this->Users->clientlist->find(nick);
00068 
00069         if (iter == this->Users->clientlist->end())
00070                 return NULL;
00071 
00072         return iter->second;
00073 }
00074 
00075 User* InspIRCd::FindNickOnly(const char* nick)
00076 {
00077         user_hash::iterator iter = this->Users->clientlist->find(nick);
00078 
00079         if (iter == this->Users->clientlist->end())
00080                 return NULL;
00081 
00082         return iter->second;
00083 }
00084 
00085 User *InspIRCd::FindUUID(const std::string &uid)
00086 {
00087         return FindUUID(uid.c_str());
00088 }
00089 
00090 User *InspIRCd::FindUUID(const char *uid)
00091 {
00092         user_hash::iterator finduuid = this->Users->uuidlist->find(uid);
00093 
00094         if (finduuid == this->Users->uuidlist->end())
00095                 return NULL;
00096 
00097         return finduuid->second;
00098 }
00099 
00100 /* find a channel record by channel name and return a pointer to it */
00101 Channel* InspIRCd::FindChan(const char* chan)
00102 {
00103         chan_hash::iterator iter = chanlist->find(chan);
00104 
00105         if (iter == chanlist->end())
00106                 /* Couldn't find it */
00107                 return NULL;
00108 
00109         return iter->second;
00110 }
00111 
00112 Channel* InspIRCd::FindChan(const std::string &chan)
00113 {
00114         chan_hash::iterator iter = chanlist->find(chan);
00115 
00116         if (iter == chanlist->end())
00117                 /* Couldn't find it */
00118                 return NULL;
00119 
00120         return iter->second;
00121 }
00122 
00123 /* Send an error notice to all users, registered or not */
00124 void InspIRCd::SendError(const std::string &s)
00125 {
00126         for (std::vector<User*>::const_iterator i = this->Users->local_users.begin(); i != this->Users->local_users.end(); i++)
00127         {
00128                 if ((*i)->registered == REG_ALL)
00129                 {
00130                         (*i)->WriteServ("NOTICE %s :%s",(*i)->nick.c_str(),s.c_str());
00131                 }
00132                 else
00133                 {
00134                         /* Unregistered connections receive ERROR, not a NOTICE */
00135                         (*i)->Write("ERROR :" + s);
00136                 }
00137                 /* This might generate a whole load of EAGAIN, but we dont really
00138                  * care about this, as if we call SendError something catastrophic
00139                  * has occured anyway, and we wont receive the events for these.
00140                  */
00141                 (*i)->FlushWriteBuf();
00142         }
00143 }
00144 
00145 /* return channel count */
00146 long InspIRCd::ChannelCount()
00147 {
00148         return chanlist->size();
00149 }
00150 
00151 bool InspIRCd::IsValidMask(const std::string &mask)
00152 {
00153         char* dest = (char*)mask.c_str();
00154         int exclamation = 0;
00155         int atsign = 0;
00156 
00157         for (char* i = dest; *i; i++)
00158         {
00159                 /* out of range character, bad mask */
00160                 if (*i < 32 || *i > 126)
00161                 {
00162                         return false;
00163                 }
00164 
00165                 switch (*i)
00166                 {
00167                         case '!':
00168                                 exclamation++;
00169                                 break;
00170                         case '@':
00171                                 atsign++;
00172                                 break;
00173                 }
00174         }
00175 
00176         /* valid masks only have 1 ! and @ */
00177         if (exclamation != 1 || atsign != 1)
00178                 return false;
00179 
00180         return true;
00181 }
00182 
00183 /* true for valid channel name, false else */
00184 bool IsChannelHandler::Call(const char *chname, size_t max)
00185 {
00186         const char *c = chname + 1;
00187 
00188         /* check for no name - don't check for !*chname, as if it is empty, it won't be '#'! */
00189         if (!chname || *chname != '#')
00190         {
00191                 return false;
00192         }
00193 
00194         while (*c)
00195         {
00196                 switch (*c)
00197                 {
00198                         case ' ':
00199                         case ',':
00200                         case 7:
00201                                 return false;
00202                 }
00203 
00204                 c++;
00205         }
00206 
00207         size_t len = c - chname;        
00208         /* too long a name - note funky pointer arithmetic here. */
00209         if (len > max)
00210         {
00211                         return false;
00212         }
00213 
00214         return true;
00215 }
00216 
00217 /* true for valid nickname, false else */
00218 bool IsNickHandler::Call(const char* n, size_t max)
00219 {
00220         if (!n || !*n)
00221                 return false;
00222  
00223         unsigned int p = 0;
00224         for (const char* i = n; *i; i++, p++)
00225         {
00226                 if ((*i >= 'A') && (*i <= '}'))
00227                 {
00228                         /* "A"-"}" can occur anywhere in a nickname */
00229                         continue;
00230                 }
00231 
00232                 if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
00233                 {
00234                         /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
00235                         continue;
00236                 }
00237 
00238                 /* invalid character! abort */
00239                 return false;
00240         }
00241 
00242         /* too long? or not -- pointer arithmetic rocks */
00243         return (p < max);
00244 }
00245 
00246 /* return true for good ident, false else */
00247 bool IsIdentHandler::Call(const char* n)
00248 {
00249         if (!n || !*n)
00250                 return false;
00251 
00252         for (const char* i = n; *i; i++)
00253         {
00254                 if ((*i >= 'A') && (*i <= '}'))
00255                 {
00256                         continue;
00257                 }
00258 
00259                 if (((*i >= '0') && (*i <= '9')) || (*i == '-') || (*i == '.'))
00260                 {
00261                         continue;
00262                 }
00263 
00264                 return false;
00265         }
00266 
00267         return true;
00268 }
00269 
00270 bool IsSIDHandler::Call(const std::string &str)
00271 {
00272         /* Returns true if the string given is exactly 3 characters long,
00273          * starts with a digit, and the other two characters are A-Z or digits
00274          */
00275         return ((str.length() == 3) && isdigit(str[0]) &&
00276                         ((str[1] >= 'A' && str[1] <= 'Z') || isdigit(str[1])) &&
00277                          ((str[2] >= 'A' && str[2] <= 'Z') || isdigit(str[2])));
00278 }
00279 
00280 /* open the proper logfile */
00281 bool InspIRCd::OpenLog(char**, int)
00282 {
00283         /* This function only happens at startup now */
00284         if (Config->nofork)
00285         {
00286                 this->Logs->SetupNoFork();
00287         }
00288         Config->MyDir = Config->GetFullProgDir();
00289 
00290         /* Attempt to find home directory, portable to windows */
00291         const char* home = getenv("HOME");
00292         if (!home)
00293         {
00294                 /* No $HOME, log to %USERPROFILE% */
00295                 home = getenv("USERPROFILE");
00296                 if (!home)
00297                 {
00298                         /* Nothing could be found at all, log to current dir */
00299                         Config->logpath = "./startup.log";
00300                 }
00301         }
00302 
00303         if (!Config->writelog) return true; // Skip opening default log if -nolog
00304 
00305         if (!*this->LogFileName)
00306         {
00307                 if (Config->logpath.empty())
00308                 {
00309                         std::string path = std::string(home) + "/.inspircd";
00310                         // This tries to create the ~/.inspircd. If it succeeds, then we go ahead and use it.
00311                         // If it fails due to an existing target, then we use it anyway.
00312                         // Either way, we make sure we can get write access to the log at this point.
00313                         if (!mkdir(path.c_str(), 0700) || errno == EEXIST)
00314                         {
00315                                 /* Log to ~/.inspircd/ircd.log */
00316                                 Config->logpath = path + "/startup.log";
00317                                 FILE* fd = fopen(Config->logpath.c_str(), "a+");
00318                                 if (!fd)
00319                                 {
00320                                         // Could not get write access... Why?
00321                                         if (errno == ENOTDIR)
00322                                                 // ~/.inspircd is not actually a directory!
00323                                                 printf("\nWARNING: Unable to create directory: %s (Exists and is not a directory)\n", path.c_str());
00324                                         else
00325                                                 // Not writable for some other reason (no +w access, readonly fs, file too big, whatever).
00326                                                 printf("\nWARNING: No write access to %s (%s)\n", Config->logpath.c_str(), strerror(errno));
00327                                         Config->logpath = "./startup.log";
00328                                 }
00329                                 else
00330                                 {
00331                                         Config->log_file = fd;
00332                                 }
00333                         }
00334                         else
00335                         {
00336                                 /* Couldn't make ~/.inspircd directory, log to current dir */
00337                                 Config->logpath = "./startup.log";
00338                                 printf("\nWARNING: Unable to create directory: %s (%s)\n", path.c_str(), strerror(errno));
00339                         }
00340                 }
00341 
00342                 if (!Config->log_file)
00343                         Config->log_file = fopen(Config->logpath.c_str(),"a+");
00344         }
00345         else
00346         {
00347                 Config->log_file = fopen(this->LogFileName,"a+");
00348         }
00349 
00350         if (!Config->log_file)
00351         {
00352                 return false;
00353         }
00354 
00355         FileWriter* fw = new FileWriter(this, Config->log_file);
00356         FileLogStream *f = new FileLogStream(this, (Config->forcedebug ? DEBUG : DEFAULT), fw);
00357 
00358         this->Logs->AddLogType("*", f, true);
00359 
00360         return true;
00361 }
00362 
00363 void InspIRCd::CheckRoot()
00364 {
00365         if (geteuid() == 0)
00366         {
00367                 printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n");
00368                 this->Logs->Log("STARTUP",DEFAULT,"Cant start as root");
00369                 Exit(EXIT_STATUS_ROOT);
00370         }
00371 }
00372 
00373 void InspIRCd::CheckDie()
00374 {
00375         if (*Config->DieValue)
00376         {
00377                 printf("WARNING: %s\n\n",Config->DieValue);
00378                 this->Logs->Log("CONFIG",DEFAULT,"Died because of <die> tag: %s",Config->DieValue);
00379                 Exit(EXIT_STATUS_DIETAG);
00380         }
00381 }
00382 
00383 void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const std::string &text)
00384 {
00385         std::string copy_text = text;
00386 
00387         int MOD_RESULT = 0;
00388         FOREACH_RESULT_I(this, I_OnWhoisLine, OnWhoisLine(user, dest, numeric, copy_text));
00389 
00390         if (!MOD_RESULT)
00391                 user->WriteServ("%d %s", numeric, copy_text.c_str());
00392 }
00393 
00394 void InspIRCd::SendWhoisLine(User* user, User* dest, int numeric, const char* format, ...)
00395 {
00396         char textbuffer[MAXBUF];
00397         va_list argsPtr;
00398         va_start (argsPtr, format);
00399         vsnprintf(textbuffer, MAXBUF, format, argsPtr);
00400         va_end(argsPtr);
00401 
00402         this->SendWhoisLine(user, dest, numeric, std::string(textbuffer));
00403 }
00404 
00408 long InspIRCd::Duration(const std::string &str)
00409 {
00410         unsigned char multiplier = 0;
00411         long total = 0;
00412         long times = 1;
00413         long subtotal = 0;
00414 
00415         /* Iterate each item in the string, looking for number or multiplier */
00416         for (std::string::const_reverse_iterator i = str.rbegin(); i != str.rend(); ++i)
00417         {
00418                 /* Found a number, queue it onto the current number */
00419                 if ((*i >= '0') && (*i <= '9'))
00420                 {
00421                         subtotal = subtotal + ((*i - '0') * times);
00422                         times = times * 10;
00423                 }
00424                 else
00425                 {
00426                         /* Found something thats not a number, find out how much
00427                          * it multiplies the built up number by, multiply the total
00428                          * and reset the built up number.
00429                          */
00430                         if (subtotal)
00431                                 total += subtotal * duration_multi[multiplier];
00432 
00433                         /* Next subtotal please */
00434                         subtotal = 0;
00435                         multiplier = *i;
00436                         times = 1;
00437                 }
00438         }
00439         if (multiplier)
00440         {
00441                 total += subtotal * duration_multi[multiplier];
00442                 subtotal = 0;
00443         }
00444         /* Any trailing values built up are treated as raw seconds */
00445         return total + subtotal;
00446 }
00447 
00448 bool InspIRCd::ULine(const char* sserver)
00449 {
00450         if (!sserver)
00451                 return false;
00452         if (!*sserver)
00453                 return true;
00454 
00455         return (Config->ulines.find(sserver) != Config->ulines.end());
00456 }
00457 
00458 bool InspIRCd::SilentULine(const char* sserver)
00459 {
00460         std::map<irc::string,bool>::iterator n = Config->ulines.find(sserver);
00461         if (n != Config->ulines.end())
00462                 return n->second;
00463         else return false;
00464 }
00465 
00466 std::string InspIRCd::TimeString(time_t curtime)
00467 {
00468         return std::string(ctime(&curtime),24);
00469 }
00470 
00471 // You should only pass a single character to this.
00472 void InspIRCd::AddExtBanChar(char c)
00473 {
00474         std::string &tok = Config->data005;
00475         std::string::size_type ebpos;
00476         
00477         if ((ebpos = tok.find(" EXTBAN=,")) == std::string::npos)
00478         {
00479                 tok.append(" EXTBAN=,");
00480                 tok.push_back(c);
00481         }
00482         else
00483                 tok.insert(ebpos + 9, 1, c);
00484 }