00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "services.h"
00014 #include "version.h"
00015 #include "modules.h"
00016 #include "lists.h"
00017 #include "config.h"
00018 #include "bots.h"
00019 #include "language.h"
00020 #include "regexpr.h"
00021 #include "sockets.h"
00022
00023 #include <errno.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #ifndef _WIN32
00027 #include <sys/socket.h>
00028 #include <netdb.h>
00029 #endif
00030
00031 NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(true), desc(descending)
00032 {
00033 Anope::string error;
00034 commasepstream sep(list);
00035 Anope::string token;
00036
00037 sep.GetToken(token);
00038 if (token.empty())
00039 token = list;
00040 do
00041 {
00042 size_t t = token.find('-');
00043
00044 if (t == Anope::string::npos)
00045 {
00046 unsigned num = convertTo<unsigned>(token, error, false);
00047 if (error.empty())
00048 numbers.insert(num);
00049 else
00050 {
00051 if (!this->InvalidRange(list))
00052 {
00053 is_valid = false;
00054 return;
00055 }
00056 }
00057 }
00058 else
00059 {
00060 Anope::string error2;
00061 unsigned num1 = convertTo<unsigned>(token.substr(0, t), error, false);
00062 unsigned num2 = convertTo<unsigned>(token.substr(t + 1), error2, false);
00063 if (error.empty() && error2.empty())
00064 {
00065 for (unsigned i = num1; i <= num2; ++i)
00066 numbers.insert(i);
00067 }
00068 else
00069 {
00070 if (!this->InvalidRange(list))
00071 {
00072 is_valid = false;
00073 return;
00074 }
00075 }
00076 }
00077 } while (sep.GetToken(token));
00078 }
00079
00080 NumberList::~NumberList()
00081 {
00082 }
00083
00084 void NumberList::Process()
00085 {
00086 if (!is_valid)
00087 return;
00088
00089 if (this->desc)
00090 {
00091 for (std::set<unsigned>::reverse_iterator it = numbers.rbegin(), it_end = numbers.rend(); it != it_end; ++it)
00092 this->HandleNumber(*it);
00093 }
00094 else
00095 {
00096 for (std::set<unsigned>::iterator it = numbers.begin(), it_end = numbers.end(); it != it_end; ++it)
00097 this->HandleNumber(*it);
00098 }
00099 }
00100
00101 void NumberList::HandleNumber(unsigned)
00102 {
00103 }
00104
00105 bool NumberList::InvalidRange(const Anope::string &)
00106 {
00107 return true;
00108 }
00109
00110 ListFormatter &ListFormatter::AddColumn(const Anope::string &name)
00111 {
00112 this->columns.push_back(name);
00113 return *this;
00114 }
00115
00116 void ListFormatter::AddEntry(const ListEntry &entry)
00117 {
00118 this->entries.push_back(entry);
00119 }
00120
00121 bool ListFormatter::IsEmpty() const
00122 {
00123 return this->entries.empty();
00124 }
00125
00126 void ListFormatter::Process(std::vector<Anope::string> &buffer)
00127 {
00128 std::map<Anope::string, size_t> lenghts;
00129 std::set<Anope::string> breaks;
00130 for (unsigned i = 0; i < this->columns.size(); ++i)
00131 lenghts[this->columns[i]] = this->columns[i].length();
00132 for (unsigned i = 0; i < this->entries.size(); ++i)
00133 {
00134 ListEntry &e = this->entries[i];
00135 for (unsigned j = 0; j < this->columns.size(); ++j)
00136 if (e[this->columns[j]].length() > lenghts[this->columns[j]])
00137 lenghts[this->columns[j]] = e[this->columns[j]].length();
00138 }
00139 unsigned length = 0;
00140 for (std::map<Anope::string, size_t>::iterator it = lenghts.begin(), it_end = lenghts.end(); it != it_end; ++it)
00141 {
00142
00143 if (length > 80)
00144 {
00145 breaks.insert(it->first);
00146 length = 0;
00147 }
00148 else
00149 length += it->second;
00150 }
00151
00152
00153 if (this->columns.size() > 1)
00154 {
00155 Anope::string s;
00156 for (unsigned i = 0; i < this->columns.size(); ++i)
00157 {
00158 if (breaks.count(this->columns[i]))
00159 {
00160 buffer.push_back(s);
00161 s = " ";
00162 }
00163 else if (!s.empty())
00164 s += " ";
00165 s += this->columns[i];
00166 if (i + 1 != this->columns.size())
00167 for (unsigned j = this->columns[i].length(); j < lenghts[this->columns[i]]; ++j)
00168 s += " ";
00169 }
00170 buffer.push_back(s);
00171 }
00172
00173 for (unsigned i = 0; i < this->entries.size(); ++i)
00174 {
00175 ListEntry &e = this->entries[i];
00176
00177 Anope::string s;
00178 for (unsigned j = 0; j < this->columns.size(); ++j)
00179 {
00180 if (breaks.count(this->columns[j]))
00181 {
00182 buffer.push_back(s);
00183 s = " ";
00184 }
00185 else if (!s.empty())
00186 s += " ";
00187 s += e[this->columns[j]];
00188 if (j + 1 != this->columns.size())
00189 for (unsigned k = e[this->columns[j]].length(); k < lenghts[this->columns[j]]; ++k)
00190 s += " ";
00191 }
00192 buffer.push_back(s);
00193 }
00194 }
00195
00196 InfoFormatter::InfoFormatter(NickCore *acc) : nc(acc), longest(0)
00197 {
00198 }
00199
00200 void InfoFormatter::Process(std::vector<Anope::string> &buffer)
00201 {
00202 buffer.clear();
00203
00204 for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = this->replies.begin(), it_end = this->replies.end(); it != it_end; ++it)
00205 {
00206 Anope::string s;
00207 for (unsigned i = it->first.length(); i < this->longest; ++i)
00208 s += " ";
00209 s += Anope::string(Language::Translate(this->nc, it->first.c_str())) + ": " + it->second;
00210
00211 buffer.push_back(s);
00212 }
00213 }
00214
00215 Anope::string& InfoFormatter::operator[](const Anope::string &key)
00216 {
00217 if (key.length() > this->longest)
00218 this->longest = key.length();
00219 this->replies.push_back(std::make_pair(key, ""));
00220 return this->replies.back().second;
00221 }
00222
00223 bool Anope::IsFile(const Anope::string &filename)
00224 {
00225 struct stat fileinfo;
00226 if (!stat(filename.c_str(), &fileinfo))
00227 return true;
00228
00229 return false;
00230 }
00231
00232 time_t Anope::DoTime(const Anope::string &s)
00233 {
00234 if (s.empty())
00235 return -1;
00236
00237 int amount = 0;
00238 Anope::string end;
00239
00240 try
00241 {
00242 amount = convertTo<int>(s, end, false);
00243 if (!end.empty())
00244 {
00245 switch (end[0])
00246 {
00247 case 's':
00248 return amount;
00249 case 'm':
00250 return amount * 60;
00251 case 'h':
00252 return amount * 3600;
00253 case 'd':
00254 return amount * 86400;
00255 case 'w':
00256 return amount * 86400 * 7;
00257 case 'y':
00258 return amount * 86400 * 365;
00259 default:
00260 return -1;
00261 }
00262 }
00263 }
00264 catch (const ConvertException &) { }
00265
00266 return amount;
00267 }
00268
00269 Anope::string Anope::Duration(time_t t, const NickCore *nc)
00270 {
00271
00272 time_t years = t / 31536000;
00273 time_t days = (t / 86400) % 365;
00274 time_t hours = (t / 3600) % 24;
00275 time_t minutes = (t / 60) % 60;
00276 time_t seconds = (t) % 60;
00277
00278 if (!days && !hours && !minutes)
00279 return stringify(seconds) + " " + (seconds != 1 ? Language::Translate(nc, _("seconds")) : Language::Translate(nc, _("second")));
00280 else
00281 {
00282 bool need_comma = false;
00283 Anope::string buffer;
00284 if (years)
00285 {
00286 buffer = stringify(years) + " " + (years != 1 ? Language::Translate(nc, _("years")) : Language::Translate(nc, _("year")));
00287 need_comma = true;
00288 }
00289 if (days)
00290 {
00291 buffer += need_comma ? ", " : "";
00292 buffer += stringify(days) + " " + (days != 1 ? Language::Translate(nc, _("days")) : Language::Translate(nc, _("day")));
00293 need_comma = true;
00294 }
00295 if (hours)
00296 {
00297 buffer += need_comma ? ", " : "";
00298 buffer += stringify(hours) + " " + (hours != 1 ? Language::Translate(nc, _("hours")) : Language::Translate(nc, _("hour")));
00299 need_comma = true;
00300 }
00301 if (minutes)
00302 {
00303 buffer += need_comma ? ", " : "";
00304 buffer += stringify(minutes) + " " + (minutes != 1 ? Language::Translate(nc, _("minutes")) : Language::Translate(nc, _("minute")));
00305 }
00306 return buffer;
00307 }
00308 }
00309
00310 Anope::string Anope::strftime(time_t t, const NickCore *nc, bool short_output)
00311 {
00312 tm tm = *localtime(&t);
00313 char buf[BUFSIZE];
00314 strftime(buf, sizeof(buf), Language::Translate(nc, _("%b %d %H:%M:%S %Y %Z")), &tm);
00315 if (short_output)
00316 return buf;
00317 if (t < Anope::CurTime)
00318 return Anope::string(buf) + " " + Anope::printf(Language::Translate(nc, _("(%s ago)")), Duration(Anope::CurTime - t).c_str(), nc);
00319 else
00320 return Anope::string(buf) + " " + Anope::printf(Language::Translate(nc, _("(%s from now)")), Duration(t - Anope::CurTime).c_str(), nc);
00321 }
00322
00323 Anope::string Anope::Expires(time_t expires, const NickCore *nc)
00324 {
00325 if (!expires)
00326 return Language::Translate(nc, NO_EXPIRE);
00327 else if (expires <= Anope::CurTime)
00328 return Language::Translate(nc, _("expires momentarily"));
00329 else
00330 {
00331 char buf[256];
00332 time_t diff = expires - Anope::CurTime + 59;
00333
00334 if (diff >= 86400)
00335 {
00336 int days = diff / 86400;
00337 snprintf(buf, sizeof(buf), Language::Translate(nc, days == 1 ? _("expires in %d day") : _("expires in %d days")), days);
00338 }
00339 else
00340 {
00341 if (diff <= 3600)
00342 {
00343 int minutes = diff / 60;
00344 snprintf(buf, sizeof(buf), Language::Translate(nc, minutes == 1 ? _("expires in %d minute") : _("expires in %d minutes")), minutes);
00345 }
00346 else
00347 {
00348 int hours = diff / 3600, minutes;
00349 diff -= hours * 3600;
00350 minutes = diff / 60;
00351 snprintf(buf, sizeof(buf), Language::Translate(nc, hours == 1 && minutes == 1 ? _("expires in %d hour, %d minute") : (hours == 1 && minutes != 1 ? _("expires in %d hour, %d minutes") : (hours != 1 && minutes == 1 ? _("expires in %d hours, %d minute") : _("expires in %d hours, %d minutes")))), hours, minutes);
00352 }
00353 }
00354
00355 return buf;
00356 }
00357 }
00358
00359 bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case_sensitive, bool use_regex)
00360 {
00361 size_t s = 0, m = 0, str_len = str.length(), mask_len = mask.length();
00362
00363 if (use_regex && mask_len >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/')
00364 {
00365 Anope::string stripped_mask = mask.substr(1, mask_len - 2);
00366
00367 static Regex *r = NULL;
00368
00369 if (r == NULL || r->GetExpression() != stripped_mask)
00370 {
00371 ServiceReference<RegexProvider> provider("Regex", Config->RegexEngine);
00372 if (provider)
00373 {
00374 try
00375 {
00376 delete r;
00377 r = NULL;
00378
00379 r = provider->Compile(stripped_mask);
00380 }
00381 catch (const RegexException &ex)
00382 {
00383 Log(LOG_DEBUG) << ex.GetReason();
00384 }
00385 }
00386 else
00387 {
00388 delete r;
00389 r = NULL;
00390 }
00391 }
00392
00393 if (r != NULL && r->Matches(str))
00394 return true;
00395
00396
00397 }
00398
00399 while (s < str_len && m < mask_len && mask[m] != '*')
00400 {
00401 char string = str[s], wild = mask[m];
00402 if (case_sensitive)
00403 {
00404 if (wild != string && wild != '?')
00405 return false;
00406 }
00407 else
00408 {
00409 if (tolower(wild) != tolower(string) && wild != '?')
00410 return false;
00411 }
00412
00413 ++m;
00414 ++s;
00415 }
00416
00417 size_t sp = Anope::string::npos, mp = Anope::string::npos;
00418 while (s < str_len)
00419 {
00420 char string = str[s], wild = mask[m];
00421 if (wild == '*')
00422 {
00423 if (++m == mask_len)
00424 return 1;
00425
00426 mp = m;
00427 sp = s + 1;
00428 }
00429 else if (case_sensitive)
00430 {
00431 if (wild == string || wild == '?')
00432 {
00433 ++m;
00434 ++s;
00435 }
00436 else
00437 {
00438 m = mp;
00439 s = sp++;
00440 }
00441 }
00442 else
00443 {
00444 if (tolower(wild) == tolower(string) || wild == '?')
00445 {
00446 ++m;
00447 ++s;
00448 }
00449 else
00450 {
00451 m = mp;
00452 s = sp++;
00453 }
00454 }
00455 }
00456
00457 if (m < mask_len && mask[m] == '*')
00458 ++m;
00459
00460 return m == mask_len;
00461 }
00462
00463 void Anope::Encrypt(const Anope::string &src, Anope::string &dest)
00464 {
00465 EventReturn MOD_RESULT;
00466 FOREACH_RESULT(I_OnEncrypt, OnEncrypt(src, dest));
00467 }
00468
00469 bool Anope::Decrypt(const Anope::string &src, Anope::string &dest)
00470 {
00471 size_t pos = src.find(':');
00472 if (pos == Anope::string::npos)
00473 {
00474 Log() << "Error: Anope::Decrypt() called with invalid password string (" << src << ")";
00475 return false;
00476 }
00477 Anope::string hashm(src.begin(), src.begin() + pos);
00478
00479 EventReturn MOD_RESULT;
00480 FOREACH_RESULT(I_OnDecrypt, OnDecrypt(hashm, src, dest));
00481 if (MOD_RESULT == EVENT_ALLOW)
00482 return true;
00483
00484 return false;
00485 }
00486
00487 Anope::string Anope::printf(const char *fmt, ...)
00488 {
00489 va_list args;
00490 char buf[1024];
00491 va_start(args, fmt);
00492 vsnprintf(buf, sizeof(buf), fmt, args);
00493 va_end(args);
00494 return buf;
00495 }
00496
00497 Anope::string Anope::Hex(const Anope::string &data)
00498 {
00499 const char hextable[] = "0123456789abcdef";
00500
00501 size_t l = data.length();
00502 Anope::string rv;
00503 for (size_t i = 0; i < l; ++i)
00504 {
00505 unsigned char c = data[i];
00506 rv += hextable[c >> 4];
00507 rv += hextable[c & 0xF];
00508 }
00509 return rv;
00510 }
00511
00512 Anope::string Anope::Hex(const char *data, unsigned len)
00513 {
00514 const char hextable[] = "0123456789abcdef";
00515
00516 Anope::string rv;
00517 for (size_t i = 0; i < len; ++i)
00518 {
00519 unsigned char c = data[i];
00520 rv += hextable[c >> 4];
00521 rv += hextable[c & 0xF];
00522 }
00523 return rv;
00524 }
00525
00526 void Anope::Unhex(const Anope::string &src, Anope::string &dest)
00527 {
00528 size_t len = src.length();
00529 Anope::string rv;
00530 for (size_t i = 0; i + 1 < len; i += 2)
00531 {
00532 char h = std::tolower(src[i], Anope::casemap), l = std::tolower(src[i + 1], Anope::casemap);
00533 unsigned char byte = (h >= 'a' ? h - 'a' + 10 : h - '0') << 4;
00534 byte += (l >= 'a' ? l - 'a' + 10 : l - '0');
00535 rv += byte;
00536 }
00537 dest = rv;
00538 }
00539
00540 void Anope::Unhex(const Anope::string &src, char *dest, size_t sz)
00541 {
00542 Anope::string d;
00543 Anope::Unhex(src, d);
00544
00545 memcpy(dest, d.c_str(), std::min(d.length() + 1, sz));
00546 }
00547
00548 int Anope::LastErrorCode()
00549 {
00550 #ifndef _WIN32
00551 return errno;
00552 #else
00553 return GetLastError();
00554 #endif
00555 }
00556
00557 const Anope::string Anope::LastError()
00558 {
00559 #ifndef _WIN32
00560 return strerror(errno);
00561 #else
00562 char errbuf[513];
00563 DWORD err = GetLastError();
00564 if (!err)
00565 return "";
00566 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, errbuf, 512, NULL);
00567 return errbuf;
00568 #endif
00569 }
00570
00571 ModuleVersion Module::GetVersion() const
00572 {
00573 return ModuleVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
00574 }
00575
00576 Anope::string Anope::Version()
00577 {
00578 #ifdef VERSION_GIT
00579 return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH) + VERSION_EXTRA + " (" + VERSION_GIT + ")";
00580 #else
00581 return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH) + VERSION_EXTRA;
00582 #endif
00583 }
00584
00585 Anope::string Anope::VersionShort()
00586 {
00587 return stringify(VERSION_MAJOR) + "." + stringify(VERSION_MINOR) + "." + stringify(VERSION_PATCH);
00588 }
00589
00590 Anope::string Anope::VersionBuildString()
00591 {
00592 Anope::string s = "build #" + stringify(BUILD) + ", compiled " + Anope::compiled;
00593 Anope::string flags;
00594
00595 #ifdef DEBUG_BUILD
00596 flags += "D";
00597 #endif
00598 #ifdef VERSION_GIT
00599 flags += "G";
00600 #endif
00601 #ifdef _WIN32
00602 flags += "W";
00603 #endif
00604
00605 if (!flags.empty())
00606 s += ", flags " + flags;
00607
00608 return s;
00609 }
00610
00611 int Anope::VersionMajor() { return VERSION_MAJOR; }
00612 int Anope::VersionMinor() { return VERSION_MINOR; }
00613 int Anope::VersionPatch() { return VERSION_PATCH; }
00614
00615 Anope::string Anope::NormalizeBuffer(const Anope::string &buf)
00616 {
00617 Anope::string newbuf;
00618
00619 for (unsigned i = 0, end = buf.length(); i < end; ++i)
00620 {
00621 switch (buf[i])
00622 {
00623
00624 case 1:
00625
00626 case 2:
00627 break;
00628
00629 case 3:
00630
00631 if (isdigit(buf[i + 1]))
00632 {
00633 ++i;
00634
00635
00636
00637
00638
00639 if (isdigit(buf[i + 1]))
00640 ++i;
00641
00642
00643
00644
00645 if (buf[i + 1] == ',')
00646 {
00647 ++i;
00648
00649 if (isdigit(buf[i + 1]))
00650 ++i;
00651
00652
00653
00654
00655 if (isdigit(buf[i + 1]))
00656 ++i;
00657 }
00658 }
00659
00660 break;
00661
00662 case 10:
00663
00664 case 13:
00665
00666 case 22:
00667
00668 case 29:
00669
00670 case 31:
00671 break;
00672
00673 default:
00674 newbuf += buf[i];
00675 }
00676 }
00677
00678 return newbuf;
00679 }
00680
00681 Anope::string Anope::Resolve(const Anope::string &host, int type)
00682 {
00683 Anope::string result = host;
00684
00685 addrinfo hints;
00686 memset(&hints, 0, sizeof(hints));
00687 hints.ai_family = type;
00688
00689 Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: Looking up " << host;
00690
00691 addrinfo *addrresult = NULL;
00692 if (getaddrinfo(host.c_str(), NULL, &hints, &addrresult) == 0)
00693 {
00694 sockaddrs addr;
00695 memcpy(&addr, addrresult->ai_addr, addrresult->ai_addrlen);
00696 try
00697 {
00698 result = addr.addr();
00699 Log(LOG_DEBUG_2) << "Resolver: " << host << " -> " << result;
00700 }
00701 catch (const SocketException &) { }
00702
00703 freeaddrinfo(addrresult);
00704 }
00705
00706 return result;
00707 }
00708