/* * Copyright (C) 2003-2011 Anope Team * Copyright (C) 2005-2006 Florian Schulze * Copyright (C) 2008-2011 Robin Burchell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License (see it online * at http://www.gnu.org/copyleft/gpl.html) as published by the Free * Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "db-convert.h" static std::string GetLevelName(int level) { switch (level) { case 0: return "INVITE"; case 1: return "AKICK"; case 2: return "SET"; case 3: return "UNBAN"; case 4: return "AUTOOP"; case 5: return "AUTODEOP"; case 6: return "AUTOVOICE"; case 7: return "OPDEOP"; case 8: return "LIST"; case 9: return "CLEAR"; case 10: return "NOJOIN"; case 11: return "CHANGE"; case 12: return "MEMO"; case 13: return "ASSIGN"; case 14: return "BADWORDS"; case 15: return "NOKICK"; case 16: return "FANTASIA"; case 17: return "SAY"; case 18: return "GREET"; case 19: return "VOICEME"; case 20: return "VOICE"; case 21: return "GETKEY"; case 22: return "AUTOHALFOP"; case 23: return "AUTOPROTECT"; case 24: return "OPDEOPME"; case 25: return "HALFOPME"; case 26: return "HALFOP"; case 27: return "PROTECTME"; case 28: return "PROTECT"; case 29: return "KICKME"; case 30: return "KICK"; case 31: return "SIGNKICK"; case 32: return "BANME"; case 33: return "BAN"; case 34: return "TOPIC"; case 35: return "INFO"; default: return "INVALID"; } } void process_mlock_modes(std::ofstream &fs, size_t m, const std::string &ircd) { /* this is the same in all protocol modules */ if (m & 0x1) fs << " CMODE_INVITE"; // CMODE_i if (m & 0x2) fs << " CMODE_MODERATED"; // CMODE_m if (m & 0x4) fs << " CMODE_NOEXTERNAL"; // CMODE_n if (m & 0x8) fs << " CMODE_PRIVATE"; // CMODE_p if (m & 0x10) fs << " CMODE_SECRET"; // CMODE_s if (m & 0x20) fs << " CMODE_TOPIC"; // CMODE_t if (m & 0x40) fs << " CMODE_KEY"; // CMODE_k if (m & 0x80) fs << " CMODE_LIMIT"; // CMODE_l if (m & 0x200) fs << " CMODE_REGISTERED"; // CMODE_r if (ircd == "unreal" || ircd == "inspircd") { if (m & 0x100) fs << " CMODE_REGISTEREDONLY"; // CMODE_R if (m & 0x400) fs << " CMODE_BLOCKCOLOR"; // CMODE_c if (m & 0x2000) fs << " CMODE_NOKNOCK"; // CMODE_K if (m & 0x4000) fs << " CMODE_REDIRECT"; // CMODE_L if (m & 0x8000) fs << " CMODE_OPERONLY"; // CMODE_O if (m & 0x10000) fs << " CMODE_NOKICK"; // CMODE_Q if (m & 0x20000) fs << " CMODE_STRIPCOLOR"; // CMODE_S if (m & 0x80000) fs << " CMODE_FLOOD"; // CMODE_f if (m & 0x100000) fs << " CMODE_FILTER"; // CMODE_G if (m & 0x200000) fs << " CMODE_NOCTCP"; // CMODE_C if (m & 0x400000) fs << " CMODE_AUDITORIUM"; // CMODE_u if (m & 0x800000) fs << " CMODE_SSL"; // CMODE_z if (m & 0x1000000) fs << " CMODE_NONICK"; // CMODE_N if (m & 0x4000000) fs << " CMODE_REGMODERATED"; // CMODE_M } if (ircd == "unreal") { if (m & 0x800) fs << " CMODE_ADMINONLY"; // CMODE_A if (m & 0x40000) fs << " CMODE_NOINVITE"; // CMODE_f if (m & 0x2000000) fs << " CMODE_NONOTICE"; // CMODE_T if (m & 0x8000000) fs << " CMODE_JOINFLOOD"; // CMODE_j } if (ircd == "inspircd" ) { if (m & 0x800) fs << " CMODE_ALLINVITE"; // CMODE_A if (m & 0x1000) fs << " CMODE_NONOTICE"; // CMODE_T /* for some reason, there is no CMODE_P in 1.8.x and no CMODE_V in the 1.9.1 protocol module we are ignoring this flag until we find a solution for this problem, so the +V/+P mlock mode is lost on convert anope 1.8: if (m & 0x40000) fs << " NOINVITE"; // CMODE_V anope 1.9: if (m & 0x40000) fs << " PERM"; // CMODE_P */ if (m & 0x2000000) fs << " CMODE_JOINFLOOD"; // CMODE_j if (m & 0x8000000) fs << " CMODE_BLOCKCAPS"; // CMODE_B if (m & 0x10000000) fs << " CMODE_NICKFLOOD"; // CMODE_F //if (m & 0x20000000) fs << ""; // CMODE_g (mode +g ) ... can't be mlocked in older version //if (m & 0x40000000) fs << ""; // CMODE_J (mode +J [seconds] ... can't be mlocked in older versions } } int main(int argc, char *argv[]) { dbFILE *f; std::ofstream fs; std::string hashm, ircd; printf("\n"C_LBLUE"Anope 1.8.x -> 1.9.3+ database converter"C_NONE"\n\n"); while (hashm != "md5" && hashm != "sha1" && hashm != "oldmd5" && hashm != "plain") { if (!hashm.empty()) std::cout << "Select a valid option, thanks!" << std::endl; std::cout << "Which hash method did you use? (md5, sha1, oldmd5, plain)" << std::endl << "? "; std::cin >> hashm; } while (ircd != "bahamut" && ircd != "charybdis" && ircd != "dreamforge" && ircd != "hybrid" && ircd != "inspircd" && ircd != "plexus2" && ircd != "plexus3" && ircd != "ptlink" && ircd != "rageircd" && ircd != "ratbox" && ircd != "shadowircd" && ircd != "solidircd" && ircd != "ultimate2" && ircd != "ultimate3" && ircd != "unreal" && ircd != "viagra") { if (!ircd.empty()) std::cout << "Select a valid option!" << std::endl; std::cout << "Which IRCd did you use? (required for converting the mlock modes)" << std::endl; std::cout << "(bahamut, charybdis, dreamforge, hybrid, inspircd, plexus2, plexus3, ptlink," << std::endl; std::cout << "rageircd, ratbox, shadowircd, solidircd, ultimate2, ultimate3, unreal, viagra)" << std::endl; std::cout << "Your IRCd: "; std::cin >> ircd; } std::cout << "You selected " << hashm << std::endl; fs.clear(); fs.open("anope.db"); if (!fs.is_open()) { printf("\n"C_LBLUE"Could not open anope.db for write"C_NONE"\n\n"); exit(1); } fs << "VER 2" << std::endl; /* Section I: Nicks */ /* Ia: First database */ if ((f = open_db_read("NickServ", "nick.db", 14))) { NickAlias *na, **nalast, *naprev; NickCore *nc, **nclast, *ncprev; int16 tmp16; int32 tmp32; int i, j, c; printf("Trying to merge nicks...\n"); /* Nick cores */ for (i = 0; i < 1024; ++i) { nclast = &nclists[i]; ncprev = NULL; while ((c = getc_db(f)) == 1) { if (c != 1) { printf("Invalid format in nickserv db.\n"); exit(0); } nc = new NickCore; nc->aliascount = 0; nc->unused = 0; *nclast = nc; nclast = &nc->next; nc->prev = ncprev; ncprev = nc; READ(read_string(&nc->display, f)); READ(read_buffer(nc->pass, f)); READ(read_string(&nc->email, f)); READ(read_string(&nc->greet, f)); READ(read_uint32(&nc->icq, f)); READ(read_string(&nc->url, f)); READ(read_uint32(&nc->flags, f)); READ(read_uint16(&nc->language, f)); READ(read_uint16(&nc->accesscount, f)); if (nc->accesscount) { char **access = new char *[nc->accesscount + 1]; nc->access = access; for (j = 0; j < nc->accesscount; ++j, ++access) READ(read_string(access, f)); } READ(read_int16(&nc->memos.memocount, f)); READ(read_int16(&nc->memos.memomax, f)); if (nc->memos.memocount) { Memo *memos = new Memo[nc->memos.memocount]; nc->memos.memos = memos; for (j = 0; j < nc->memos.memocount; ++j, ++memos) { READ(read_uint32(&memos->number, f)); READ(read_uint16(&memos->flags, f)); READ(read_int32(&tmp32, f)); memos->time = tmp32; READ(read_buffer(memos->sender, f)); READ(read_string(&memos->text, f)); } } READ(read_uint16(&nc->channelcount, f)); READ(read_int16(&tmp16, f)); } /* getc_db() */ *nclast = NULL; } /* for() loop */ /* Nick aliases */ for (i = 0; i < 1024; ++i) { char *s = NULL; nalast = &nalists[i]; naprev = NULL; while ((c = getc_db(f)) == 1) { if (c != 1) { printf("Invalid format in nick db.\n"); exit(0); } na = new NickAlias; READ(read_string(&na->nick, f)); READ(read_string(&na->last_usermask, f)); READ(read_string(&na->last_realname, f)); READ(read_string(&na->last_quit, f)); READ(read_int32(&tmp32, f)); na->time_registered = tmp32; READ(read_int32(&tmp32, f)); na->last_seen = tmp32; READ(read_uint16(&na->status, f)); READ(read_string(&s, f)); na->nc = findcore(s, 0); ++na->nc->aliascount; //free(s); delete [] s; *nalast = na; nalast = &na->next; na->prev = naprev; naprev = na; } /* getc_db() */ *nalast = NULL; } /* for() loop */ close_db(f); /* End of section Ia */ } /* CLEAN THE CORES */ int i; for (i = 0; i < 1024; ++i) { NickCore *ncnext; for (NickCore *nc = nclists[i]; nc; nc = ncnext) { ncnext = nc->next; if (nc->aliascount < 1) { printf("Deleting core %s (%s).\n", nc->display, nc->email); delcore(nc); } } } head = NULL; if ((f = open_db_read("HostServ", "hosts.db", 3))) { int c; HostCore *hc; while ((c = getc_db(f)) == 1) { hc = new HostCore; READ(read_string(&hc->nick, f)); READ(read_string(&hc->vIdent, f)); READ(read_string(&hc->vHost, f)); READ(read_string(&hc->creator, f)); READ(read_int32(&hc->time, f)); hc->next = head; head = hc; } close_db(f); } /* Nick cores */ for (i = 0; i < 1024; ++i) { NickAlias *na; NickCore *nc; char **access; Memo *memos; int j, len; std::string cpass; for (nc = nclists[i]; nc; nc = nc->next) { if (!nc->display) { std::cout << "Skipping core with no display" << std::endl; continue; } if (nc->aliascount < 1) { std::cout << "Skipping core with 0 or less aliases (wtf?)" << std::endl; continue; } if (nc->flags & 0x80000000) { std::cout << "Skipping forbidden nick " << nc->display << std::endl; continue; } // Enc pass if (hashm == "plain") len = strlen(nc->pass); else if (hashm == "md5") len = 16; else if (hashm == "sha1") len = 20; else if (hashm == "oldmd5") len = 16; else len = 32; if (hashm == "plain") b64_encode(nc->pass, cpass); else cpass = Hex(nc->pass); fs << "NC " << nc->display << " " << hashm << ":" << cpass << std::endl; fs << "MD LANGUAGE " << GetLanguageID(nc->language) << std::endl; fs << "MD MEMOMAX " << nc->memos.memomax << std::endl; fs << "MD CHANCOUNT " << nc->channelcount << std::endl; std::cout << "Wrote account for " << nc->display << " passlen " << cpass.length() << std::endl; if (nc->email) fs << "MD EMAIL " << nc->email << std::endl; if (nc->greet) fs << "MD GREET :" << nc->greet << std::endl; if (nc->icq) fs << "MD ICQ :" << nc->icq << std::endl; if (nc->url) fs << "MD URL :" << nc->url << std::endl; if (nc->accesscount) for (j = 0, access = nc->access; j < nc->accesscount && *access; ++j, ++access) fs << "MD ACCESS " << *access << std::endl; fs << "MD FLAGS " << (nc->flags & NI_KILLPROTECT ? "KILLPROTECT " : "") << (nc->flags & NI_SECURE ? "SECURE " : "") << (nc->flags & NI_MSG ? "MSG " : "") << (nc->flags & NI_MEMO_HARDMAX ? "MEMO_HARDMAX " : "") << (nc->flags & NI_MEMO_SIGNON ? "MEMO_SIGNON " : "") << (nc->flags & NI_MEMO_RECEIVE ? "MEMO_RECEIVE " : "") << (nc->flags & NI_PRIVATE ? "PRIVATE " : "") << (nc->flags & NI_HIDE_EMAIL ? "HIDE_EMAIL " : "") << (nc->flags & NI_HIDE_MASK ? "HIDE_MASK " : "") << (nc->flags & NI_HIDE_QUIT ? "HIDE_QUIT " : "") << (nc->flags & NI_KILL_QUICK ? "KILL_QUICK " : "") << (nc->flags & NI_KILL_IMMED ? "KILL_IMMED " : "") << (nc->flags & NI_MEMO_MAIL ? "MEMO_MAIL " : "") << (nc->flags & NI_HIDE_STATUS ? "HIDE_STATUS " : "") << (nc->flags & NI_SUSPENDED ? "SUSPENDED " : "") // in 1.8, the AUTOOP flag was set to disable AUTOOP. Now we enable it. --DP << (!(nc->flags & NI_AUTOOP) ? "AUTOOP " : "") << (nc->flags & NI_FORBIDDEN ? "FORBIDDEN " : "") << std::endl; if (nc->memos.memocount) { memos = nc->memos.memos; for (j = 0; j < nc->memos.memocount; ++j, ++memos) { if (!memos->text || !memos->sender) continue; fs << "MD MI " << memos->time << " " << memos->sender; if (memos->flags & MF_UNREAD) fs << " UNREAD"; if (memos->flags & MF_RECEIPT) fs << " RECEIPT"; if (memos->flags & MF_NOTIFYS) fs << " NOTIFYS"; fs << " :" << memos->text << std::endl; } } /* we could do this in a seperate loop, I'm doing it here for tidiness. */ for (int tmp = 0; tmp < 1024; ++tmp) { for (na = nalists[tmp]; na; na = na->next) { if (!na->nc) { std::cout << "Skipping alias with no core (wtf?)" << std::endl; continue; } if (na->nc != nc) continue; std::cout << "Writing: " << na->nc->display << "'s nick: " << na->nick << std::endl; fs << "NA " << na->nc->display << " " << na->nick << " " << na->time_registered << " " << na->last_seen << std::endl; if (na->last_usermask) fs << "MD LAST_USERMASK " << na->last_usermask << std::endl; if (na->last_realname) fs << "MD LAST_REALNAME :" << na->last_realname << std::endl; if (na->last_quit) fs << "MD LAST_QUIT :" << na->last_quit << std::endl; if ((na->status & NS_FORBIDDEN) || (na->status & NS_NO_EXPIRE)) fs << "MD FLAGS" << (na->status & NS_FORBIDDEN ? " FORBIDDEN" : "") << (na->status & NS_NO_EXPIRE ? " NOEXPIRE" : "") << std::endl; HostCore *hc = findHostCore(na->nick); if (hc && hc->creator && hc->vHost) fs << "MD VHOST " << hc->creator << " " << hc->time << " " << hc->vHost << " :" << (hc->vIdent ? hc->vIdent : "") << std::endl; } } } } /* Section II: Bots */ /* IIa: First database */ if ((f = open_db_read("Botserv", "bot.db", 10))) { std::string input; int c, broken = 0; int32 created; int16 flags, chancount; char *nick, *user, *host, *real; std::cout << "Trying to convert bots..." << std::endl; while (input != "y" && input != "n") { std::cout << std::endl << "Are you converting a 1.9.0 database? (y/n) " << std::endl << "? "; std::cin >> input; } if (input == "y") broken = 1; input = ""; while (input != "y" && input != "n") { std::cout << std::endl << "Are you converting a 1.8.x database? (y/n) " << std::endl << "? "; std::cin >> input; } /* 1.8 doesn't have nickserv etc in bot.db, create them */ if (input == "y") { time_t now = time(NULL); fs << "BI NickServ NickServ services.anope.org " << now << " 0 :NickServ" << std::endl; fs << "MD FLAGS NICKSERV" << std::endl; fs << "BI ChanServ ChanServ services.anope.org " << now << " 0 :ChanServ" << std::endl; fs << "MD FLAGS CHANSERV" << std::endl; fs << "BI BotServ BotServ services.anope.org " << now << " 0 :BotServ" << std::endl; fs << "MD FLAGS BOTSERV" << std::endl; fs << "BI HostServ HostServ services.anope.org " << now << " 0 :HostServ" << std::endl; fs << "MD FLAGS HOSTSERV" << std::endl; fs << "BI OperServ OperServ services.anope.org " << now << " 0 :OperServ" << std::endl; fs << "MD FLAGS OPERSERV" << std::endl; fs << "BI MemoServ MemoServ services.anope.org " << now << " 0 :MemoServ" << std::endl; fs << "MD FLAGS MEMOSERV" << std::endl; fs << "BI Global Global services.anope.org " << now << " 0: Global" << std::endl; fs << "MD FLAGS GLOBAL" << std::endl; } while ((c = getc_db(f)) == 1) { READ(read_string(&nick, f)); READ(read_string(&user, f)); READ(read_string(&host, f)); READ(read_string(&real, f)); SAFE(read_int16(&flags, f)); READ(read_int32(&created, f)); READ(read_int16(&chancount, f)); if (!created) created = time(NULL); // Unfortunatley, we forgot to store the created bot time in 1.9.1+ /* fix for the 1.9.0 broken bot.db */ if (broken) { flags = 0; if (!mystricmp(nick, "ChanServ")) flags |= BI_CHANSERV; if (!mystricmp(nick, "BotServ")) flags |= BI_BOTSERV; if (!mystricmp(nick, "HostServ")) flags |= BI_HOSTSERV; if (!mystricmp(nick, "OperServ")) flags |= BI_OPERSERV; if (!mystricmp(nick, "MemoServ")) flags |= BI_MEMOSERV; if (!mystricmp(nick, "NickServ")) flags |= BI_NICKSERV; if (!mystricmp(nick, "Global")) flags |= BI_GLOBAL; } /* end of 1.9.0 broken database fix */ std::cout << "Writing Bot " << nick << "!" << user << "@" << host << std::endl; fs << "BI " << nick << " " << user << " " << host << " " << created << " " << chancount << " :" << real << std::endl; fs << "MD FLAGS" << (flags & BI_PRIVATE ? " PRIVATE" : "") << (flags & BI_CHANSERV ? " CHANSERV" : "") << (flags & BI_BOTSERV ? " BOTSERV" : "") << (flags & BI_HOSTSERV ? " HOSTSERV" : "") << (flags & BI_OPERSERV ? " OPERSERV" : "") << (flags & BI_MEMOSERV ? " MEMOSERV" : "") << (flags & BI_NICKSERV ? " NICKSERV" : "") << (flags & BI_GLOBAL ? " GLOBAL" : "") << std::endl; } close_db(f); } /* Section III: Chans */ // IIIa: First database if ((f = open_db_read("ChanServ", "chan.db", 16))) { ChannelInfo *ci, **last, *prev; int c; printf("Trying to merge channels...\n"); for (i = 0; i < 256; ++i) { int16 tmp16; int32 tmp32; int n_levels; char *s; int n_ttb; last = &chanlists[i]; prev = NULL; while ((c = getc_db(f)) == 1) { int j; if (c != 1) { printf("Invalid format in chans.db.\n"); exit(0); } ci = new ChannelInfo; *last = ci; last = &ci->next; ci->prev = prev; prev = ci; READ(read_buffer(ci->name, f)); READ(read_string(&ci->founder, f)); READ(read_string(&ci->successor, f)); READ(read_buffer(ci->founderpass, f)); READ(read_string(&ci->desc, f)); if (!ci->desc) ci->desc = strdup(""); std::cout << "Read " << ci->name << " founder " << (ci->founder ? ci->founder : "N/A") << std::endl; READ(read_string(&ci->url, f)); READ(read_string(&ci->email, f)); READ(read_int32(&tmp32, f)); ci->time_registered = tmp32; READ(read_int32(&tmp32, f)); ci->last_used = tmp32; READ(read_string(&ci->last_topic, f)); READ(read_buffer(ci->last_topic_setter, f)); READ(read_int32(&tmp32, f)); ci->last_topic_time = tmp32; READ(read_uint32(&ci->flags, f)); // Temporary flags cleanup ci->flags &= ~0x80000000; READ(read_string(&ci->forbidby, f)); READ(read_string(&ci->forbidreason, f)); READ(read_int16(&tmp16, f)); ci->bantype = tmp16; READ(read_int16(&tmp16, f)); n_levels = tmp16; ci->levels = new int16[36]; for (j = 0; j < n_levels; ++j) { if (j < 36) READ(read_int16(&ci->levels[j], f)); else READ(read_int16(&tmp16, f)); } READ(read_uint16(&ci->accesscount, f)); if (ci->accesscount) { ci->access = new ChanAccess[ci->accesscount]; for (j = 0; j < ci->accesscount; ++j) { READ(read_uint16(&ci->access[j].in_use, f)); if (ci->access[j].in_use) { READ(read_int16(&ci->access[j].level, f)); READ(read_string(&s, f)); if (s) { ci->access[j].nc = findcore(s, 0); delete [] s; } if (ci->access[j].nc == NULL) ci->access[j].in_use = 0; READ(read_int32(&tmp32, f)); ci->access[j].last_seen = tmp32; } } } else ci->access = NULL; READ(read_uint16(&ci->akickcount, f)); if (ci->akickcount) { ci->akick = new AutoKick[ci->akickcount]; for (j = 0; j < ci->akickcount; ++j) { SAFE(read_uint16(&ci->akick[j].flags, f)); if (ci->akick[j].flags & 0x0001) { SAFE(read_string(&s, f)); if (ci->akick[j].flags & 0x0002) { ci->akick[j].u.nc = findcore(s, 0); if (!ci->akick[j].u.nc) ci->akick[j].flags &= ~0x0001; delete [] s; } else ci->akick[j].u.mask = s; SAFE(read_string(&s, f)); if (ci->akick[j].flags & 0x0001) ci->akick[j].reason = s; else if (s) delete [] s; SAFE(read_string(&s, f)); if (ci->akick[j].flags & 0x0001) ci->akick[j].creator = s; else if (s) delete [] s; SAFE(read_int32(&tmp32, f)); if (ci->akick[j].flags & 0x0001) ci->akick[j].addtime = tmp32; } } } else ci->akick = NULL; READ(read_uint32(&ci->mlock_on, f)); READ(read_uint32(&ci->mlock_off, f)); READ(read_uint32(&ci->mlock_limit, f)); READ(read_string(&ci->mlock_key, f)); READ(read_string(&ci->mlock_flood, f)); READ(read_string(&ci->mlock_redirect, f)); READ(read_int16(&ci->memos.memocount, f)); READ(read_int16(&ci->memos.memomax, f)); if (ci->memos.memocount) { Memo *memos = new Memo[ci->memos.memocount]; ci->memos.memos = memos; for (j = 0; j < ci->memos.memocount; ++j, ++memos) { READ(read_uint32(&memos->number, f)); READ(read_uint16(&memos->flags, f)); READ(read_int32(&tmp32, f)); memos->time = tmp32; READ(read_buffer(memos->sender, f)); READ(read_string(&memos->text, f)); } } READ(read_string(&ci->entry_message, f)); // BotServ options READ(read_string(&ci->bi, f)); READ(read_int32(&tmp32, f)); ci->botflags = tmp32; READ(read_int16(&tmp16, f)); n_ttb = tmp16; ci->ttb = new int16[16]; for (j = 0; j < n_ttb; ++j) { if (j < 8) READ(read_int16(&ci->ttb[j], f)); else READ(read_int16(&tmp16, f)); } for (j = n_ttb; j < 8; ++j) ci->ttb[j] = 0; READ(read_int16(&tmp16, f)); ci->capsmin = tmp16; READ(read_int16(&tmp16, f)); ci->capspercent = tmp16; READ(read_int16(&tmp16, f)); ci->floodlines = tmp16; READ(read_int16(&tmp16, f)); ci->floodsecs = tmp16; READ(read_int16(&tmp16, f)); ci->repeattimes = tmp16; READ(read_uint16(&ci->bwcount, f)); if (ci->bwcount) { ci->badwords = new BadWord[ci->bwcount]; for (j = 0; j < ci->bwcount; ++j) { SAFE(read_uint16(&ci->badwords[j].in_use, f)); if (ci->badwords[j].in_use) { SAFE(read_string(&ci->badwords[j].word, f)); SAFE(read_uint16(&ci->badwords[j].type, f)); } } } else ci->badwords = NULL; } *last = NULL; } close_db(f); } ChannelInfo *ci; for (i = 0; i < 256; ++i) { for (ci = chanlists[i]; ci; ci = ci->next) { int j; fs << "CH " << ci->name << " " << ci->time_registered << " " << ci->last_used << std::endl; if (ci->founder) fs << "MD FOUNDER " << ci->founder << std::endl; if (ci->successor) fs << "MD SUCCESSOR " << ci->successor << std::endl; fs << "MD BANTYPE " << ci->bantype << std::endl; fs << "MD MEMOMAX " << ci->memos.memomax << std::endl; fs << "MD LEVELS"; for (j = 0; j < 36; ++j) { /* In 1.8 disabled meant founder only. In 1.9.2 disabled literally means its disabled so, we will set these to ACCESS_QOP */ if (ci->levels[j] == -10000) fs << " " << GetLevelName(j) << " " << 10000; else fs << " " << GetLevelName(j) << " " << ci->levels[j]; } fs << std::endl; fs << "MD FLAGS" << (ci->flags & CI_KEEPTOPIC ? " KEEPTOPIC" : "") << (ci->flags & CI_SECUREOPS ? " SECUREOPS" : "") << (ci->flags & CI_PRIVATE ? " PRIVATE" : "") << (ci->flags & CI_TOPICLOCK ? " TOPICLOCK" : "") << (ci->flags & CI_RESTRICTED ? " RESTRICTED" : "") << (ci->flags & CI_PEACE ? " PEACE" : "") << (ci->flags & CI_SECURE ? " SECURE" : "") << (ci->flags & CI_FORBIDDEN ? " FORBIDDEN" : "") << (ci->flags & CI_NO_EXPIRE ? " NO_EXPIRE" : "") << (ci->flags & CI_MEMO_HARDMAX ? " MEMO_HARDMAX" : "") << (ci->flags & CI_OPNOTICE ? " OPNOTICE" : "") << (ci->flags & CI_SECUREFOUNDER ? " SECUREFOUNDER" : "") << (ci->flags & CI_SIGNKICK ? " SIGNKICK" : "") << (ci->flags & CI_SIGNKICK_LEVEL ? " SIGNKICKLEVEL" : "") << (ci->flags & CI_XOP ? " XOP" : "") << (ci->flags & CI_SUSPENDED ? " SUSPENDED" : "") << std::endl; if (ci->desc && *ci->desc) fs << "MD DESC :" << ci->desc << std::endl; if (ci->url) fs << "MD URL :" << ci->url << std::endl; if (ci->email) fs << "MD EMAIL :" << ci->email << std::endl; if (ci->last_topic && ci->last_topic_setter) // MD CH topic