operserv.cpp

Go to the documentation of this file.
00001 /* OperServ functions.
00002  *
00003  * (C) 2003-2012 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 
00013 #include "services.h"
00014 #include "modules.h"
00015 #include "oper.h"
00016 #include "users.h"
00017 #include "extern.h"
00018 #include "sockets.h"
00019 #include "regexpr.h"
00020 #include "config.h"
00021 #include "commands.h"
00022 
00023 /* List of XLine managers we check users against in XLineManager::CheckAll */
00024 std::list<XLineManager *> XLineManager::XLineManagers;
00025 serialize_checker<std::multimap<Anope::string, XLine *, ci::less> > XLineManager::XLinesByUID("XLine");
00026 
00027 void XLine::InitRegex()
00028 {
00029         if (!Config->RegexEngine.empty() && this->Mask.length() >= 2 && this->Mask[0] == '/' && this->Mask[this->Mask.length() - 1] == '/')
00030         {
00031                 Anope::string stripped_mask = this->Mask.substr(1, this->Mask.length() - 2);
00032 
00033                 service_reference<RegexProvider> provider("Regex", Config->RegexEngine);
00034                 if (provider)
00035                 {
00036                         try
00037                         {
00038                                 this->regex = provider->Compile(stripped_mask);
00039                         }
00040                         catch (const RegexException &ex)
00041                         {
00042                                 Log(LOG_DEBUG) << ex.GetReason();
00043                         }
00044                 }
00045         }
00046 }
00047 
00048 XLine::XLine(const Anope::string &mask, const Anope::string &reason, const Anope::string &uid) : Serializable("XLine"), Mask(mask), By(Config->OperServ), Created(0), Expires(0), Reason(reason), UID(uid)
00049 {
00050         regex = NULL;
00051         manager = NULL;
00052 
00053         this->InitRegex();
00054 }
00055 
00056 XLine::XLine(const Anope::string &mask, const Anope::string &by, const time_t expires, const Anope::string &reason, const Anope::string &uid) : Serializable("XLine"), Mask(mask), By(by), Created(Anope::CurTime), Expires(expires), Reason(reason), UID(uid)
00057 {
00058         regex = NULL;
00059         manager = NULL;
00060 
00061         this->InitRegex();
00062 }
00063 
00064 XLine::~XLine()
00065 {
00066         delete regex;
00067 }
00068 
00069 Anope::string XLine::GetNick() const
00070 {
00071         size_t nick_t = this->Mask.find('!');
00072 
00073         if (nick_t == Anope::string::npos)
00074                 return "";
00075 
00076         return this->Mask.substr(0, nick_t);
00077 }
00078 
00079 Anope::string XLine::GetUser() const
00080 {
00081         size_t user_t = this->Mask.find('!'), host_t = this->Mask.find('@');
00082 
00083         if (host_t != Anope::string::npos)
00084         {
00085                 if (user_t != Anope::string::npos && host_t > user_t)
00086                         return this->Mask.substr(user_t + 1, host_t - user_t - 1);
00087                 else
00088                         return this->Mask.substr(0, host_t);
00089         }
00090         else
00091                 return "";
00092 }
00093 
00094 Anope::string XLine::GetHost() const
00095 {
00096         size_t host_t = this->Mask.find('@'), real_t = this->Mask.find('#');
00097 
00098         if (host_t != Anope::string::npos)
00099         {
00100                 if (real_t != Anope::string::npos && real_t > host_t)
00101                         return this->Mask.substr(host_t + 1, real_t - host_t - 1);
00102                 else
00103                         return this->Mask.substr(host_t + 1);
00104         }
00105         else
00106                 return "";
00107 }
00108 
00109 Anope::string XLine::GetReal() const
00110 {
00111         size_t real_t = this->Mask.find('#');
00112 
00113         if (real_t != Anope::string::npos)
00114                 return this->Mask.substr(real_t + 1);
00115         else
00116                 return "";
00117 }
00118 
00119 Anope::string XLine::GetReason() const
00120 {
00121         Anope::string r = this->Reason;
00122         if (Config->AddAkiller && !this->By.empty())
00123                 r = "[" + this->By + "] " + r;
00124         if (!this->UID.empty())
00125                 r += " (ID: " + this->UID + ")";
00126         return r;
00127 }
00128 
00129 bool XLine::HasNickOrReal() const
00130 {
00131         bool r = this->GetNick().find_first_not_of("?*") != Anope::string::npos;
00132         r = r || this->GetReal().find_first_not_of("?*") != Anope::string::npos;
00133         return r;
00134 }
00135 
00136 bool XLine::IsRegex() const
00137 {
00138         return !this->Mask.empty() && this->Mask[0] == '/' && this->Mask[this->Mask.length() - 1] == '/';
00139 }
00140 
00141 Serialize::Data XLine::serialize() const
00142 {
00143         Serialize::Data data;   
00144 
00145         data["mask"] << this->Mask;
00146         data["by"] << this->By;
00147         data["created"] << this->Created;
00148         data["expires"] << this->Expires;
00149         data["reason"] << this->Reason;
00150         data["uid"] << this->UID;
00151         if (this->manager)
00152                 data["manager"] << this->manager->name;
00153 
00154         return data;
00155 }
00156 
00157 Serializable* XLine::unserialize(Serializable *obj, Serialize::Data &data)
00158 {
00159         service_reference<XLineManager> xlm("XLineManager", data["manager"].astr());
00160         if (!xlm)
00161                 return NULL;
00162 
00163         XLine *xl;
00164         if (obj)
00165         {
00166                 xl = anope_dynamic_static_cast<XLine *>(obj);
00167                 data["mask"] >> xl->Mask;
00168                 data["by"] >> xl->By;
00169                 data["reason"] >> xl->Reason;
00170                 data["uid"] >> xl->UID;
00171 
00172                 if (xlm != xl->manager)
00173                 {
00174                         xl->manager->DelXLine(xl);
00175                         xlm->AddXLine(xl);
00176                 }
00177         }
00178         else
00179         {
00180                 time_t expires;
00181                 data["expires"] >> expires;
00182                 xl = new XLine(data["mask"].astr(), data["by"].astr(), expires, data["reason"].astr(), data["uid"].astr());
00183                 xlm->AddXLine(xl);
00184         }
00185 
00186         data["created"] >> xl->Created;
00187         xl->manager = xlm;
00188 
00189         return xl;
00190 }
00191 
00198 void XLineManager::RegisterXLineManager(XLineManager *xlm)
00199 {
00200         XLineManagers.push_back(xlm);
00201 }
00202 
00206 void XLineManager::UnregisterXLineManager(XLineManager *xlm)
00207 {
00208         std::list<XLineManager *>::iterator it = std::find(XLineManagers.begin(), XLineManagers.end(), xlm);
00209 
00210         if (it != XLineManagers.end())
00211                 XLineManagers.erase(it);
00212 }
00213 
00214 /* Check a user against all known XLineManagers
00215  * @param u The user
00216  * @return A pair of the XLineManager the user was found in and the XLine they matched, both may be NULL for no match
00217  */
00218 void XLineManager::CheckAll(User *u)
00219 {
00220         for (std::list<XLineManager *>::iterator it = XLineManagers.begin(), it_end = XLineManagers.end(); it != it_end; ++it)
00221         {
00222                 XLineManager *xlm = *it;
00223 
00224                 XLine *x = xlm->CheckAllXLines(u);
00225 
00226                 if (x)
00227                 {
00228                         xlm->OnMatch(u, x);
00229                         break;
00230                 }
00231         }
00232 }
00233 
00234 Anope::string XLineManager::GenerateUID()
00235 {
00236         Anope::string id;
00237         int count = 0;
00238         while (id.empty() || XLinesByUID->count(id) > 0)
00239         {
00240                 if (++count > 10)
00241                 {
00242                         id.clear();
00243                         Log(LOG_DEBUG) << "Unable to generate XLine UID";
00244                         break;
00245                 }
00246 
00247                 for (int i = 0; i < 10; ++i)
00248                 {
00249                         char c;
00250                         do
00251                                 c = (rand() % 75) + 48;
00252                         while (!isupper(c) && !isdigit(c));
00253                         id += c;
00254                 }
00255         }
00256 
00257         return id;
00258 }
00259 
00262 XLineManager::XLineManager(Module *creator, const Anope::string &xname, char t) : Service(creator, "XLineManager", xname), type(t), XLines("XLine")
00263 {
00264 }
00265 
00269 XLineManager::~XLineManager()
00270 {
00271         this->Clear();
00272 }
00273 
00277 const char &XLineManager::Type()
00278 {
00279         return this->type;
00280 }
00281 
00285 size_t XLineManager::GetCount() const
00286 {
00287         return this->XLines->size();
00288 }
00289 
00293 const std::vector<XLine *> &XLineManager::GetList() const
00294 {
00295         return this->XLines;
00296 }
00297 
00301 void XLineManager::AddXLine(XLine *x)
00302 {
00303         if (!x->UID.empty())
00304                 XLinesByUID->insert(std::make_pair(x->UID, x));
00305         this->XLines->push_back(x);
00306         x->manager = this;
00307 }
00308 
00313 bool XLineManager::DelXLine(XLine *x)
00314 {
00315         std::vector<XLine *>::iterator it = std::find(this->XLines->begin(), this->XLines->end(), x);
00316 
00317         if (!x->UID.empty())
00318         {
00319                 std::multimap<Anope::string, XLine *, ci::less>::iterator it2 = XLinesByUID->find(x->UID), it3 = XLinesByUID->upper_bound(x->UID);
00320                 for (; it2 != XLinesByUID->end() && it2 != it3; ++it2)
00321                         if (it2->second == x)
00322                         {
00323                                 XLinesByUID->erase(it2);
00324                                 break;
00325                         }
00326         }
00327 
00328         if (it != this->XLines->end())
00329         {
00330                 this->SendDel(x);
00331 
00332                 x->destroy();
00333                 this->XLines->erase(it);
00334 
00335                 return true;
00336         }
00337 
00338         return false;
00339 }
00340 
00345 XLine* XLineManager::GetEntry(unsigned index)
00346 {
00347         if (index >= this->XLines->size())
00348                 return NULL;
00349 
00350         XLine *x = this->XLines->at(index);
00351         x->QueueUpdate();
00352         return x;
00353 }
00354 
00357 void XLineManager::Clear()
00358 {
00359         for (unsigned i = 0; i < this->XLines->size(); ++i)
00360         {
00361                 XLine *x = this->XLines->at(i);
00362                 if (!x->UID.empty())
00363                         XLinesByUID->erase(x->UID);
00364                 x->destroy();
00365         }
00366         this->XLines->clear();
00367 }
00368 
00376 bool XLineManager::CanAdd(CommandSource &source, const Anope::string &mask, time_t expires, const Anope::string &reason)
00377 {
00378         for (unsigned i = this->GetCount(); i > 0; --i)
00379         {
00380                 XLine *x = this->GetEntry(i - 1);
00381 
00382                 if (x->Mask.equals_ci(mask))
00383                 {
00384                         if (!x->Expires || x->Expires >= expires)
00385                         {
00386                                 if (x->Reason != reason)
00387                                 {
00388                                         x->Reason = reason;
00389                                         source.Reply(_("Reason for %s updated."), x->Mask.c_str());
00390                                 }
00391                                 else
00392                                         source.Reply(_("%s already exists."), mask.c_str());
00393                         }
00394                         else
00395                         {
00396                                 x->Expires = expires;
00397                                 if (x->Reason != reason)
00398                                 {
00399                                         x->Reason = reason;
00400                                         source.Reply(_("Expiry and reason updated for %s."), x->Mask.c_str());
00401                                 }
00402                                 else
00403                                         source.Reply(_("Expiry for %s updated."), x->Mask.c_str());
00404                         }
00405 
00406                         return false;
00407                 }
00408                 else if (Anope::Match(mask, x->Mask) && (!x->Expires || x->Expires >= expires))
00409                 {
00410                         source.Reply(_("%s is already covered by %s."), mask.c_str(), x->Mask.c_str());
00411                         return false;
00412                 }
00413                 else if (Anope::Match(x->Mask, mask) && (!expires || x->Expires <= expires))
00414                 {
00415                         source.Reply(_("Removing %s because %s covers it."), x->Mask.c_str(), mask.c_str());
00416                         this->DelXLine(x);
00417                 }
00418         }
00419 
00420         return true;
00421 }
00422 
00427 XLine* XLineManager::HasEntry(const Anope::string &mask)
00428 {
00429         std::multimap<Anope::string, XLine *, ci::less>::iterator it = XLinesByUID->find(mask);
00430         if (it != XLinesByUID->end())
00431                 for (std::multimap<Anope::string, XLine *, ci::less>::iterator it2 = XLinesByUID->upper_bound(mask); it != it2; ++it)
00432                         if (it->second->manager == NULL || it->second->manager == this)
00433                         {
00434                                 it->second->QueueUpdate();
00435                                 return it->second;
00436                         }
00437         for (unsigned i = 0, end = this->XLines->size(); i < end; ++i)
00438         {
00439                 XLine *x = this->XLines->at(i);
00440 
00441                 if (x->Mask.equals_ci(mask))
00442                 {
00443                         x->QueueUpdate();
00444                         return x;
00445                 }
00446         }
00447 
00448         return NULL;
00449 }
00450 
00455 XLine *XLineManager::CheckAllXLines(User *u)
00456 {
00457         for (unsigned i = this->XLines->size(); i > 0; --i)
00458         {
00459                 XLine *x = this->XLines->at(i - 1);
00460 
00461                 if (x->Expires && x->Expires < Anope::CurTime)
00462                 {
00463                         this->OnExpire(x);
00464                         this->DelXLine(x);
00465                         continue;
00466                 }
00467 
00468                 if (this->Check(u, x))
00469                 {
00470                         this->OnMatch(u, x);
00471                         return x;
00472                 }
00473         }
00474 
00475         return NULL;
00476 }
00477 
00481 void XLineManager::OnExpire(const XLine *x)
00482 {
00483 }
00484