00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "module.h"
00014 #include "../commands/os_session.h"
00015
00016 Anope::string DatabaseFile;
00017 Anope::string BackupFile;
00018 std::stringstream db_buffer;
00019
00020 class DatabaseException : public CoreException
00021 {
00022 public:
00023 DatabaseException(const Anope::string &reason = "") : CoreException(reason) { }
00024
00025 virtual ~DatabaseException() throw() { }
00026 };
00027
00030 enum MDType
00031 {
00032 MD_NONE,
00033 MD_NC,
00034 MD_NA,
00035 MD_BI,
00036 MD_CH
00037 };
00038
00039 static void LoadNickCore(const std::vector<Anope::string> ¶ms);
00040 static void LoadNickAlias(const std::vector<Anope::string> ¶ms);
00041 static void LoadBotInfo(const std::vector<Anope::string> ¶ms);
00042 static void LoadChanInfo(const std::vector<Anope::string> ¶ms);
00043 static void LoadOperInfo(const std::vector<Anope::string> ¶ms);
00044
00045 EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms)
00046 {
00047 Anope::string key = params[0];
00048 std::vector<Anope::string> otherparams = params;
00049 otherparams.erase(otherparams.begin());
00050
00051 if (key.equals_ci("NC"))
00052 LoadNickCore(otherparams);
00053 else if (key.equals_ci("NA"))
00054 LoadNickAlias(otherparams);
00055 else if (key.equals_ci("BI"))
00056 LoadBotInfo(otherparams);
00057 else if (key.equals_ci("CH"))
00058 LoadChanInfo(otherparams);
00059 else if (key.equals_ci("OS"))
00060 LoadOperInfo(otherparams);
00061
00062 return EVENT_CONTINUE;
00063 }
00064
00065 EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms)
00066 {
00067 try
00068 {
00069 if (key.equals_ci("LANGUAGE"))
00070 nc->language = params[0];
00071 else if (key.equals_ci("MEMOMAX"))
00072 nc->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16_t>(params[0]) : -1;
00073 else if (key.equals_ci("EMAIL"))
00074 nc->email = params[0];
00075 else if (key.equals_ci("GREET"))
00076 nc->greet = params[0];
00077 else if (key.equals_ci("ACCESS"))
00078 nc->AddAccess(params[0]);
00079 else if (key.equals_ci("CERT"))
00080 nc->AddCert(params[0]);
00081 else if (key.equals_ci("FLAGS"))
00082 {
00083 for (unsigned i = 0; i < params.size(); ++i)
00084 nc->ExtendMetadata(params[i]);
00085 }
00086 else if (key.equals_ci("MI"))
00087 {
00088 Memo *m = new Memo;
00089 m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0;
00090 m->sender = params[1];
00091 for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j)
00092 {
00093 if (params[j].equals_ci("UNREAD"))
00094 m->unread = true;
00095 else if (params[j].equals_ci("RECEIPT"))
00096 m->receipt = true;
00097 }
00098 m->text = params[params.size() - 1];
00099 nc->memos.memos->push_back(m);
00100 }
00101 else if (key.equals_ci("MIG"))
00102 nc->memos.ignores.push_back(params[0].ci_str());
00103 }
00104 catch (const ConvertException &ex)
00105 {
00106 throw DatabaseException(ex.GetReason());
00107 }
00108 return EVENT_CONTINUE;
00109 }
00110
00111 EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, const std::vector<Anope::string> ¶ms)
00112 {
00113 if (key.equals_ci("LAST_USERMASK"))
00114 na->last_usermask = params[0];
00115 else if (key.equals_ci("LAST_REALHOST"))
00116 na->last_realhost = params[0];
00117 else if (key.equals_ci("LAST_REALNAME"))
00118 na->last_realname = params[0];
00119 else if (key.equals_ci("LAST_QUIT"))
00120 na->last_quit = params[0];
00121 else if (key.equals_ci("FLAGS"))
00122 for (unsigned i = 0; i < params.size(); ++i)
00123 na->ExtendMetadata(params[i]);
00124 else if (key.equals_ci("VHOST"))
00125 na->SetVhost(params.size() > 3 ? params[3] : "", params[2], params[0], params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0);
00126 return EVENT_CONTINUE;
00127 }
00128
00129 EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const std::vector<Anope::string> ¶ms)
00130 {
00131 return EVENT_CONTINUE;
00132 }
00133
00134 EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms)
00135 {
00136 try
00137 {
00138 if (key.equals_ci("BANTYPE"))
00139 ci->bantype = params[0].is_pos_number_only() ? convertTo<int16_t>(params[0]) : Config->CSDefBantype;
00140 else if (key.equals_ci("MEMOMAX"))
00141 ci->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16_t>(params[0]) : -1;
00142 else if (key.equals_ci("FOUNDER"))
00143 ci->SetFounder(NickCore::Find(params[0]));
00144 else if (key.equals_ci("SUCCESSOR"))
00145 ci->SetSuccessor(NickCore::Find(params[0]));
00146 else if (key.equals_ci("LEVELS"))
00147 {
00148 for (unsigned j = 0, end = params.size(); j < end; j += 2)
00149 {
00150 Privilege *p = PrivilegeManager::FindPrivilege(params[j]);
00151 if (p == NULL)
00152 continue;
00153 ci->SetLevel(p->name, params[j + 1].is_number_only() ? convertTo<int16_t>(params[j + 1]) : 0);
00154 }
00155 }
00156 else if (key.equals_ci("FLAGS"))
00157 for (unsigned i = 0; i < params.size(); ++i)
00158 ci->ExtendMetadata(params[i]);
00159 else if (key.equals_ci("DESC"))
00160 ci->desc = params[0];
00161 else if (key.equals_ci("TOPIC"))
00162 {
00163 ci->last_topic_setter = params[0];
00164 ci->last_topic_time = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0;
00165 ci->last_topic = params[2];
00166 }
00167 else if (key.equals_ci("SUSPEND"))
00168 {
00169 ci->ExtendMetadata("suspend:by", params[0]);
00170 ci->ExtendMetadata("suspend:reason", params[1]);
00171 }
00172 else if (key.equals_ci("ACCESS"))
00173 {
00174 ServiceReference<AccessProvider> provider("AccessProvider", "access/access");
00175 if (!provider)
00176 throw DatabaseException("Old access entry for nonexistant provider");
00177
00178 ChanAccess *access = const_cast<ChanAccess *>(provider->Create());
00179 access->ci = ci;
00180 access->mask = params[0];
00181 access->AccessUnserialize(params[1]);
00182 access->last_seen = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0;
00183 access->creator = params[3];
00184 access->created = Anope::CurTime;
00185
00186 ci->AddAccess(access);
00187 }
00188 else if (key.equals_ci("ACCESS2"))
00189 {
00190 ServiceReference<AccessProvider> provider("AccessProvider", params[0]);
00191 if (!provider)
00192 throw DatabaseException("Access entry for nonexistant provider " + params[0]);
00193
00194 ChanAccess *access = const_cast<ChanAccess *>(provider->Create());
00195 access->ci = ci;
00196 access->mask = params[1];
00197 access->AccessUnserialize(params[2]);
00198 access->last_seen = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0;
00199 access->creator = params[4];
00200 access->created = params.size() > 5 && params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime;
00201
00202 ci->AddAccess(access);
00203 }
00204 else if (key.equals_ci("AKICK"))
00205 {
00206
00207 bool Nick = params[1].equals_ci("NICK");
00208 NickCore *nc = NULL;
00209 if (Nick)
00210 {
00211 nc = NickCore::Find(params[2]);
00212 if (!nc)
00213 throw DatabaseException("Akick for nonexistant core " + params[2] + " on " + ci->name);
00214 }
00215
00216 AutoKick *ak;
00217 if (Nick)
00218 ak = ci->AddAkick(params[3], nc, params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0);
00219 else
00220 ak = ci->AddAkick(params[3], params[2], params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0);
00221
00222 }
00223 else if (key.equals_ci("LOG"))
00224 {
00225 LogSetting *l = new LogSetting();
00226
00227 l->ci = ci;
00228 l->service_name = params[0];
00229 l->command_service = params[1];
00230 l->command_name = params[2];
00231 l->method = params[3];
00232 l->creator = params[4];
00233 l->created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime;
00234 l->extra = params.size() > 6 ? params[6] : "";
00235
00236 ci->log_settings->push_back(l);
00237 }
00238 else if (key.equals_ci("MLOCK"))
00239 {
00240 bool set = params[0] == "1" ? true : false;
00241 Anope::string mode_name = params[1].substr(6);
00242 Anope::string setter = params[2];
00243 time_t mcreated = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : Anope::CurTime;
00244 Anope::string param = params.size() > 4 ? params[4] : "";
00245 ci->mode_locks->insert(std::make_pair(mode_name, new ModeLock(ci, set, mode_name, param, setter, mcreated)));
00246 }
00247 else if (key.equals_ci("MI"))
00248 {
00249 Memo *m = new Memo;
00250 m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0;
00251 m->sender = params[1];
00252 for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j)
00253 {
00254 if (params[j].equals_ci("UNREAD"))
00255 m->unread = true;
00256 else if (params[j].equals_ci("RECEIPT"))
00257 m->receipt = true;
00258 }
00259 m->text = params[params.size() - 1];
00260 ci->memos.memos->push_back(m);
00261 }
00262 else if (key.equals_ci("MIG"))
00263 ci->memos.ignores.push_back(params[0].ci_str());
00264 else if (key.equals_ci("BI"))
00265 {
00266 if (params[0].equals_ci("NAME"))
00267 ci->bi = BotInfo::Find(params[1]);
00268 else if (params[0].equals_ci("FLAGS"))
00269 for (unsigned i = 0; i < params.size(); ++i)
00270 ci->ExtendMetadata(params[i]);
00271 else if (params[0].equals_ci("TTB"))
00272 {
00273 for (unsigned j = 1, end = params.size(); j < end; j += 2)
00274 {
00275 if (params[j].equals_ci("BOLDS"))
00276 ci->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00277 else if (params[j].equals_ci("COLORS"))
00278 ci->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00279 else if (params[j].equals_ci("REVERSES"))
00280 ci->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00281 else if (params[j].equals_ci("UNDERLINES"))
00282 ci->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00283 else if (params[j].equals_ci("BADWORDS"))
00284 ci->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00285 else if (params[j].equals_ci("CAPS"))
00286 ci->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00287 else if (params[j].equals_ci("FLOOD"))
00288 ci->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00289 else if (params[j].equals_ci("REPEAT"))
00290 ci->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00291 else if (params[j].equals_ci("ITALICS"))
00292 ci->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00293 else if (params[j].equals_ci("AMSGS"))
00294 ci->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0;
00295 }
00296 }
00297 else if (params[0].equals_ci("CAPSMIN"))
00298 ci->capsmin = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0;
00299 else if (params[0].equals_ci("CAPSPERCENT"))
00300 ci->capspercent = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0;
00301 else if (params[0].equals_ci("FLOODLINES"))
00302 ci->floodlines = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0;
00303 else if (params[0].equals_ci("FLOODSECS"))
00304 ci->floodsecs = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0;
00305 else if (params[0].equals_ci("REPEATTIMES"))
00306 ci->repeattimes = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0;
00307 else if (params[0].equals_ci("BADWORD"))
00308 {
00309 BadWordType Type;
00310 if (params[1].equals_ci("SINGLE"))
00311 Type = BW_SINGLE;
00312 else if (params[1].equals_ci("START"))
00313 Type = BW_START;
00314 else if (params[1].equals_ci("END"))
00315 Type = BW_END;
00316 else
00317 Type = BW_ANY;
00318 ci->AddBadWord(params[2], Type);
00319 }
00320 }
00321 }
00322 catch (const ConvertException &ex)
00323 {
00324 throw DatabaseException(ex.GetReason());
00325 }
00326 return EVENT_CONTINUE;
00327 }
00328
00329
00330
00331
00332
00333 static const char endl = '\n';
00334
00338 static void ReadDatabase(Module *m = NULL)
00339 {
00340
00341 MDType Type = MD_NONE;
00342
00343 std::fstream db;
00344 db.open(DatabaseFile.c_str(), std::ios_base::in);
00345
00346 if (!db.is_open())
00347 {
00348 Log() << "Unable to open " << DatabaseFile << " for reading!";
00349 return;
00350 }
00351
00352 NickCore *nc = NULL;
00353 NickAlias *na = NULL;
00354 BotInfo *bi = NULL;
00355 ChannelInfo *ci = NULL;
00356
00357 Anope::string buf;
00358 while (std::getline(db, buf.str()))
00359 {
00360 if (buf.empty())
00361 continue;
00362
00363 spacesepstream sep(buf);
00364 std::vector<Anope::string> params;
00365 while (sep.GetToken(buf))
00366 {
00367 if (buf[0] == ':')
00368 {
00369 buf.erase(buf.begin());
00370 if (!buf.empty() && !sep.StreamEnd())
00371 params.push_back(buf + " " + sep.GetRemaining());
00372 else if (!sep.StreamEnd())
00373 params.push_back(sep.GetRemaining());
00374 else if (!buf.empty())
00375 params.push_back(buf);
00376 break;
00377 }
00378 else
00379 params.push_back(buf);
00380 }
00381
00382
00383
00384
00385
00386
00387
00388 OnDatabaseRead(params);
00389
00390 if (!params.empty())
00391 {
00392 if (params[0].equals_ci("NC"))
00393 {
00394 nc = NickCore::Find(params[1]);
00395 Type = MD_NC;
00396 }
00397 else if (params[0].equals_ci("NA"))
00398 {
00399 na = NickAlias::Find(params[2]);
00400 Type = MD_NA;
00401 }
00402 else if (params[0].equals_ci("BI"))
00403 {
00404 bi = BotInfo::Find(params[1]);
00405 Type = MD_BI;
00406 }
00407 else if (params[0].equals_ci("CH"))
00408 {
00409 ci = ChannelInfo::Find(params[1]);
00410 Type = MD_CH;
00411 }
00412 else if (params[0].equals_ci("MD"))
00413 {
00414 Anope::string key = params[1];
00415 params.erase(params.begin());
00416 params.erase(params.begin());
00417
00418 if (Type == MD_NC && nc)
00419 {
00420 try
00421 {
00422 OnDatabaseReadMetadata(nc, key, params);
00423 }
00424 catch (const DatabaseException &ex)
00425 {
00426 Log() << "[db_plain]: " << ex.GetReason();
00427 }
00428 }
00429 else if (Type == MD_NA && na)
00430 {
00431 try
00432 {
00433 OnDatabaseReadMetadata(na, key, params);
00434 }
00435 catch (const DatabaseException &ex)
00436 {
00437 Log() << "[db_plain]: " << ex.GetReason();
00438 }
00439 }
00440 else if (Type == MD_BI && bi)
00441 {
00442 try
00443 {
00444 OnDatabaseReadMetadata(bi, key, params);
00445 }
00446 catch (const DatabaseException &ex)
00447 {
00448 Log() << "[db_plain]: " << ex.GetReason();
00449 }
00450 }
00451 else if (Type == MD_CH && ci)
00452 {
00453 try
00454 {
00455 OnDatabaseReadMetadata(ci, key, params);
00456 }
00457 catch (const DatabaseException &ex)
00458 {
00459 Log() << "[db_plain]: " << ex.GetReason();
00460 }
00461 }
00462 }
00463 }
00464 }
00465
00466 db.close();
00467 }
00468
00469 static void LoadNickCore(const std::vector<Anope::string> ¶ms)
00470 {
00471 NickCore *nc = new NickCore(params[0]);
00472
00473 std::deque<Anope::string> list;
00474 nc->GetExtList(list);
00475 for (unsigned i = 0; i < list.size(); ++i)
00476 nc->Shrink(list[i]);
00477
00478 nc->pass = params.size() > 1 ? params[1] : "";
00479
00480 Log(LOG_DEBUG_2) << "[db_plain]: Loaded NickCore " << nc->display;
00481 }
00482
00483 static void LoadNickAlias(const std::vector<Anope::string> ¶ms)
00484 {
00485 NickCore *nc = NickCore::Find(params[0]);
00486 if (!nc)
00487 {
00488 Log() << "[db_plain]: Unable to find core " << params[0];
00489 return;
00490 }
00491
00492 NickAlias *na = new NickAlias(params[1], nc);
00493
00494 na->time_registered = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0;
00495
00496 na->last_seen = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0;
00497
00498 Log(LOG_DEBUG_2) << "[db_plain}: Loaded nickalias for " << na->nick;
00499 }
00500
00501 static void LoadBotInfo(const std::vector<Anope::string> ¶ms)
00502 {
00503 BotInfo *bi = BotInfo::Find(params[0]);
00504 if (!bi)
00505 bi = new BotInfo(params[0], params[1], params[2]);
00506
00507 bi->created = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0;
00508
00509 bi->realname = params[5];
00510
00511 Log(LOG_DEBUG_2) << "[db_plain]: Loaded botinfo for " << bi->nick;
00512 }
00513
00514 static void LoadChanInfo(const std::vector<Anope::string> ¶ms)
00515 {
00516 ChannelInfo *ci = new ChannelInfo(params[0]);
00517
00518 ci->ClearMLock();
00519
00520 std::deque<Anope::string> list;
00521 ci->GetExtList(list);
00522 for (unsigned i = 0; i < list.size(); ++i)
00523 ci->Shrink(list[i]);
00524
00525 ci->time_registered = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0;
00526
00527 ci->last_used = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0;
00528
00529 Log(LOG_DEBUG_2) << "[db_plain]: loaded channel " << ci->name;
00530 }
00531
00532 static void LoadOperInfo(const std::vector<Anope::string> ¶ms)
00533 {
00534 if (params[0].equals_ci("STATS"))
00535 {
00536 MaxUserCount = params[1].is_pos_number_only() ? convertTo<uint32_t>(params[1]) : 0;
00537 MaxUserTime = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0;
00538 }
00539 else if (params[0].equals_ci("SXLINE"))
00540 {
00541 char type = params[1][0];
00542 for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it)
00543 {
00544 XLineManager *xl = *it;
00545 if (xl->Type() == type)
00546 {
00547 Anope::string mask = params[2] + "@" + params[3];
00548 Anope::string by = params[4];
00549 time_t seton = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0;
00550 time_t expires = params[6].is_pos_number_only() ? convertTo<time_t>(params[6]) : 0;
00551 Anope::string reason = params[7];
00552
00553 XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
00554 x->created = seton;
00555 xl->AddXLine(x);
00556 break;
00557 }
00558 }
00559 }
00560 else if (params[0].equals_ci("EXCEPTION") && session_service)
00561 {
00562 Exception *exception = new Exception();
00563 exception->mask = params[1];
00564 exception->limit = params[2].is_pos_number_only() ? convertTo<int>(params[2]) : 1;
00565 exception->who = params[3];
00566 exception->time = params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0;
00567 exception->expires = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0;
00568 exception->reason = params[6];
00569 session_service->AddException(exception);
00570 }
00571 }
00572
00573 void Write(const Anope::string &buf)
00574 {
00575 db_buffer << buf << endl;
00576 }
00577
00578 void WriteMetadata(const Anope::string &key, const Anope::string &data)
00579 {
00580 Write("MD " + key + " " + data);
00581 }
00582
00583 class DBPlain : public Module
00584 {
00585
00586 int LastDay;
00587
00588 std::list<Anope::string> Backups;
00589 public:
00590 DBPlain(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE)
00591 {
00592 this->SetAuthor("Anope");
00593
00594 Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase };
00595 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00596
00597 OnReload();
00598
00599 LastDay = 0;
00600 }
00601
00602 ~DBPlain()
00603 {
00604 }
00605
00606 void BackupDatabase()
00607 {
00608
00609 if (!IsFile(DatabaseFile))
00610 return;
00611
00612 time_t now = Anope::CurTime;
00613 tm *tm = localtime(&now);
00614
00615 if (tm->tm_mday != LastDay)
00616 {
00617 LastDay = tm->tm_mday;
00618 Anope::string newname = BackupFile + "." + stringify(tm->tm_year) + stringify(tm->tm_mon) + stringify(tm->tm_mday);
00619
00620
00621 if (IsFile(newname))
00622 return;
00623
00624 Log(LOG_DEBUG) << "db_plain: Attemping to rename " << DatabaseFile << " to " << newname;
00625 if (rename(DatabaseFile.c_str(), newname.c_str()))
00626 {
00627 Log() << "Unable to back up database!";
00628
00629 if (!Config->NoBackupOkay)
00630 Anope::Quitting = true;
00631
00632 return;
00633 }
00634
00635 Backups.push_back(newname);
00636
00637 unsigned KeepBackups = Config->KeepBackups;
00638 if (KeepBackups && Backups.size() > KeepBackups)
00639 {
00640 unlink(Backups.front().c_str());
00641 Backups.pop_front();
00642 }
00643 }
00644 }
00645
00646 void OnReload() anope_override
00647 {
00648 ConfigReader config;
00649 DatabaseFile = Anope::DataDir + "/" + config.ReadValue("db_plain", "database", "anope.db", 0);
00650 BackupFile = Anope::DataDir + "/backups/" + config.ReadValue("db_plain", "database", "anope.db", 0);
00651 }
00652
00653 EventReturn OnLoadDatabase() anope_override
00654 {
00655 ReadDatabase();
00656
00657
00658 ModuleManager::Detach(I_OnLoadDatabase, this);
00659
00660 return EVENT_STOP;
00661 }
00662
00663
00664 EventReturn OnSaveDatabase() anope_override
00665 {
00666 BackupDatabase();
00667
00668 db_buffer << "VER 2" << endl;
00669
00670 for (nickcore_map::const_iterator nit = NickCoreList->begin(), nit_end = NickCoreList->end(); nit != nit_end; ++nit)
00671 {
00672 const NickCore *nc = nit->second;
00673
00674 db_buffer << "NC " << nc->display << " " << nc->pass << endl;
00675
00676 db_buffer << "MD MEMOMAX " << nc->memos.memomax << endl;
00677
00678 if (!nc->language.empty())
00679 db_buffer << "MD LANGUAGE " << nc->language << endl;
00680 if (!nc->email.empty())
00681 db_buffer << "MD EMAIL " << nc->email << endl;
00682 if (!nc->greet.empty())
00683 db_buffer << "MD GREET :" << nc->greet << endl;
00684
00685 if (!nc->access.empty())
00686 {
00687 for (std::vector<Anope::string>::const_iterator it = nc->access.begin(), it_end = nc->access.end(); it != it_end; ++it)
00688 db_buffer << "MD ACCESS " << *it << endl;
00689 }
00690 if (!nc->cert.empty())
00691 {
00692 for (std::vector<Anope::string>::const_iterator it = nc->cert.begin(), it_end = nc->cert.end(); it != it_end; ++it)
00693 db_buffer << "MD CERT " << *it << endl;
00694 }
00695 db_buffer << "MD FLAGS ";
00696 std::deque<Anope::string> list;
00697 nc->GetExtList(list);
00698 for (unsigned i = 0; i < list.size(); ++i)
00699 db_buffer << list[i] << " ";
00700 db_buffer << std::endl;
00701 const MemoInfo *mi = &nc->memos;
00702 for (unsigned k = 0, end = mi->memos->size(); k < end; ++k)
00703 {
00704 const Memo *m = mi->GetMemo(k);
00705 db_buffer << "MD MI " << m->time << " " << m->sender;
00706 if (m->unread)
00707 db_buffer << " UNREAD";
00708 if (m->receipt)
00709 db_buffer << " RECEIPT";
00710 db_buffer << " :" << m->text << endl;
00711 }
00712 for (unsigned k = 0, end = mi->ignores.size(); k < end; ++k)
00713 db_buffer << "MD MIG " << Anope::string(mi->ignores[k]) << endl;
00714
00715 }
00716
00717 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it)
00718 {
00719 const NickAlias *na = it->second;
00720
00721 db_buffer << "NA " << na->nc->display << " " << na->nick << " " << na->time_registered << " " << na->last_seen << endl;
00722 if (!na->last_usermask.empty())
00723 db_buffer << "MD LAST_USERMASK " << na->last_usermask << endl;
00724 if (!na->last_realhost.empty())
00725 db_buffer << "MD LAST_REALHOST " << na->last_realhost << endl;
00726 if (!na->last_realname.empty())
00727 db_buffer << "MD LAST_REALNAME :" << na->last_realname << endl;
00728 if (!na->last_quit.empty())
00729 db_buffer << "MD LAST_QUIT :" << na->last_quit << endl;
00730 db_buffer << "MD FLAGS ";
00731 std::deque<Anope::string> list;
00732 na->GetExtList(list);
00733 for (unsigned i = 0; i < list.size(); ++i)
00734 db_buffer << list[i] << " ";
00735 db_buffer << std::endl;
00736 if (na->HasVhost())
00737 db_buffer << "MD VHOST " << na->GetVhostCreator() << " " << na->GetVhostCreated() << " " << na->GetVhostHost() << " :" << na->GetVhostIdent() << endl;
00738
00739
00740 }
00741
00742 for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
00743 {
00744 BotInfo *bi = it->second;
00745
00746 if (bi->HasExt("CONF"))
00747 continue;
00748
00749 db_buffer << "BI " << bi->nick << " " << bi->GetIdent() << " " << bi->host << " " << bi->created << " " << bi->GetChannelCount() << " :" << bi->realname << endl;
00750 db_buffer << "MD FLAGS ";
00751 std::deque<Anope::string> list;
00752 bi->GetExtList(list);
00753 for (unsigned i = 0; i < list.size(); ++i)
00754 db_buffer << list[i] << " ";
00755 db_buffer << std::endl;
00756 }
00757
00758 for (registered_channel_map::const_iterator cit = RegisteredChannelList->begin(), cit_end = RegisteredChannelList->end(); cit != cit_end; ++cit)
00759 {
00760 const ChannelInfo *ci = cit->second;
00761
00762 db_buffer << "CH " << ci->name << " " << ci->time_registered << " " << ci->last_used << endl;
00763 db_buffer << "MD BANTYPE " << ci->bantype << endl;
00764 db_buffer << "MD MEMOMAX " << ci->memos.memomax << endl;
00765 if (ci->GetFounder())
00766 db_buffer << "MD FOUNDER " << ci->GetFounder()->display << endl;
00767 if (ci->GetSuccessor())
00768 db_buffer << "MD SUCCESSOR " << ci->GetSuccessor()->display << endl;
00769 if (!ci->desc.empty())
00770 db_buffer << "MD DESC :" << ci->desc << endl;
00771 if (!ci->last_topic.empty())
00772 db_buffer << "MD TOPIC " << ci->last_topic_setter << " " << ci->last_topic_time << " :" << ci->last_topic << endl;
00773 db_buffer << "MD LEVELS";
00774 const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
00775 for (unsigned i = 0; i < privs.size(); ++i)
00776 {
00777 const Privilege &p = privs[i];
00778 db_buffer << p.name << " " << ci->GetLevel(p.name);
00779 }
00780 db_buffer << endl;
00781 std::deque<Anope::string> list;
00782 ci->GetExtList(list);
00783 for (unsigned i = 0; i < list.size(); ++i)
00784 db_buffer << list[i];
00785 db_buffer << std::endl;
00786 if (ci->HasExt("SUSPENDED"))
00787 {
00788 Anope::string *by = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend_by"), *reason = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend_reason");
00789 if (by && reason)
00790 db_buffer << "MD SUSPEND " << *by << " :" << *reason << endl;
00791 }
00792 for (unsigned k = 0, end = ci->GetAccessCount(); k < end; ++k)
00793 {
00794 const ChanAccess *access = ci->GetAccess(k);
00795 db_buffer << "MD ACCESS2 " << access->provider->name << " " << access->mask << " " << access->AccessSerialize() << " " << access->last_seen << " " << access->creator << " " << access->created << endl;
00796 }
00797 for (unsigned k = 0, end = ci->GetAkickCount(); k < end; ++k)
00798 {
00799 db_buffer << "MD AKICK 0 " << (ci->GetAkick(k)->nc ? "NICK " : "MASK ") <<
00800 (ci->GetAkick(k)->nc ? ci->GetAkick(k)->nc->display : ci->GetAkick(k)->mask) << " " << ci->GetAkick(k)->creator << " " << ci->GetAkick(k)->addtime << " " << ci->last_used << " :";
00801 if (!ci->GetAkick(k)->reason.empty())
00802 db_buffer << ci->GetAkick(k)->reason;
00803 db_buffer << endl;
00804 }
00805 for (unsigned k = 0, end = ci->log_settings->size(); k < end; ++k)
00806 {
00807 const LogSetting &l = *ci->log_settings->at(k);
00808
00809 db_buffer << "MD LOG " << l.service_name << " " << l.command_service << " " << l.command_name << " " << l.method << " " << l.creator << " " << l.created << " " << l.extra << endl;
00810 }
00811 for (ChannelInfo::ModeList::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it)
00812 {
00813 const ModeLock &ml = *it->second;
00814 ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name);
00815 if (cm != NULL)
00816 db_buffer << "MD MLOCK " << (ml.set ? 1 : 0) << " " << cm->name << " " << ml.setter << " " << ml.created << " " << ml.param << endl;
00817 }
00818 const MemoInfo *memos = &ci->memos;
00819 for (unsigned k = 0, end = memos->memos->size(); k < end; ++k)
00820 {
00821 const Memo *m = memos->GetMemo(k);
00822 db_buffer << "MD MI " << m->time << " " << m->sender;
00823 if (m->unread)
00824 db_buffer << " UNREAD";
00825 if (m->receipt)
00826 db_buffer << " RECEIPT";
00827 db_buffer << " :" << m->text << endl;
00828 }
00829 for (unsigned k = 0, end = memos->ignores.size(); k < end; ++k)
00830 db_buffer << "MD MIG " << Anope::string(memos->ignores[k]) << endl;
00831 if (ci->bi)
00832 db_buffer << "MD BI NAME " << ci->bi->nick << endl;
00833 db_buffer << "MD BI TTB BOLDS " << ci->ttb[0] << " COLORS " << ci->ttb[1] << " REVERSES " << ci->ttb[2] << " UNDERLINES " << ci->ttb[3] << " BADWORDS " << ci->ttb[4] << " CAPS " << ci->ttb[5] << " FLOOD " << ci->ttb[6] << " REPEAT " << ci->ttb[7] << " ITALICS " << ci->ttb[8] << " AMSGS " << ci->ttb[9] << endl;
00834 if (ci->capsmin)
00835 db_buffer << "MD BI CAPSMIN " << ci->capsmin << endl;
00836 if (ci->capspercent)
00837 db_buffer << "MD BI CAPSPERCENT " << ci->capspercent << endl;
00838 if (ci->floodlines)
00839 db_buffer << "MD BI FLOODLINES " << ci->floodlines << endl;
00840 if (ci->floodsecs)
00841 db_buffer << "MD BI FLOODSECS " << ci->floodsecs << endl;
00842 if (ci->repeattimes)
00843 db_buffer << "MD BI REPEATTIMES " << ci->repeattimes << endl;
00844 for (unsigned k = 0, end = ci->GetBadWordCount(); k < end; ++k)
00845 db_buffer << "MD BI BADWORD " << (ci->GetBadWord(k)->type == BW_ANY ? "ANY " : "") << (ci->GetBadWord(k)->type == BW_SINGLE ? "SINGLE " : "") << (ci->GetBadWord(k)->type == BW_START ? "START " : "") <<
00846 (ci->GetBadWord(k)->type == BW_END ? "END " : "") << ":" << ci->GetBadWord(k)->word << endl;
00847
00848
00849 }
00850
00851 db_buffer << "OS STATS " << MaxUserCount << " " << MaxUserTime << endl;
00852
00853 for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it)
00854 {
00855 XLineManager *xl = *it;
00856 for (unsigned i = 0, end = xl->GetCount(); i < end; ++i)
00857 {
00858 const XLine *x = xl->GetEntry(i);
00859 db_buffer << "OS SXLINE " << xl->Type() << " " << x->GetUser() << " " << x->GetHost() << " " << x->by << " " << x->created << " " << x->expires << " :" << x->reason << endl;
00860 }
00861 }
00862
00863 if (session_service)
00864 for (SessionService::ExceptionVector::iterator it = session_service->GetExceptions().begin(); it != session_service->GetExceptions().end(); ++it)
00865 {
00866 Exception *e = *it;
00867 db_buffer << "OS EXCEPTION " << e->mask << " " << e->limit << " " << e->who << " " << e->time << " " << e->expires << " " << e->reason << endl;
00868 }
00869
00870
00871
00872 std::fstream db;
00873 db.open(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc);
00874
00875 if (!db.is_open())
00876 {
00877 IRCD->SendGlobops(NULL, "Unable to open %s for writing!", DatabaseFile.c_str());
00878 return EVENT_CONTINUE;
00879 }
00880
00881 db << db_buffer.str();
00882 db_buffer.str("");
00883
00884 db.close();
00885
00886 return EVENT_CONTINUE;
00887 }
00888 };
00889
00890 MODULE_INIT(DBPlain)