anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

db_old.cpp (31723B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "module.h"
     13 #include "modules/os_session.h"
     14 #include "modules/bs_kick.h"
     15 #include "modules/cs_mode.h"
     16 #include "modules/bs_badwords.h"
     17 #include "modules/os_news.h"
     18 #include "modules/suspend.h"
     19 #include "modules/os_forbid.h"
     20 #include "modules/cs_entrymsg.h"
     21 
     22 #define READ(x) \
     23 if (true) \
     24 { \
     25 	if ((x) < 0) \
     26 		printf("Error, the database is broken, line %d, trying to continue... no guarantee.\n", __LINE__); \
     27 } \
     28 else \
     29 	static_cast<void>(0)
     30 
     31 #define getc_db(f) (fgetc((f)->fp))
     32 #define read_db(f, buf, len) (fread((buf), 1, (len), (f)->fp))
     33 #define read_buffer(buf, f) ((read_db((f), (buf), sizeof(buf)) == sizeof(buf)) ? 0 : -1)
     34 
     35 #define OLD_BI_PRIVATE	0x0001
     36 
     37 #define OLD_NI_KILLPROTECT	0x00000001 /* Kill others who take this nick */
     38 #define OLD_NI_SECURE		0x00000002 /* Don't recognize unless IDENTIFY'd */
     39 #define OLD_NI_MSG			0x00000004 /* Use PRIVMSGs instead of NOTICEs */
     40 #define OLD_NI_MEMO_HARDMAX	0x00000008 /* Don't allow user to change memo limit */
     41 #define OLD_NI_MEMO_SIGNON	0x00000010 /* Notify of memos at signon and un-away */
     42 #define OLD_NI_MEMO_RECEIVE	0x00000020 /* Notify of new memos when sent */
     43 #define OLD_NI_PRIVATE		0x00000040 /* Don't show in LIST to non-servadmins */
     44 #define OLD_NI_HIDE_EMAIL	0x00000080 /* Don't show E-mail in INFO */
     45 #define OLD_NI_HIDE_MASK	0x00000100 /* Don't show last seen address in INFO */
     46 #define OLD_NI_HIDE_QUIT	0x00000200 /* Don't show last quit message in INFO */
     47 #define OLD_NI_KILL_QUICK	0x00000400 /* Kill in 20 seconds instead of 60 */
     48 #define OLD_NI_KILL_IMMED	0x00000800 /* Kill immediately instead of in 60 sec */
     49 #define OLD_NI_MEMO_MAIL	0x00010000 /* User gets email on memo */
     50 #define OLD_NI_HIDE_STATUS	0x00020000 /* Don't show services access status */
     51 #define OLD_NI_SUSPENDED	0x00040000 /* Nickname is suspended */
     52 #define OLD_NI_AUTOOP		0x00080000 /* Autoop nickname in channels */
     53 
     54 #define OLD_NS_NO_EXPIRE		0x0004     /* nick won't expire */
     55 #define OLD_NS_VERBOTEN			0x0002
     56 
     57 #define OLD_CI_KEEPTOPIC		0x00000001
     58 #define OLD_CI_SECUREOPS		0x00000002
     59 #define OLD_CI_PRIVATE			0x00000004
     60 #define OLD_CI_TOPICLOCK		0x00000008
     61 #define OLD_CI_RESTRICTED		0x00000010
     62 #define OLD_CI_PEACE			0x00000020
     63 #define OLD_CI_SECURE			0x00000040
     64 #define OLD_CI_VERBOTEN			0x00000080
     65 #define OLD_CI_ENCRYPTEDPW		0x00000100
     66 #define OLD_CI_NO_EXPIRE		0x00000200
     67 #define OLD_CI_MEMO_HARDMAX		0x00000400
     68 #define OLD_CI_OPNOTICE			0x00000800
     69 #define OLD_CI_SECUREFOUNDER	0x00001000
     70 #define OLD_CI_SIGNKICK			0x00002000
     71 #define OLD_CI_SIGNKICK_LEVEL	0x00004000
     72 #define OLD_CI_XOP				0x00008000
     73 #define OLD_CI_SUSPENDED		0x00010000
     74 
     75 /* BotServ SET flags */
     76 #define OLD_BS_DONTKICKOPS		0x00000001
     77 #define OLD_BS_DONTKICKVOICES	0x00000002
     78 #define OLD_BS_FANTASY			0x00000004
     79 #define OLD_BS_SYMBIOSIS		0x00000008
     80 #define OLD_BS_GREET			0x00000010
     81 #define OLD_BS_NOBOT			0x00000020
     82 
     83 /* BotServ Kickers flags */
     84 #define OLD_BS_KICK_BOLDS		0x80000000
     85 #define OLD_BS_KICK_COLORS		0x40000000
     86 #define OLD_BS_KICK_REVERSES	0x20000000
     87 #define OLD_BS_KICK_UNDERLINES	0x10000000
     88 #define OLD_BS_KICK_BADWORDS	0x08000000
     89 #define OLD_BS_KICK_CAPS		0x04000000
     90 #define OLD_BS_KICK_FLOOD		0x02000000
     91 #define OLD_BS_KICK_REPEAT		0x01000000
     92 
     93 #define OLD_NEWS_LOGON	0
     94 #define OLD_NEWS_OPER	1
     95 #define OLD_NEWS_RANDOM	2
     96 
     97 static struct mlock_info
     98 {
     99 	char c;
    100 	uint32_t m;
    101 } mlock_infos[] = {
    102 	{'i', 0x00000001},
    103 	{'m', 0x00000002},
    104 	{'n', 0x00000004},
    105 	{'p', 0x00000008},
    106 	{'s', 0x00000010},
    107 	{'t', 0x00000020},
    108 	{'R', 0x00000100},
    109 	{'r', 0x00000200},
    110 	{'c', 0x00000400},
    111 	{'A', 0x00000800},
    112 	{'K', 0x00002000},
    113 	{'O', 0x00008000},
    114 	{'Q', 0x00010000},
    115 	{'S', 0x00020000},
    116 	{'G', 0x00100000},
    117 	{'C', 0x00200000},
    118 	{'u', 0x00400000},
    119 	{'z', 0x00800000},
    120 	{'N', 0x01000000},
    121 	{'M', 0x04000000}
    122 };
    123 
    124 static Anope::string hashm;
    125 
    126 enum
    127 {
    128 	LANG_EN_US, /* United States English */
    129 	LANG_JA_JIS, /* Japanese (JIS encoding) */
    130 	LANG_JA_EUC, /* Japanese (EUC encoding) */
    131 	LANG_JA_SJIS, /* Japanese (SJIS encoding) */
    132 	LANG_ES, /* Spanish */
    133 	LANG_PT, /* Portugese */
    134 	LANG_FR, /* French */
    135 	LANG_TR, /* Turkish */
    136 	LANG_IT, /* Italian */
    137 	LANG_DE, /* German */
    138 	LANG_CAT, /* Catalan */
    139 	LANG_GR, /* Greek */
    140 	LANG_NL, /* Dutch */
    141 	LANG_RU, /* Russian */
    142 	LANG_HUN, /* Hungarian */
    143 	LANG_PL /* Polish */
    144 };
    145 
    146 static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status, uint32_t *limit, Anope::string *key)
    147 {
    148 	ModeLocks *ml = ci->Require<ModeLocks>("modelocks");
    149 	for (unsigned i = 0; i < (sizeof(mlock_infos) / sizeof(mlock_info)); ++i)
    150 		if (lock & mlock_infos[i].m)
    151 		{
    152 			ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock_infos[i].c);
    153 			if (cm && ml)
    154 			{
    155 				if (limit && mlock_infos[i].c == 'l')
    156 					ml->SetMLock(cm, status, stringify(*limit));
    157 				else if (key && mlock_infos[i].c == 'k')
    158 					ml->SetMLock(cm, status, *key);
    159 				else
    160 					ml->SetMLock(cm, status);
    161 			}
    162 		}
    163 }
    164 
    165 static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    166 static const char Pad64 = '=';
    167 
    168 static void my_b64_encode(const Anope::string &src, Anope::string &target)
    169 {
    170 	size_t src_pos = 0, src_len = src.length();
    171 	unsigned char input[3];
    172 
    173 	target.clear();
    174 
    175 	while (src_len - src_pos > 2)
    176 	{
    177 		input[0] = src[src_pos++];
    178 		input[1] = src[src_pos++];
    179 		input[2] = src[src_pos++];
    180 
    181 		target += Base64[input[0] >> 2];
    182 		target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
    183 		target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
    184 		target += Base64[input[2] & 0x3f];
    185 	}
    186 
    187 	/* Now we worry about padding */
    188 	if (src_pos != src_len)
    189 	{
    190 		input[0] = input[1] = input[2] = 0;
    191 		for (size_t i = 0; i < src_len - src_pos; ++i)
    192 			input[i] = src[src_pos + i];
    193 
    194 		target += Base64[input[0] >> 2];
    195 		target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
    196 		if (src_pos == src_len - 1)
    197 			target += Pad64;
    198 		else
    199 			target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
    200 		target += Pad64;
    201 	}
    202 }
    203 
    204 static Anope::string Hex(const char *data, size_t l)
    205 {
    206 	const char hextable[] = "0123456789abcdef";
    207 
    208 	std::string rv;
    209 	for (size_t i = 0; i < l; ++i)
    210 	{
    211 		unsigned char c = data[i];
    212 		rv += hextable[c >> 4];
    213 		rv += hextable[c & 0xF];
    214 	}
    215 	return rv;
    216 }
    217 
    218 static Anope::string GetLevelName(int level)
    219 {
    220 	switch (level)
    221 	{
    222 		case 0:
    223 			return "INVITE";
    224 		case 1:
    225 			return "AKICK";
    226 		case 2:
    227 			return "SET";
    228 		case 3:
    229 			return "UNBAN";
    230 		case 4:
    231 			return "AUTOOP";
    232 		case 5:
    233 			return "AUTODEOP";
    234 		case 6:
    235 			return "AUTOVOICE";
    236 		case 7:
    237 			return "OP";
    238 		case 8:
    239 			return "ACCESS_LIST";
    240 		case 9:
    241 			return "CLEAR";
    242 		case 10:
    243 			return "NOJOIN";
    244 		case 11:
    245 			return "ACCESS_CHANGE";
    246 		case 12:
    247 			return "MEMO";
    248 		case 13:
    249 			return "ASSIGN";
    250 		case 14:
    251 			return "BADWORDS";
    252 		case 15:
    253 			return "NOKICK";
    254 		case 16:
    255 			return "FANTASIA";
    256 		case 17:
    257 			return "SAY";
    258 		case 18:
    259 			return "GREET";
    260 		case 19:
    261 			return "VOICEME";
    262 		case 20:
    263 			return "VOICE";
    264 		case 21:
    265 			return "GETKEY";
    266 		case 22:
    267 			return "AUTOHALFOP";
    268 		case 23:
    269 			return "AUTOPROTECT";
    270 		case 24:
    271 			return "OPME";
    272 		case 25:
    273 			return "HALFOPME";
    274 		case 26:
    275 			return "HALFOP";
    276 		case 27:
    277 			return "PROTECTME";
    278 		case 28:
    279 			return "PROTECT";
    280 		case 29:
    281 			return "KICKME";
    282 		case 30:
    283 			return "KICK";
    284 		case 31:
    285 			return "SIGNKICK";
    286 		case 32:
    287 			return "BANME";
    288 		case 33:
    289 			return "BAN";
    290 		case 34:
    291 			return "TOPIC";
    292 		case 35:
    293 			return "INFO";
    294 		default:
    295 			return "INVALID";
    296 	}
    297 }
    298 
    299 static char *strscpy(char *d, const char *s, size_t len)
    300 {
    301 	char *d_orig = d;
    302 
    303 	if (!len)
    304 		return d;
    305 	while (--len && (*d++ = *s++));
    306 	*d = '\0';
    307 	return d_orig;
    308 }
    309 
    310 struct dbFILE
    311 {
    312 	int mode;				/* 'r' for reading, 'w' for writing */
    313 	FILE *fp;				/* The normal file descriptor */
    314 	char filename[1024];	/* Name of the database file */
    315 };
    316 
    317 static dbFILE *open_db_read(const char *service, const char *filename, int version)
    318 {
    319 	dbFILE *f;
    320 	FILE *fp;
    321 	int myversion;
    322 
    323 	f = new dbFILE;
    324 	strscpy(f->filename, (Anope::DataDir + "/" + filename).c_str(), sizeof(f->filename));
    325 	f->mode = 'r';
    326 	fp = fopen(f->filename, "rb");
    327 	if (!fp)
    328 	{
    329 		Log() << "Can't read " << service << " database " << f->filename;
    330 		delete f;
    331 		return NULL;
    332 	}
    333 	f->fp = fp;
    334 	myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
    335 	if (feof(fp))
    336 	{
    337 		Log() << "Error reading version number on " << f->filename << ": End of file detected.";
    338 		delete f;
    339 		return NULL;
    340 	}
    341 	else if (myversion < version)
    342 	{
    343 		Log() << "Unsupported database version (" << myversion << ") on " << f->filename << ".";
    344 		delete f;
    345 		return NULL;
    346 	}
    347 	return f;
    348 }
    349 
    350 void close_db(dbFILE *f)
    351 {
    352 	fclose(f->fp);
    353 	delete f;
    354 }
    355 
    356 static int read_int16(int16_t *ret, dbFILE *f)
    357 {
    358 	int c1, c2;
    359 
    360 	*ret = 0;
    361 
    362 	c1 = fgetc(f->fp);
    363 	c2 = fgetc(f->fp);
    364 	if (c1 == EOF || c2 == EOF)
    365 		return -1;
    366 	*ret = c1 << 8 | c2;
    367 	return 0;
    368 }
    369 
    370 static int read_uint16(uint16_t *ret, dbFILE *f)
    371 {
    372 	int c1, c2;
    373 
    374 	*ret = 0;
    375 
    376 	c1 = fgetc(f->fp);
    377 	c2 = fgetc(f->fp);
    378 	if (c1 == EOF || c2 == EOF)
    379 		return -1;
    380 	*ret = c1 << 8 | c2;
    381 	return 0;
    382 }
    383 
    384 static int read_string(Anope::string &str, dbFILE *f)
    385 {
    386 	str.clear();
    387 	uint16_t len;
    388 
    389 	if (read_uint16(&len, f) < 0)
    390 		return -1;
    391 	if (len == 0)
    392 		return 0;
    393 	char *s = new char[len];
    394 	if (len != fread(s, 1, len, f->fp))
    395 	{
    396 		delete [] s;
    397 		return -1;
    398 	}
    399 	str = s;
    400 	delete [] s;
    401 	return 0;
    402 }
    403 
    404 static int read_uint32(uint32_t *ret, dbFILE *f)
    405 {
    406 	int c1, c2, c3, c4;
    407 
    408 	*ret = 0;
    409 
    410 	c1 = fgetc(f->fp);
    411 	c2 = fgetc(f->fp);
    412 	c3 = fgetc(f->fp);
    413 	c4 = fgetc(f->fp);
    414 	if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
    415 		return -1;
    416 	*ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
    417 	return 0;
    418 }
    419 
    420 int read_int32(int32_t *ret, dbFILE *f)
    421 {
    422 	int c1, c2, c3, c4;
    423 
    424 	*ret = 0;
    425 
    426 	c1 = fgetc(f->fp);
    427 	c2 = fgetc(f->fp);
    428 	c3 = fgetc(f->fp);
    429 	c4 = fgetc(f->fp);
    430 	if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
    431 		return -1;
    432 	*ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
    433 	return 0;
    434 }
    435 
    436 static void LoadNicks()
    437 {
    438 	ServiceReference<ForbidService> forbid("ForbidService", "forbid");
    439 	dbFILE *f = open_db_read("NickServ", "nick.db", 14);
    440 	if (f == NULL)
    441 		return;
    442 	for (int i = 0; i < 1024; ++i)
    443 		for (int c; (c = getc_db(f)) == 1;)
    444 		{
    445 			Anope::string buffer;
    446 
    447 			READ(read_string(buffer, f));
    448 			NickCore *nc = new NickCore(buffer);
    449 
    450 			const Anope::string settings[] = { "killprotect", "kill_quick", "ns_secure", "ns_private", "hide_email",
    451 				"hide_mask", "hide_quit", "memo_signon", "memo_receive", "autoop", "msg", "ns_keepmodes" };
    452 			for (unsigned j = 0; j < sizeof(settings) / sizeof(Anope::string); ++j)
    453 				nc->Shrink<bool>(settings[j].upper());
    454 
    455 			char pwbuf[32];
    456 			READ(read_buffer(pwbuf, f));
    457 			if (hashm == "plain")
    458 				my_b64_encode(pwbuf, nc->pass);
    459 			else if (hashm == "md5" || hashm == "oldmd5")
    460 				nc->pass = Hex(pwbuf, 16);
    461 			else if (hashm == "sha1")
    462 				nc->pass = Hex(pwbuf, 20);
    463 			else
    464 				nc->pass = Hex(pwbuf, strlen(pwbuf));
    465 			nc->pass = hashm + ":" + nc->pass;
    466 
    467 			READ(read_string(buffer, f));
    468 			nc->email = buffer;
    469 
    470 			READ(read_string(buffer, f));
    471 			if (!buffer.empty())
    472 				nc->Extend<Anope::string>("greet", buffer);
    473 
    474 			uint32_t u32;
    475 			READ(read_uint32(&u32, f));
    476 			//nc->icq = u32;
    477 
    478 			READ(read_string(buffer, f));
    479 			//nc->url = buffer;
    480 
    481 			READ(read_uint32(&u32, f));
    482 			if (u32 & OLD_NI_KILLPROTECT)
    483 				nc->Extend<bool>("KILLPROTECT");
    484 			if (u32 & OLD_NI_SECURE)
    485 				nc->Extend<bool>("NS_SECURE");
    486 			if (u32 & OLD_NI_MSG)
    487 				nc->Extend<bool>("MSG");
    488 			if (u32 & OLD_NI_MEMO_HARDMAX)
    489 				nc->Extend<bool>("MEMO_HARDMAX");
    490 			if (u32 & OLD_NI_MEMO_SIGNON)
    491 				nc->Extend<bool>("MEMO_SIGNON");
    492 			if (u32 & OLD_NI_MEMO_RECEIVE)
    493 				nc->Extend<bool>("MEMO_RECEIVE");
    494 			if (u32 & OLD_NI_PRIVATE)
    495 				nc->Extend<bool>("NS_PRIVATE");
    496 			if (u32 & OLD_NI_HIDE_EMAIL)
    497 				nc->Extend<bool>("HIDE_EMAIL");
    498 			if (u32 & OLD_NI_HIDE_MASK)
    499 				nc->Extend<bool>("HIDE_MASK");
    500 			if (u32 & OLD_NI_HIDE_QUIT)
    501 				nc->Extend<bool>("HIDE_QUIT");
    502 			if (u32 & OLD_NI_KILL_QUICK)
    503 				nc->Extend<bool>("KILL_QUICK");
    504 			if (u32 & OLD_NI_KILL_IMMED)
    505 				nc->Extend<bool>("KILL_IMMED");
    506 			if (u32 & OLD_NI_MEMO_MAIL)
    507 				nc->Extend<bool>("MEMO_MAIL");
    508 			if (u32 & OLD_NI_HIDE_STATUS)
    509 				nc->Extend<bool>("HIDE_STATUS");
    510 			if (u32 & OLD_NI_SUSPENDED)
    511 			{
    512 				SuspendInfo si;
    513 				si.what = nc->display;
    514 				si.when = si.expires = 0;
    515 				nc->Extend("NS_SUSPENDED", si);
    516 			}
    517 			if (!(u32 & OLD_NI_AUTOOP))
    518 				nc->Extend<bool>("AUTOOP");
    519 
    520 			uint16_t u16;
    521 			READ(read_uint16(&u16, f));
    522 			switch (u16)
    523 			{
    524 				case LANG_ES:
    525 					nc->language = "es_ES.UTF-8";
    526 					break;
    527 				case LANG_PT:
    528 					nc->language = "pt_PT.UTF-8";
    529 					break;
    530 				case LANG_FR:
    531 					nc->language = "fr_FR.UTF-8";
    532 					break;
    533 				case LANG_TR:
    534 					nc->language = "tr_TR.UTF-8";
    535 					break;
    536 				case LANG_IT:
    537 					nc->language = "it_IT.UTF-8";
    538 					break;
    539 				case LANG_DE:
    540 					nc->language = "de_DE.UTF-8";
    541 					break;
    542 				case LANG_CAT:
    543 					nc->language = "ca_ES.UTF-8"; // yes, iso639 defines catalan as CA
    544 					break;
    545 				case LANG_GR:
    546 					nc->language = "el_GR.UTF-8";
    547 					break;
    548 				case LANG_NL:
    549 					nc->language = "nl_NL.UTF-8";
    550 					break;
    551 				case LANG_RU:
    552 					nc->language = "ru_RU.UTF-8";
    553 					break;
    554 				case LANG_HUN:
    555 					nc->language = "hu_HU.UTF-8";
    556 					break;
    557 				case LANG_PL:
    558 					nc->language = "pl_PL.UTF-8";
    559 					break;
    560 				case LANG_EN_US:
    561 				case LANG_JA_JIS:
    562 				case LANG_JA_EUC:
    563 				case LANG_JA_SJIS: // these seem to be unused
    564 				default:
    565 					nc->language = "en";
    566 			}
    567 
    568 			READ(read_uint16(&u16, f));
    569 			for (uint16_t j = 0; j < u16; ++j)
    570 			{
    571 				READ(read_string(buffer, f));
    572 				nc->access.push_back(buffer);
    573 			}
    574 
    575 			int16_t i16;
    576 			READ(read_int16(&i16, f));
    577 			READ(read_int16(&nc->memos.memomax, f));
    578 			for (int16_t j = 0; j < i16; ++j)
    579 			{
    580 				Memo *m = new Memo;
    581 				READ(read_uint32(&u32, f));
    582 				uint16_t flags;
    583 				READ(read_uint16(&flags, f));
    584 				int32_t tmp32;
    585 				READ(read_int32(&tmp32, f));
    586 				m->time = tmp32;
    587 				char sbuf[32];
    588 				READ(read_buffer(sbuf, f));
    589 				m->sender = sbuf;
    590 				READ(read_string(m->text, f));
    591 				m->owner = nc->display;
    592 				nc->memos.memos->push_back(m);
    593 				m->mi = &nc->memos;
    594 			}
    595 			READ(read_uint16(&u16, f));
    596 			READ(read_int16(&i16, f));
    597 
    598 			Log(LOG_DEBUG) << "Loaded NickCore " << nc->display;
    599 		}
    600 
    601 	for (int i = 0; i < 1024; ++i)
    602 		for (int c; (c = getc_db(f)) == 1;)
    603 		{
    604 			Anope::string nick, last_usermask, last_realname, last_quit;
    605 			time_t time_registered, last_seen;
    606 
    607 			READ(read_string(nick, f));
    608 			READ(read_string(last_usermask, f));
    609 			READ(read_string(last_realname, f));
    610 			READ(read_string(last_quit, f));
    611 
    612 			int32_t tmp32;
    613 			READ(read_int32(&tmp32, f));
    614 			time_registered = tmp32;
    615 			READ(read_int32(&tmp32, f));
    616 			last_seen = tmp32;
    617 
    618 			uint16_t tmpu16;
    619 			READ(read_uint16(&tmpu16, f));
    620 
    621 			Anope::string core;
    622 			READ(read_string(core, f));
    623 			NickCore *nc = NickCore::Find(core);
    624 			if (nc == NULL)
    625 			{
    626 				Log() << "Skipping coreless nick " << nick << " with core " << core;
    627 				continue;
    628 			}
    629 
    630 			if (tmpu16 & OLD_NS_VERBOTEN)
    631 			{
    632 				if (!forbid)
    633 				{
    634 					delete nc;
    635 					continue;
    636 				}
    637 
    638 				if (nc->display.find_first_of("?*") != Anope::string::npos)
    639 				{
    640 					delete nc;
    641 					continue;
    642 				}
    643 
    644 				ForbidData *d = forbid->CreateForbid();
    645 				d->mask = nc->display;
    646 				d->creator = last_usermask;
    647 				d->reason = last_realname;
    648 				d->expires = 0;
    649 				d->created = 0;
    650 				d->type = FT_NICK;
    651 				delete nc;
    652 				forbid->AddForbid(d);
    653 				continue;
    654 			}
    655 
    656 			NickAlias *na = new NickAlias(nick, nc);
    657 			na->last_usermask = last_usermask;
    658 			na->last_realname = last_realname;
    659 			na->last_quit = last_quit;
    660 			na->time_registered = time_registered;
    661 			na->last_seen = last_seen;
    662 
    663 			if (tmpu16 & OLD_NS_NO_EXPIRE)
    664 				na->Extend<bool>("NS_NO_EXPIRE");
    665 
    666 			Log(LOG_DEBUG) << "Loaded NickAlias " << na->nick;
    667 		}
    668 
    669 	close_db(f); /* End of section Ia */
    670 }
    671 
    672 static void LoadVHosts()
    673 {
    674 	dbFILE *f = open_db_read("HostServ", "hosts.db", 3);
    675 	if (f == NULL)
    676 		return;
    677 
    678 	for (int c; (c = getc_db(f)) == 1;)
    679 	{
    680 		Anope::string nick, ident, host, creator;
    681 		int32_t vtime;
    682 
    683 		READ(read_string(nick, f));
    684 		READ(read_string(ident, f));
    685 		READ(read_string(host, f));
    686 		READ(read_string(creator, f));
    687 		READ(read_int32(&vtime, f));
    688 
    689 		NickAlias *na = NickAlias::Find(nick);
    690 		if (na == NULL)
    691 		{
    692 			Log() << "Removing vhost for nonexistent nick " << nick;
    693 			continue;
    694 		}
    695 
    696 		na->SetVhost(ident, host, creator, vtime);
    697 
    698 		Log() << "Loaded vhost for " << na->nick;
    699 	}
    700 
    701 	close_db(f);
    702 }
    703 
    704 static void LoadBots()
    705 {
    706 	dbFILE *f = open_db_read("Botserv", "bot.db", 10);
    707 	if (f == NULL)
    708 		return;
    709 
    710 	for (int c; (c = getc_db(f)) == 1;)
    711 	{
    712 		Anope::string nick, user, host, real;
    713 		int16_t flags, chancount;
    714 		int32_t created;
    715 
    716 		READ(read_string(nick, f));
    717 		READ(read_string(user, f));
    718 		READ(read_string(host, f));
    719 		READ(read_string(real, f));
    720 		READ(read_int16(&flags, f));
    721 		READ(read_int32(&created, f));
    722 		READ(read_int16(&chancount, f));
    723 
    724 		BotInfo *bi = BotInfo::Find(nick, true);
    725 		if (!bi)
    726 			bi = new BotInfo(nick, user, host, real);
    727 		bi->created = created;
    728 
    729 		if (flags & OLD_BI_PRIVATE)
    730 			bi->oper_only = true;
    731 
    732 		Log(LOG_DEBUG) << "Loaded bot " << bi->nick;
    733 	}
    734 
    735 	close_db(f);
    736 }
    737 
    738 static void LoadChannels()
    739 {
    740 	ServiceReference<ForbidService> forbid("ForbidService", "forbid");
    741 	dbFILE *f = open_db_read("ChanServ", "chan.db", 16);
    742 	if (f == NULL)
    743 		return;
    744 
    745 	for (int i = 0; i < 256; ++i)
    746 		for (int c; (c = getc_db(f)) == 1;)
    747 		{
    748 			Anope::string buffer;
    749 			char namebuf[64];
    750 			READ(read_buffer(namebuf, f));
    751 			ChannelInfo *ci = new ChannelInfo(namebuf);
    752 
    753 			const Anope::string settings[] = { "keeptopic", "peace", "cs_private", "restricted", "cs_secure", "secureops", "securefounder",
    754 				"signkick", "signkick_level", "topiclock", "persist", "noautoop", "cs_keepmodes" };
    755 			for (unsigned j = 0; j < sizeof(settings) / sizeof(Anope::string); ++j)
    756 				ci->Shrink<bool>(settings[j].upper());
    757 
    758 			READ(read_string(buffer, f));
    759 			ci->SetFounder(NickCore::Find(buffer));
    760 
    761 			READ(read_string(buffer, f));
    762 			ci->SetSuccessor(NickCore::Find(buffer));
    763 
    764 			char pwbuf[32];
    765 			READ(read_buffer(pwbuf, f));
    766 
    767 			READ(read_string(ci->desc, f));
    768 			READ(read_string(buffer, f));
    769 			READ(read_string(buffer, f));
    770 
    771 			int32_t tmp32;
    772 			READ(read_int32(&tmp32, f));
    773 			ci->time_registered = tmp32;
    774 
    775 			READ(read_int32(&tmp32, f));
    776 			ci->last_used = tmp32;
    777 
    778 			READ(read_string(ci->last_topic, f));
    779 
    780 			READ(read_buffer(pwbuf, f));
    781 			ci->last_topic_setter = pwbuf;
    782 
    783 			READ(read_int32(&tmp32, f));
    784 			ci->last_topic_time = tmp32;
    785 
    786 			uint32_t tmpu32;
    787 			READ(read_uint32(&tmpu32, f));
    788 			// Temporary flags cleanup
    789 			tmpu32 &= ~0x80000000;
    790 			if (tmpu32 & OLD_CI_KEEPTOPIC)
    791 				ci->Extend<bool>("KEEPTOPIC");
    792 			if (tmpu32 & OLD_CI_SECUREOPS)
    793 				ci->Extend<bool>("SECUREOPS");
    794 			if (tmpu32 & OLD_CI_PRIVATE)
    795 				ci->Extend<bool>("CS_PRIVATE");
    796 			if (tmpu32 & OLD_CI_TOPICLOCK)
    797 				ci->Extend<bool>("TOPICLOCK");
    798 			if (tmpu32 & OLD_CI_RESTRICTED)
    799 				ci->Extend<bool>("RESTRICTED");
    800 			if (tmpu32 & OLD_CI_PEACE)
    801 				ci->Extend<bool>("PEACE");
    802 			if (tmpu32 & OLD_CI_SECURE)
    803 				ci->Extend<bool>("CS_SECURE");
    804 			if (tmpu32 & OLD_CI_NO_EXPIRE)
    805 				ci->Extend<bool>("CS_NO_EXPIRE");
    806 			if (tmpu32 & OLD_CI_MEMO_HARDMAX)
    807 				ci->Extend<bool>("MEMO_HARDMAX");
    808 			if (tmpu32 & OLD_CI_SECUREFOUNDER)
    809 				ci->Extend<bool>("SECUREFOUNDER");
    810 			if (tmpu32 & OLD_CI_SIGNKICK)
    811 				ci->Extend<bool>("SIGNKICK");
    812 			if (tmpu32 & OLD_CI_SIGNKICK_LEVEL)
    813 				ci->Extend<bool>("SIGNKICK_LEVEL");
    814 
    815 			Anope::string forbidby, forbidreason;
    816 			READ(read_string(forbidby, f));
    817 			READ(read_string(forbidreason, f));
    818 			if (tmpu32 & OLD_CI_SUSPENDED)
    819 			{
    820 				SuspendInfo si;
    821 				si.what = ci->name;
    822 				si.by = forbidby;
    823 				si.reason = forbidreason;
    824 				si.when = si.expires = 0;
    825 				ci->Extend("CS_SUSPENDED", si);
    826 			}
    827 			bool forbid_chan = tmpu32 & OLD_CI_VERBOTEN;
    828 
    829 			int16_t tmp16;
    830 			READ(read_int16(&tmp16, f));
    831 			ci->bantype = tmp16;
    832 
    833 			READ(read_int16(&tmp16, f));
    834 			if (tmp16 > 36)
    835 				tmp16 = 36;
    836 			for (int16_t j = 0; j < tmp16; ++j)
    837 			{
    838 				int16_t level;
    839 				READ(read_int16(&level, f));
    840 
    841 				if (level == ACCESS_INVALID)
    842 					level = ACCESS_FOUNDER;
    843 
    844 				if (j == 10 && level < 0) // NOJOIN
    845 					ci->Shrink<bool>("RESTRICTED"); // If CSDefRestricted was enabled this can happen
    846 
    847 				ci->SetLevel(GetLevelName(j), level);
    848 			}
    849 
    850 			bool xop = tmpu32 & OLD_CI_XOP;
    851 			ServiceReference<AccessProvider> provider_access("AccessProvider", "access/access"), provider_xop("AccessProvider", "access/xop");
    852 			uint16_t tmpu16;
    853 			READ(read_uint16(&tmpu16, f));
    854 			for (uint16_t j = 0; j < tmpu16; ++j)
    855 			{
    856 				uint16_t in_use;
    857 				READ(read_uint16(&in_use, f));
    858 				if (in_use)
    859 				{
    860 					ChanAccess *access = NULL;
    861 
    862 					if (xop)
    863 					{
    864 						if (provider_xop)
    865 							access = provider_xop->Create();
    866 					}
    867 					else
    868 						if (provider_access)
    869 							access = provider_access->Create();
    870 
    871 					if (access)
    872 						access->ci = ci;
    873 
    874 					int16_t level;
    875 					READ(read_int16(&level, f));
    876 					if (access)
    877 					{
    878 						if (xop)
    879 						{
    880 							switch (level)
    881 							{
    882 								case 3:
    883 									access->AccessUnserialize("VOP");
    884 									break;
    885 								case 4:
    886 									access->AccessUnserialize("HOP");
    887 									break;
    888 								case 5:
    889 									access->AccessUnserialize("AOP");
    890 									break;
    891 								case 10:
    892 									access->AccessUnserialize("SOP");
    893 									break;
    894 							}
    895 						}
    896 						else
    897 							access->AccessUnserialize(stringify(level));
    898 					}
    899 
    900 					Anope::string mask;
    901 					READ(read_string(mask, f));
    902 					if (access)
    903 						access->SetMask(mask, ci);
    904 
    905 					READ(read_int32(&tmp32, f));
    906 					if (access)
    907 					{
    908 						access->last_seen = tmp32;
    909 						access->creator = "Unknown";
    910 						access->created = Anope::CurTime;
    911 
    912 						ci->AddAccess(access);
    913 					}
    914 				}
    915 			}
    916 
    917 			READ(read_uint16(&tmpu16, f));
    918 			for (uint16_t j = 0; j < tmpu16; ++j)
    919 			{
    920 				uint16_t flags;
    921 				READ(read_uint16(&flags, f));
    922 				if (flags & 0x0001)
    923 				{
    924 					Anope::string mask, reason, creator;
    925 					READ(read_string(mask, f));
    926 					READ(read_string(reason, f));
    927 					READ(read_string(creator, f));
    928 					READ(read_int32(&tmp32, f));
    929 
    930 					ci->AddAkick(creator, mask, reason, tmp32);
    931 				}
    932 			}
    933 
    934 			READ(read_uint32(&tmpu32, f)); // mlock on
    935 			ci->Extend<uint32_t>("mlock_on", tmpu32);
    936 			READ(read_uint32(&tmpu32, f)); // mlock off
    937 			ci->Extend<uint32_t>("mlock_off", tmpu32);
    938 			READ(read_uint32(&tmpu32, f)); // mlock limit
    939 			ci->Extend<uint32_t>("mlock_limit", tmpu32);
    940 			READ(read_string(buffer, f)); // key
    941 			ci->Extend<Anope::string>("mlock_key", buffer);
    942 			READ(read_string(buffer, f)); // +f
    943 			READ(read_string(buffer, f)); // +L
    944 
    945 			READ(read_int16(&tmp16, f));
    946 			READ(read_int16(&ci->memos.memomax, f));
    947 			for (int16_t j = 0; j < tmp16; ++j)
    948 			{
    949 				READ(read_uint32(&tmpu32, f));
    950 				READ(read_uint16(&tmpu16, f));
    951 				Memo *m = new Memo;
    952 				READ(read_int32(&tmp32, f));
    953 				m->time = tmp32;
    954 				char sbuf[32];
    955 				READ(read_buffer(sbuf, f));
    956 				m->sender = sbuf;
    957 				READ(read_string(m->text, f));
    958 				m->owner = ci->name;
    959 				ci->memos.memos->push_back(m);
    960 				m->mi = &ci->memos;
    961 			}
    962 
    963 			READ(read_string(buffer, f));
    964 			if (!buffer.empty())
    965 			{
    966 				EntryMessageList *eml = ci->Require<EntryMessageList>("entrymsg");
    967 				if (eml)
    968 				{
    969 					EntryMsg *e = eml->Create();
    970 
    971 					e->chan = ci->name;
    972 					e->creator = "Unknown";
    973 					e->message = buffer;
    974 					e->when = Anope::CurTime;
    975 
    976 					(*eml)->push_back(e);
    977 				}
    978 			}
    979 
    980 			READ(read_string(buffer, f));
    981 			ci->bi = BotInfo::Find(buffer, true);
    982 
    983 			READ(read_int32(&tmp32, f));
    984 			if (tmp32 & OLD_BS_DONTKICKOPS)
    985 				ci->Extend<bool>("BS_DONTKICKOPS");
    986 			if (tmp32 & OLD_BS_DONTKICKVOICES)
    987 				ci->Extend<bool>("BS_DONTKICKVOICES");
    988 			if (tmp32 & OLD_BS_FANTASY)
    989 				ci->Extend<bool>("BS_FANTASY");
    990 			if (tmp32 & OLD_BS_GREET)
    991 				ci->Extend<bool>("BS_GREET");
    992 			if (tmp32 & OLD_BS_NOBOT)
    993 				ci->Extend<bool>("BS_NOBOT");
    994 
    995 			KickerData *kd = ci->Require<KickerData>("kickerdata");
    996 			if (kd)
    997 			{
    998 				if (tmp32 & OLD_BS_KICK_BOLDS)
    999 					kd->bolds = true;
   1000 				if (tmp32 & OLD_BS_KICK_COLORS)
   1001 					kd->colors = true;
   1002 				if (tmp32 & OLD_BS_KICK_REVERSES)
   1003 					kd->reverses = true;
   1004 				if (tmp32 & OLD_BS_KICK_UNDERLINES)
   1005 					kd->underlines = true;
   1006 				if (tmp32 & OLD_BS_KICK_BADWORDS)
   1007 					kd->badwords = true;
   1008 				if (tmp32 & OLD_BS_KICK_CAPS)
   1009 					kd->caps = true;
   1010 				if (tmp32 & OLD_BS_KICK_FLOOD)
   1011 					kd->flood = true;
   1012 				if (tmp32 & OLD_BS_KICK_REPEAT)
   1013 					kd->repeat = true;
   1014 			}
   1015 
   1016 			READ(read_int16(&tmp16, f));
   1017 			for (int16_t j = 0; j < tmp16; ++j)
   1018 			{
   1019 				int16_t ttb;
   1020 				READ(read_int16(&ttb, f));
   1021 				if (j < TTB_SIZE && kd)
   1022 					kd->ttb[j] = ttb;
   1023 			}
   1024 
   1025 			READ(read_int16(&tmp16, f));
   1026 			if (kd)
   1027 				kd->capsmin = tmp16;
   1028 			READ(read_int16(&tmp16, f));
   1029 			if (kd)
   1030 				kd->capspercent = tmp16;
   1031 			READ(read_int16(&tmp16, f));
   1032 			if (kd)
   1033 				kd->floodlines = tmp16;
   1034 			READ(read_int16(&tmp16, f));
   1035 			if (kd)
   1036 				kd->floodsecs = tmp16;
   1037 			READ(read_int16(&tmp16, f));
   1038 			if (kd)
   1039 				kd->repeattimes = tmp16;
   1040 
   1041 			BadWords *bw = ci->Require<BadWords>("badwords");
   1042 			READ(read_uint16(&tmpu16, f));
   1043 			for (uint16_t j = 0; j < tmpu16; ++j)
   1044 			{
   1045 				uint16_t in_use;
   1046 				READ(read_uint16(&in_use, f));
   1047 				if (in_use)
   1048 				{
   1049 					READ(read_string(buffer, f));
   1050 					uint16_t type;
   1051 					READ(read_uint16(&type, f));
   1052 
   1053 					BadWordType bwtype = BW_ANY;
   1054 					if (type == 1)
   1055 						bwtype = BW_SINGLE;
   1056 					else if (type == 2)
   1057 						bwtype = BW_START;
   1058 					else if (type == 3)
   1059 						bwtype = BW_END;
   1060 
   1061 					if (bw)
   1062 						bw->AddBadWord(buffer, bwtype);
   1063 				}
   1064 			}
   1065 
   1066 			if (forbid_chan)
   1067 			{
   1068 				if (!forbid)
   1069 				{
   1070 					delete ci;
   1071 					continue;
   1072 				}
   1073 
   1074 				if (ci->name.find_first_of("?*") != Anope::string::npos)
   1075 				{
   1076 					delete ci;
   1077 					continue;
   1078 				}
   1079 
   1080 				ForbidData *d = forbid->CreateForbid();
   1081 				d->mask = ci->name;
   1082 				d->creator = forbidby;
   1083 				d->reason = forbidreason;
   1084 				d->expires = 0;
   1085 				d->created = 0;
   1086 				d->type = FT_CHAN;
   1087 				delete ci;
   1088 				forbid->AddForbid(d);
   1089 				continue;
   1090 			}
   1091 
   1092 			Log(LOG_DEBUG) << "Loaded channel " << ci->name;
   1093 		}
   1094 
   1095 	close_db(f);
   1096 }
   1097 
   1098 static void LoadOper()
   1099 {
   1100 	dbFILE *f = open_db_read("OperServ", "oper.db", 13);
   1101 	if (f == NULL)
   1102 		return;
   1103 
   1104 	XLineManager *akill, *sqline, *snline, *szline;
   1105 	akill = sqline = snline = szline = NULL;
   1106 
   1107 	for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it)
   1108 	{
   1109 		XLineManager *xl = *it;
   1110 		if (xl->Type() == 'G')
   1111 			akill = xl;
   1112 		else if (xl->Type() == 'Q')
   1113 			sqline = xl;
   1114 		else if (xl->Type() == 'N')
   1115 			snline = xl;
   1116 		else if (xl->Type() == 'Z')
   1117 			szline = xl;
   1118 	}
   1119 
   1120 	int32_t tmp32;
   1121 	READ(read_int32(&tmp32, f));
   1122 	READ(read_int32(&tmp32, f));
   1123 
   1124 	int16_t capacity;
   1125 	read_int16(&capacity, f); // AKill count
   1126 	for (int16_t i = 0; i < capacity; ++i)
   1127 	{
   1128 		Anope::string user, host, by, reason;
   1129 		int32_t seton, expires;
   1130 
   1131 		READ(read_string(user, f));
   1132 		READ(read_string(host, f));
   1133 		READ(read_string(by, f));
   1134 		READ(read_string(reason, f));
   1135 		READ(read_int32(&seton, f));
   1136 		READ(read_int32(&expires, f));
   1137 
   1138 		if (!akill)
   1139 			continue;
   1140 
   1141 		XLine *x = new XLine(user + "@" + host, by, expires, reason, XLineManager::GenerateUID());
   1142 		x->created = seton;
   1143 		akill->AddXLine(x);
   1144 	}
   1145 
   1146 	read_int16(&capacity, f); // SNLines
   1147 	for (int16_t i = 0; i < capacity; ++i)
   1148 	{
   1149 		Anope::string mask, by, reason;
   1150 		int32_t seton, expires;
   1151 
   1152 		READ(read_string(mask, f));
   1153 		READ(read_string(by, f));
   1154 		READ(read_string(reason, f));
   1155 		READ(read_int32(&seton, f));
   1156 		READ(read_int32(&expires, f));
   1157 
   1158 		if (!snline)
   1159 			continue;
   1160 
   1161 		XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
   1162 		x->created = seton;
   1163 		snline->AddXLine(x);
   1164 	}
   1165 
   1166 	read_int16(&capacity, f); // SQLines
   1167 	for (int16_t i = 0; i < capacity; ++i)
   1168 	{
   1169 		Anope::string mask, by, reason;
   1170 		int32_t seton, expires;
   1171 
   1172 		READ(read_string(mask, f));
   1173 		READ(read_string(by, f));
   1174 		READ(read_string(reason, f));
   1175 		READ(read_int32(&seton, f));
   1176 		READ(read_int32(&expires, f));
   1177 
   1178 		if (!sqline)
   1179 			continue;
   1180 
   1181 		XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
   1182 		x->created = seton;
   1183 		sqline->AddXLine(x);
   1184 	}
   1185 
   1186 	read_int16(&capacity, f); // SZLines
   1187 	for (int16_t i = 0; i < capacity; ++i)
   1188 	{
   1189 		Anope::string mask, by, reason;
   1190 		int32_t seton, expires;
   1191 
   1192 		READ(read_string(mask, f));
   1193 		READ(read_string(by, f));
   1194 		READ(read_string(reason, f));
   1195 		READ(read_int32(&seton, f));
   1196 		READ(read_int32(&expires, f));
   1197 
   1198 		if (!szline)
   1199 			continue;
   1200 
   1201 		XLine *x = new XLine(mask, by, expires, reason, XLineManager::GenerateUID());
   1202 		x->created = seton;
   1203 		szline->AddXLine(x);
   1204 	}
   1205 
   1206 	close_db(f);
   1207 }
   1208 
   1209 static void LoadExceptions()
   1210 {
   1211 	if (!session_service)
   1212 		return;
   1213 
   1214 	dbFILE *f = open_db_read("OperServ", "exception.db", 9);
   1215 	if (f == NULL)
   1216 		return;
   1217 
   1218 	int16_t num;
   1219 	READ(read_int16(&num, f));
   1220 	for (int i = 0; i < num; ++i)
   1221 	{
   1222 		Anope::string mask, reason;
   1223 		int16_t limit;
   1224 		char who[32];
   1225 		int32_t time, expires;
   1226 
   1227 		READ(read_string(mask, f));
   1228 		READ(read_int16(&limit, f));
   1229 		READ(read_buffer(who, f));
   1230 		READ(read_string(reason, f));
   1231 		READ(read_int32(&time, f));
   1232 		READ(read_int32(&expires, f));
   1233 
   1234 		Exception *exception = session_service->CreateException();
   1235 		exception->mask = mask;
   1236 		exception->limit = limit;
   1237 		exception->who = who;
   1238 		exception->time = time;
   1239 		exception->expires = expires;
   1240 		exception->reason = reason;
   1241 		session_service->AddException(exception);
   1242 	}
   1243 
   1244 	close_db(f);
   1245 }
   1246 
   1247 static void LoadNews()
   1248 {
   1249 	if (!news_service)
   1250 		return;
   1251 
   1252 	dbFILE *f = open_db_read("OperServ", "news.db", 9);
   1253 
   1254 	if (f == NULL)
   1255 		return;
   1256 
   1257 	int16_t n;
   1258 	READ(read_int16(&n, f));
   1259 
   1260 	for (int16_t i = 0; i < n; i++)
   1261 	{
   1262 		int16_t type;
   1263 		NewsItem *ni = news_service->CreateNewsItem();
   1264 
   1265 		READ(read_int16(&type, f));
   1266 
   1267 		switch (type)
   1268 		{
   1269 			case OLD_NEWS_LOGON:
   1270 				ni->type = NEWS_LOGON;
   1271 				break;
   1272 			case OLD_NEWS_OPER:
   1273 				ni->type = NEWS_OPER;
   1274 				break;
   1275 			case OLD_NEWS_RANDOM:
   1276 				ni->type = NEWS_RANDOM;
   1277 				break;
   1278 		}
   1279 
   1280 		int32_t unused;
   1281 		READ(read_int32(&unused, f));
   1282 
   1283 		READ(read_string(ni->text, f));
   1284 
   1285 		char who[32];
   1286 		READ(read_buffer(who, f));
   1287 		ni->who = who;
   1288 
   1289 		int32_t tmp;
   1290 		READ(read_int32(&tmp, f));
   1291 		ni->time = tmp;
   1292 
   1293 		news_service->AddNewsItem(ni);
   1294 	}
   1295 
   1296 	close_db(f);
   1297 }
   1298 
   1299 class DBOld : public Module
   1300 {
   1301 	PrimitiveExtensibleItem<uint32_t> mlock_on, mlock_off, mlock_limit;
   1302 	PrimitiveExtensibleItem<Anope::string> mlock_key;
   1303 
   1304  public:
   1305 	DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR),
   1306 		mlock_on(this, "mlock_on"), mlock_off(this, "mlock_off"), mlock_limit(this, "mlock_limit"), mlock_key(this, "mlock_key")
   1307 	{
   1308 
   1309 
   1310 		hashm = Config->GetModule(this)->Get<const Anope::string>("hash");
   1311 
   1312 		if (hashm != "md5" && hashm != "oldmd5" && hashm != "sha1" && hashm != "plain" && hashm != "sha256")
   1313 			throw ModuleException("Invalid hash method");
   1314 	}
   1315 
   1316 	EventReturn OnLoadDatabase() anope_override
   1317 	{
   1318 		LoadNicks();
   1319 		LoadVHosts();
   1320 		LoadBots();
   1321 		LoadChannels();
   1322 		LoadOper();
   1323 		LoadExceptions();
   1324 		LoadNews();
   1325 
   1326 		return EVENT_STOP;
   1327 	}
   1328 
   1329 	void OnUplinkSync(Server *s) anope_override
   1330 	{
   1331 		for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it)
   1332 		{
   1333 			ChannelInfo *ci = it->second;
   1334 			uint32_t *limit = mlock_limit.Get(ci);
   1335 			Anope::string *key = mlock_key.Get(ci);
   1336 
   1337 			uint32_t *u = mlock_on.Get(ci);
   1338 			if (u)
   1339 			{
   1340 				process_mlock(ci, *u, true, limit, key);
   1341 				mlock_on.Unset(ci);
   1342 			}
   1343 
   1344 			u = mlock_off.Get(ci);
   1345 			if (u)
   1346 			{
   1347 				process_mlock(ci, *u, false, limit, key);
   1348 				mlock_off.Unset(ci);
   1349 			}
   1350 
   1351 			mlock_limit.Unset(ci);
   1352 			mlock_key.Unset(ci);
   1353 
   1354 			if (ci->c)
   1355 				ci->c->CheckModes();
   1356 		}
   1357 	}
   1358 };
   1359 
   1360 MODULE_INIT(DBOld)