Tekil Mesaj gösterimi
Alt 09 Eylül 2010, 18:59   #42
Çevrimdışı
PRaNGaLaR
Kullanıcıların profil bilgileri misafirlere kapatılmıştır.
IF Ticaret Sayısı: (0)
IF Ticaret Yüzdesi:(%)
Cevap: IRCServices PROFIL (Geliştirildi.)




Benim Nereye eklemem Gerekiyor

Kod:   Kodu kopyalamak için üzerine çift tıklayın!
/* Routines to load/save Services databases in the obsolete format used * by version 4.x (and 5.0). * * IRC Services is copyright (c) 1996-2009 Andrew Church. * E-mail: <
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
> * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file GPL.txt for * details. */ #include "services.h" #include "modules.h" #include "conffile.h" #include "databases.h" #include "hash.h" #include "language.h" #include "encrypt.h" #include "modules/nickserv/nickserv.h" #include "modules/chanserv/chanserv.h" #include "modules/memoserv/memoserv.h" #include "modules/operserv/operserv.h" #include "modules/operserv/maskdata.h" #include "modules/operserv/akill.h" #include "modules/operserv/news.h" #include "modules/operserv/sline.h" #include "modules/statserv/statserv.h" #include "extsyms.h" /* Avoid symbol clashes with database/standard when using static modules */ #define check_file_version version4_check_file_version #define get_file_version version4_get_file_version #define write_file_version version4_write_file_version #define open_db version4_open_db #define restore_db version4_restore_db #define close_db version4_close_db #define read_int8 version4_read_int8 #define read_uint8 version4_read_uint8 #define write_int8 version4_write_int8 #define read_int16 version4_read_int16 #define read_uint16 version4_read_uint16 #define write_int16 version4_write_int16 #define read_int32 version4_read_int32 #define read_uint32 version4_read_uint32 #define write_int32 version4_write_int32 #define read_time version4_read_time #define write_time version4_write_time #define read_ptr version4_read_ptr #define write_ptr version4_write_ptr #define read_string version4_read_string #define write_string version4_write_string #include "fileutil.c" #define SAFE(x) do { if ((x) < 0) goto fail; } while (0) /*************************************************************************/ #define FILE_VERSION 11 /* Must remain constant */ #define LOCAL_VERSION 100 /* For extensions to database files */ #define FIRST_VERSION_51 100 /* First extension version in 5.1 */ #define LOCAL_VERSION_50 27 /* Version we show to 5.0 */ /* LOCAL_VERSION change history: * [5.1] * 100: First version * [5.0] * 27: Added Bahamut +j handling (ci->mlock.joinrate{1,2} fields) * 26: Forced AUTODEOP and NOJOIN to default values * 25: Added trircd +J handling (ci->mlock.joindelay field) * 24: Moved nickname authentication reason into its own field (no * longer stored as part of authentication code) * 23: Added count to autokick entries in channel extension data * 22: Fixed bug causing nickgroups with ID 0 to get written out * 21: AUTODEOP and NOJOIN levels changed from -10/-20 to -1/-100 * 20: Access levels changed; v5 level data and access entry levels * added to channel extension data * 19: Added last IDENTIFY stamp to nickname extension data * 18: Added autojoin functionality; added autojoin list to nickgroup * extension data * 17: Added memo ignore functionality; added ignore list to nickgroup * extension data * 16: Added Unreal +L/+f handling; added respective fields to channel * extension data * 15: Added nick timezones; added timezone field to nickgroup extension * data * 14: Added autokick time and lastused fields (saved to channel * extension data) * 13: Added nickname privilege level to nickgroup extension data */   /* Default channel entries in version 4.5: */ #define CA_SIZE_4_5 18 #define ACCLEV_INVALID_4_5 -10000 static int def_levels_4_5[CA_SIZE_4_5] = { /* CA_INVITE */ 5, /* CA_AKICK */ 10, /* CA_SET */ ACCLEV_INVALID_4_5, /* CA_UNBAN */ 5, /* CA_AUTOOP */ 5, /* CA_AUTODEOP */ -1, /* CA_AUTOVOICE */ 3, /* CA_OPDEOP */ 5, /* CA_ACCESS_LIST */ 0, /* CA_CLEAR */ ACCLEV_INVALID_4_5, /* CA_NOJOIN */ -2, /* CA_ACCESS_CHANGE */ 10, /* CA_MEMO */ 10, /* CA_VOICE */ 3, /* CA_AUTOHALFOP */ 4, /* CA_HALFOP */ 4, /* CA_AUTOPROTECT */ 10, /* CA_PROTECT */ 10, }; /* For handling servadmins/servopers in 4.5.x databases: */ #define MAX_SERVOPERS 256 #define MAX_SERVADMINS 256 static nickname_t services_admins[MAX_SERVADMINS]; static nickname_t services_opers[MAX_SERVOPERS]; static int services_admins_count = 0, services_opers_count = 0; /* Database file names (loaded from modules.conf): */ static char *NickDBName; static char *ChanDBName; static char *OperDBName; static char *NewsDBName; static char *AutokillDBName; static char *ExceptionDBName; static char *SlineDBName; static char *StatDBName; /*************************************************************************/ /**************************** Table load/save ****************************/ /*************************************************************************/ /* Forward declarations of individual load/save routines */ static int load_nick_table(DBTable *nick_table, DBTable *nickgroup_table); static int save_nick_table(DBTable *nick_table, DBTable *nickgroup_table); static int load_chan_table(DBTable *table); static int save_chan_table(DBTable *table); static int load_oper_table(DBTable *table); static int save_oper_table(DBTable *table); static int load_news_table(DBTable *table); static int save_news_table(DBTable *table); static int load_akill_table(DBTable *akill_table, DBTable *exclude_table); static int save_akill_table(DBTable *akill_table, DBTable *exclude_table); static int load_exception_table(DBTable *table); static int save_exception_table(DBTable *table); static int load_sline_table(DBTable *sgline_table, DBTable *sqline_table, DBTable *szline_table); static int save_sline_table(DBTable *sgline_table, DBTable *sqline_table, DBTable *szline_table); static int load_stat_servers_table(DBTable *table); static int save_stat_servers_table(DBTable *table); static int load_generic_table(DBTable *table); static int save_generic_table(DBTable *table); /*************************************************************************/ static int version4_load_table(DBTable *table) { int retval = 1; /* In order to load nicknames properly, we need access to both nick * and nickgroup tables, so we save the value of each table when it's * passed in, and only call load_nick_table() when we have both values * (after which we clear them for the next time around). */ static DBTable *nick_table = NULL, *nickgroup_table = NULL; /* Likewise for the autokill/exclude and S-line tables. */ static DBTable *akill_table = NULL, *exclude_table = NULL, *sgline_table = NULL, *sqline_table = NULL, *szline_table = NULL; /* Most load routines have to go through the data multiple times to * read it in, due to the workarounds used to maintain backwards * compatibility. The expiration timestamps may not be correct during * this time, so disable expiration while the load is in progress. */ int saved_noexpire = noexpire; noexpire = 1; if (strcmp(table->name, "nick") == 0) { nick_table = table; } else if (strcmp(table->name, "nickgroup") == 0) { nickgroup_table = table; } else if (strcmp(table->name, "nick-access") == 0 || strcmp(table->name, "nick-autojoin") == 0 || strcmp(table->name, "memo") == 0 || strcmp(table->name, "memo-ignore") == 0) { /* ignore */ } else if (strcmp(table->name, "chan") == 0) { retval = load_chan_table(table); } else if (strcmp(table->name, "chan-access") == 0 || strcmp(table->name, "chan-akick") == 0) { /* ignore */ } else if (strcmp(table->name, "oper") == 0) { retval = load_oper_table(table); } else if (strcmp(table->name, "news") == 0) { retval = load_news_table(table); } else if (strcmp(table->name, "akill") == 0) { akill_table = table; } else if (strcmp(table->name, "exclude") == 0) { exclude_table = table; } else if (strcmp(table->name, "exception") == 0) { retval = load_exception_table(table); } else if (strcmp(table->name, "sgline") == 0) { sgline_table = table; } else if (strcmp(table->name, "sqline") == 0) { sqline_table = table; } else if (strcmp(table->name, "szline") == 0) { szline_table = table; } else if (strcmp(table->name, "stat-servers") == 0) { retval = load_stat_servers_table(table); } else { retval = load_generic_table(table); } if (nick_table && nickgroup_table) { /* Got both tables, run the load routine and clear the variables */ retval = load_nick_table(nick_table, nickgroup_table); nick_table = nickgroup_table = NULL; } if (akill_table && exclude_table) { retval = load_akill_table(akill_table, exclude_table); akill_table = exclude_table = NULL; } if (sgline_table && sqline_table && szline_table) { retval = load_sline_table(sgline_table, sqline_table, szline_table); sgline_table = sqline_table = szline_table = NULL; } noexpire = saved_noexpire; if (retval && table->postload && !(*table->postload)()) { module_log_perror("Table %s postload routine failed", table->name); retval = 0; } return retval; } /*************************************************************************/ static int version4_save_table(DBTable *table) { /* See version4_load_table() for why we need these */ static DBTable *nick_table = NULL, *nickgroup_table = NULL, *akill_table = NULL, *exclude_table = NULL, *sgline_table = NULL, *sqline_table = NULL, *szline_table = NULL; if (strcmp(table->name, "nick") == 0) { nick_table = table; } else if (strcmp(table->name, "nickgroup") == 0) { nickgroup_table = table; } else if (strcmp(table->name, "nick-access") == 0 || strcmp(table->name, "nick-autojoin") == 0 || strcmp(table->name, "memo") == 0 || strcmp(table->name, "memo-ignore") == 0) { /* ignore */ } else if (strcmp(table->name, "chan") == 0) { return save_chan_table(table); } else if (strcmp(table->name, "chan-access") == 0 || strcmp(table->name, "chan-akick") == 0) { /* ignore */ } else if (strcmp(table->name, "oper") == 0) { return save_oper_table(table); } else if (strcmp(table->name, "news") == 0) { return save_news_table(table); } else if (strcmp(table->name, "akill") == 0) { akill_table = table; } else if (strcmp(table->name, "exclude") == 0) { exclude_table = table; } else if (strcmp(table->name, "exception") == 0) { return save_exception_table(table); } else if (strcmp(table->name, "sgline") == 0) { sgline_table = table; } else if (strcmp(table->name, "sqline") == 0) { sqline_table = table; } else if (strcmp(table->name, "szline") == 0) { szline_table = table; } else if (strcmp(table->name, "stat-servers") == 0) { return save_stat_servers_table(table); } else { return save_generic_table(table); } if (nick_table && nickgroup_table) { int retval = save_nick_table(nick_table, nickgroup_table); nick_table = nickgroup_table = NULL; return retval; } if (akill_table && exclude_table) { int retval = save_akill_table(akill_table, exclude_table); akill_table = exclude_table = NULL; return retval; } if (sgline_table && sqline_table && szline_table) { int retval = save_sline_table(sgline_table, sqline_table, szline_table); sgline_table = sqline_table = szline_table = NULL; return retval; } return 1; } /*************************************************************************/ /*************************************************************************/ /* Common routine to open a file for reading and check version number. */ #define OPENDB_ERROR ((dbFILE *)PTR_INVALID) static dbFILE *my_open_db_r(const char *dbname, int32 *ver_ret) { dbFILE *f; int32 ver; f = open_db(dbname, "r", 0); if (!f) return NULL; ver = get_file_version(f); if (ver < 5 || ver > 11) { if (ver == -1) { module_log("Unable to read version number from %s", dbname); } else { module_log("Invalid version number %d on %s", ver, dbname); } close_db(f); return OPENDB_ERROR; } *ver_ret = ver; return f; } /*************************************************************************/ /* Read a MaskData category from a file. */ static int read_maskdata(DBTable *table, uint8 type, const char *dbname, dbFILE *f) { int32 ver; MaskData *md; int16 count; int i; #if CLEAN_COMPILE count = 0; #endif SAFE(read_int16(&count, f)); for (i = 0; i < count; i++) { int32 tmp32; md = table->newrec(); SAFE(read_string(&md->mask, f)); if (type == MD_EXCEPTION) { SAFE(read_int16(&md->limit, f)); SAFE(read_buffer(md->who, f)); SAFE(read_string(&md->reason, f)); } else { SAFE(read_string(&md->reason, f)); SAFE(read_buffer(md->who, f)); } SAFE(read_int32(&tmp32, f)); md->time = tmp32; SAFE(read_int32(&tmp32, f)); md->expires = tmp32; md->num = i+1; table->insert(md); } if (read_int32(&ver, f) == 0) { if (ver <= FILE_VERSION || ver > LOCAL_VERSION) { module_log("Invalid extension data version in %s", dbname); return 0; } for (i = 0; i < count; i++) { /* O(n^2), but we can't help it if we want to be robust */ for (md = table->first(); md; md = table->next()) { if (md->num == i+1) break; } if (md) { SAFE(read_time(&md->time, f)); SAFE(read_time(&md->expires, f)); SAFE(read_time(&md->lastused, f)); } } } return 1; fail: close_db(f); module_log("Read error on %s", dbname); return 0; } /*************************************************************************/ /* Write a MaskData category to a file. */ static int write_maskdata(DBTable *table, uint8 type, const char *dbname, dbFILE *f) { static time_t lastwarn[256]; MaskData *md; int count; int save_noexpire = noexpire; count = 0; for (md = table->first(); md; md = table->next()) count++; write_int16(count, f); /* Disable expiration for the remainder of this function. This is a * kludge to ensure that nothing expires while we're writing it out. */ noexpire = 1; for (md = table->first(); md; md = table->next()) { SAFE(write_string(md->mask, f)); if (type == MD_EXCEPTION) { SAFE(write_int16(md->limit, f)); SAFE(write_buffer(md->who, f)); SAFE(write_string(md->reason, f)); } else { SAFE(write_string(md->reason, f)); SAFE(write_buffer(md->who, f)); } SAFE(write_int32(md->time, f)); SAFE(write_int32(md->expires, f)); } SAFE(write_int32(LOCAL_VERSION_50, f)); for (md = table->first(); md; md = table->next()) { SAFE(write_time(md->time, f)); SAFE(write_time(md->expires, f)); SAFE(write_time(md->lastused, f)); } noexpire = save_noexpire; return 1; fail: restore_db(f); module_log_perror("Write error on %s", dbname); if (time(NULL) - lastwarn[type] > WarningTimeout) { wallops(NULL, "Write error on %s: %s", dbname, strerror(errno)); lastwarn[type] = time(NULL); } noexpire = save_noexpire; return 0; } /*************************************************************************/ /********************** NickServ database handling ***********************/ /*************************************************************************/ #define NGI_TEMP_ID 0xFFFFFFFFU /* until we know the real group */ static NickInfo *load_one_nick(DBTable *nick_table, DBTable *nickgroup_table, dbFILE *f, int32 ver) { NickInfo *ni; NickGroupInfo *ngi; int16 tmp16; int32 tmp32; int i; char passbuf[PASSMAX]; char *url, *email; ni = nick_table->newrec(); SAFE(read_buffer(ni->nick, f)); module_log_debug(2, "loading nick %s", ni->nick); SAFE(read_buffer(passbuf, f)); SAFE(read_string(&url, f)); SAFE(read_string(&email, f)); SAFE(read_string(&ni->last_usermask, f)); if (!ni->last_usermask) ni->last_usermask = sstrdup("@"); SAFE(read_string(&ni->last_realname, f)); if (!ni->last_realname) ni->last_realname = sstrdup(""); SAFE(read_string(&ni->last_quit, f)); SAFE(read_int32(&tmp32, f)); ni->time_registered = tmp32; SAFE(read_int32(&tmp32, f)); ni->last_seen = tmp32; SAFE(read_int16(&ni->status, f)); ni->status &= NS_PERMANENT; /* Old-style links were hierarchical; if this nick was linked to * another, the name of the parent link, else NULL, was stored here. * Store that value in ni->last_realmask, which coincidentally was * not saved before version 5.0, and resolve links later. */ SAFE(read_string(&ni->last_realmask, f)); SAFE(read_int16(&tmp16, f)); /* linkcount */ if (ni->last_realmask) { SAFE(read_int16(&tmp16, f)); /* channelcount */ free(url); free(email); } else { ngi = nickgroup_table->newrec(); ngi->id = NGI_TEMP_ID; ARRAY_EXTEND(ngi->nicks); strbcpy(ngi->nicks[0], ni->nick); init_password(&ngi->pass); encrypt_password("a", 1, &ngi->pass); /* get encryption type */ memcpy(ngi->pass.password, passbuf, PASSMAX); ngi->url = url; ngi->email = email; SAFE(read_int32(&ngi->flags, f)); if (ngi->flags & NF_KILL_IMMED) ngi->flags |= NF_KILL_QUICK; ngi->flags |= NF_NOGROUP; if (ver >= 9) { void *tmpptr; SAFE(read_ptr(&tmpptr, f)); if (tmpptr) ngi->flags |= NF_SUSPENDED; else ngi->flags &= ~NF_SUSPENDED; } else if (ver == 8 && (ngi->flags & 0x10000000)) { /* In version 8, 0x10000000 was NI_SUSPENDED */ ngi->flags |= NF_SUSPENDED; } else { ngi->flags &= ~NF_SUSPENDED; /* just in case */ } if (ngi->flags & NF_SUSPENDED) { SAFE(read_buffer(ngi->suspend_who, f)); SAFE(read_string(&ngi->suspend_reason, f)); SAFE(read_int32(&tmp32, f)); ngi->suspend_time = tmp32; SAFE(read_int32(&tmp32, f)); ngi->suspend_expires = tmp32; } SAFE(read_int16(&ngi->access_count, f)); if (ngi->access_count) { char **access; access = smalloc(sizeof(char *) * ngi->access_count); ngi->access = access; ARRAY_FOREACH (i, ngi->access) SAFE(read_string(&ngi->access[i], f)); } SAFE(read_int16(&ngi->memos.memos_count, f)); SAFE(read_int16(&ngi->memos.memomax, f)); /* * Note that at this stage we have no way of comparing this to the * default memo max (MSMaxMemos) because the MemoServ module is not * loaded. If this is a 5.x database, this is not a problem, * because the correct memo max value will be stored in the * extension data, but if not, we need to check and change the * value to MEMOMAX_DEFAULT as needed. This is handled by a * callback (nick_memomax_callback() below) which triggers when the * MemoServ module is loaded. The callback is added by * open_nick_db() if needed. */ if (ngi->memos.memos_count) { Memo *memos; memos = smalloc(sizeof(Memo) * ngi->memos.memos_count); ngi->memos.memos = memos; ARRAY_FOREACH (i, ngi->memos.memos) { SAFE(read_uint32(&ngi->memos.memos[i].number, f)); SAFE(read_int16(&ngi->memos.memos[i].flags, f)); SAFE(read_int32(&tmp32, f)); ngi->memos.memos[i].time = tmp32; if (ngi->memos.memos[i].flags & MF_UNREAD) ngi->memos.memos[i].firstread = 0; else ngi->memos.memos[i].firstread = tmp32; SAFE(read_buffer(ngi->memos.memos[i].sender, f)); ngi->memos.memos[i].channel = NULL; SAFE(read_string(&ngi->memos.memos[i].text, f)); } } /* Channel counts are recalculated by open_channel_db() */ SAFE(read_int16(&tmp16, f)); /* channelcount */ /* If this is a 5.x database, we now get the real nickgroup value * from bits 30-15 of the flags and the 16 bits we just read; the * real flags value is stored in the extension data. */ if (ngi->flags & 0x80000000) { ngi->id = (ngi->flags & 0x7FFF8000) << 1 | ((int)tmp16 & 0xFFFF); ngi->flags &= ~NF_NOGROUP; } /* There was no way to set channel limits, so must be the default. * Note that if this is a 5.x database, the correct value for this * field (as well as memomax and language) will be read from the * extension data. */ SAFE(read_int16(&tmp16, f)); /* channelmax */ ngi->channelmax = CHANMAX_DEFAULT; SAFE(read_int16(&ngi->language, f)); if (!have_language(ngi->language)) ngi->language = LANG_DEFAULT; /* Ver 4.x had no way to say "use the default language", so set that * for all nicks that are using DEF_LANGUAGE */ if (ngi->language == DEF_LANGUAGE) ngi->language = LANG_DEFAULT; ngi->timezone = TIMEZONE_DEFAULT; ni->nickgroup = ngi->id; if (ngi->id != 0) { nickgroup_table->insert(ngi); } else { nickgroup_table->freerec(ngi); if (!(ni->status & NS_VERBOTEN)) { module_log("warning: nick %s has no nick group but is not" " forbidden (corrupt database or BUG?)", ni->nick); } } } return ni; fail: module_log("Read error on %s", f->filename); return NULL; } /*************************************************************************/ /* Load extension data for a nick. Returns zero on success, nonzero on * failure. */ static int load_one_nick_ext(DBTable *nick_table, DBTable *nickgroup_table, dbFILE *f, int32 ver) { char *nick; NickInfo *ni = NULL; NickInfo dummy_ni; /* for nonexistent nicks */ SAFE(read_string(&nick, f)); if (!nick) goto fail; module_log_debug(2, "loading nick extension %s", nick); if (!(ni = get_nickinfo(nick))) { module_log("Extension data found for nonexistent nick `%s'", nick); ni = &dummy_ni; memset(ni, 0, sizeof(*ni)); } free(nick); nick = NULL; free(ni->last_realmask); /* copied from last_usermask */ SAFE(read_string(&ni->last_realmask, f)); if (ver >= 19) SAFE(read_uint32(&ni->id_stamp, f)); if (ni == &dummy_ni) free(ni->last_realmask); else put_nickinfo(ni); return 1; fail: module_log("Read error on %s", f->filename); if (ni != &dummy_ni) put_nickinfo(ni); return 0; } /*************************************************************************/ /* Load extension data for a nick group. */ static int load_one_nickgroup_ext(DBTable *table, dbFILE *f, int32 ver) { uint32 group; NickGroupInfo *ngi = NULL; NickGroupInfo dummy_ngi; /* for nonexistent nick groups */ int i; SAFE(read_uint32(&group, f)); module_log_debug(2, "loading nickgroup extension %u", group); if (!group) { if (ver < 22) { module_log("Ignoring nickgroup 0 (bug in previous versions)"); ngi = &dummy_ngi; memset(ngi, 0, sizeof(*ngi)); } else { goto fail; } } else if (!(ngi = get_nickgroupinfo(group))) { module_log("Extension data found for nonexistent nick group %u", group); ngi = &dummy_ngi; memset(ngi, 0, sizeof(*ngi)); } SAFE(read_int32(&ngi->flags, f)); SAFE(read_int32(&ngi->authcode, f)); SAFE(read_time(&ngi->authset, f)); if (ver >= 24) { SAFE(read_int16(&ngi->authreason, f)); } else { switch ((ngi->authcode & 0x300) >> 8) { case 0 : ngi->authreason = NICKAUTH_REGISTER; break; case 1 : ngi->authreason = NICKAUTH_SET_EMAIL; break; case 2 : ngi->authreason = NICKAUTH_SETAUTH; break; default: ngi->authreason = 0; break; } } SAFE(read_int16(&ngi->channelmax, f)); if (ver >= 18) { SAFE(read_int16(&ngi->ajoin_count, f)); if (ngi->ajoin_count) { ngi->ajoin = smalloc(sizeof(char *) * ngi->ajoin_count); ARRAY_FOREACH (i, ngi->ajoin) SAFE(read_string(&ngi->ajoin[i], f)); } } SAFE(read_int16(&ngi->memos.memomax, f)); if (ver >= 17) { SAFE(read_int16(&ngi->ignore_count, f)); if (ngi->ignore_count) { ngi->ignore = smalloc(sizeof(char *) * ngi->ignore_count); ARRAY_FOREACH (i, ngi->ignore) SAFE(read_string(&ngi->ignore[i], f)); } } SAFE(read_int16(&ngi->language, f)); if (!have_language(ngi->language)) ngi->language = LANG_DEFAULT; if (ver >= 15) SAFE(read_int16(&ngi->timezone, f)); SAFE(read_string(&ngi->info, f)); if (ver >= 13) SAFE(read_int16(&ngi->os_priv, f)); if (ngi == &dummy_ngi) { ARRAY_FOREACH (i, ngi->ajoin) free(ngi->ajoin[i]); free(ngi->ajoin); ARRAY_FOREACH (i, ngi->ignore) free(ngi->ignore[i]); free(ngi->ignore); } else { put_nickgroupinfo(ngi); } return 1; fail: module_log("Read error on %s", f->filename); if (ngi != &dummy_ngi) put_nickgroupinfo(ngi); return 0; } /*************************************************************************/ /* Load version 5.1 extension data for a nick group. */ static int load_one_nickgroup_ext51(DBTable *table, dbFILE *f, int32 ver) { uint16 tmp16; uint32 group; NickGroupInfo *ngi = NULL; NickGroupInfo dummy_ngi; /* for nonexistent nick groups */ int i; SAFE(read_uint32(&group, f)); module_log_debug(2, "loading nickgroup extension %u", group); if (!group) { goto fail; } else if (!(ngi = get_nickgroupinfo(group))) { module_log("5.1 extension data found for nonexistent nick group %u", group); ngi = &dummy_ngi; memset(ngi, 0, sizeof(*ngi)); init_password(&ngi->pass); } SAFE(read_string(&ngi->last_email, f)); SAFE(read_uint16(&tmp16, f)); if (ngi != &dummy_ngi && tmp16 != ngi->memos.memos_count) { module_log("Warning: memo count mismatch on nickgroup %u" " (main data: %d, ext51 data: %d)", ngi->id, ngi->memos.memos_count, tmp16); } for (i = 0; i < tmp16; i++) { time_t t; char *s; SAFE(read_time(&t, f)); SAFE(read_string(&s, f)); if (ngi != &dummy_ngi && i < ngi->memos.memos_count) { ngi->memos.memos[i].firstread = t; ngi->memos.memos[i].channel = s; } else { free(s); } } free((char *)ngi->pass.cipher); SAFE(read_string((char **)&ngi->pass.cipher, f)); if (ngi == &dummy_ngi) { ARRAY_FOREACH (i, ngi->ajoin) free(ngi->ajoin[i]); free(ngi->ajoin); ARRAY_FOREACH (i, ngi->ignore) free(ngi->ignore[i]); free(ngi->ignore); clear_password(&ngi->pass); } else { put_nickgroupinfo(ngi); } return 1; fail: module_log("Read error on %s", f->filename); if (ngi != &dummy_ngi) put_nickgroupinfo(ngi); return 0; } /*************************************************************************/ static int nick_memomax_callback(Module *mod, const char *name) { NickGroupInfo *ngi; if (strcmp(name, "memoserv/main") != 0) return 0; for (ngi = first_nickgroupinfo(); ngi; ngi = next_nickgroupinfo()) { if (ngi->memos.memomax == MSMaxMemos) ngi->memos.memomax = MEMOMAX_DEFAULT; } /* We only need to do this once */ remove_callback(NULL, "load module", nick_memomax_callback); return 0; } /*************************************************************************/ static int load_nick_table(DBTable *nick_table, DBTable *nickgroup_table) { dbFILE *f; int32 ver; int i, c; NickInfo *ni; NickGroupInfo *ngi; int failed = 0, need_memomax_check = 1; /* Open database. */ if (!(f = my_open_db_r(NickDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; /* Load original data. */ for (i = 0; i < 256 && !failed; i++) { while ((c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in nick.db"); failed = 1; } ni = load_one_nick(nick_table, nickgroup_table, f, ver); if (ni) { nick_table->insert(ni); } else { failed = 1; } } } /* Assign nickgroup IDs to groups that don't have them (e.g. from a * 4.5 database) */ for (ngi = nickgroup_table->first(); ngi; ngi = nickgroup_table->next()) { if (ngi->flags & NF_NOGROUP) { #define NEWNICKGROUP_TRIES 1000 int tries; for (tries = 0; tries < NEWNICKGROUP_TRIES; tries++) { uint32 id = rand() + rand(); if (id == 0 || id == NGI_TEMP_ID) id = 1; if (!get_nickgroupinfo(id)) { ngi->id = id; break; } } if (tries >= NEWNICKGROUP_TRIES) { module_log("load_nick_table(): unable to assign new ID to" " nickgroup for nick %s--dropping", ngi->nicks[0]); ARRAY_FOREACH (i, ngi->nicks) { if ((ni = get_nickinfo(ngi->nicks[i])) != NULL) del_nickinfo(ni); } del_nickgroupinfo(ngi); } } } /* Resolve links. First point each last_realmask field at the * NickInfo * of the appropriate nick; then copy the nickgroup ID from * each root nick to all of its children, effectively collapsing the * link hierarchies to a single level, and add the child nicks to the * root nickgroup's nick array. */ for (ni = nick_table->first(); ni; ni = nick_table->next()) { if (ni->last_realmask) { char *s = ni->last_realmask; ni->last_realmask = (char *)get_nickinfo(s); free(s); } } for (ni = nick_table->first(); ni; ni = nick_table->next()) { if (ni->last_realmask) { NickInfo *root = (NickInfo *)ni->last_realmask; NickGroupInfo *ngi; while (root->last_realmask) root = (NickInfo *)root->last_realmask; ni->nickgroup = root->nickgroup; ngi = get_nickgroupinfo(ni->nickgroup); if (!ngi) { module_log("BUG: Unable to find nickgroup %u for linked" " nick %s (parent = %s, root = %s)", ni->nickgroup, ni->nick, ((NickInfo *)ni->last_realmask)->nick, root->nick); } else { ARRAY_EXTEND(ngi->nicks); strbcpy(ngi->nicks[ngi->nicks_count-1], ni->nick); put_nickgroupinfo(ngi); } } if (!ni->nickgroup && !(ni->status & NS_VERBOTEN)) { module_log("Nick %s has no settings (linked to missing nick?)," " deleting", ni->nick); if (ni->last_realmask) put_nickinfo((NickInfo *)ni->last_realmask); ni->last_realmask = NULL; /* Don't free someone else's NickInfo */ del_nickinfo(ni); } } /* Copy all last_usermask fields to last_realmask. */ for (ni = nick_table->first(); ni; ni = nick_table->next()) { if (ni->last_realmask) put_nickinfo((NickInfo *)ni->last_realmask); ni->last_realmask = sstrdup(ni->last_usermask); } /* Load extension data if present. */ ver = 0; if (read_int32(&ver, f) == 0) { if (ver <= FILE_VERSION || ver > LOCAL_VERSION_50) { module_log("Invalid extension data version in nick.db"); failed = 1; } else { while (!failed && (c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in nick.db extension data"); failed = 1; } else if (!load_one_nick_ext(nick_table, nickgroup_table, f, ver)) { failed = 1; } } while (!failed && (c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in nick.db extension data"); failed = 1; } else if (!load_one_nickgroup_ext(nickgroup_table, f, ver)) { failed = 1; } } } need_memomax_check = 0; } if (read_int32(&ver, f) == 0) { if (ver < FIRST_VERSION_51 || ver > LOCAL_VERSION) { module_log("Invalid extension (5.1) data version in nick.db"); failed = 1; } else { while (!failed && (c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in nick.db extension (5.1)" " data"); failed = 1; } else if (!load_one_nickgroup_ext51(nickgroup_table, f, ver)){ failed = 1; } } } } if (!failed && ver < 13) { /* Need to restore Services admin/oper privs from oper.db lists */ NickGroupInfo *ngi; ARRAY_FOREACH (i, services_admins) { ni = get_nickinfo(services_admins[i]); if (ni != NULL && (ngi = get_ngi(ni)) != NULL) { ngi->os_priv = NP_SERVADMIN; put_nickgroupinfo(ngi); } put_nickinfo(ni); } ARRAY_FOREACH (i, services_opers) { ni = get_nickinfo(services_opers[i]); if (ni != NULL && (ngi = get_ngi(ni)) != NULL) { ngi->os_priv = NP_SERVOPER; put_nickgroupinfo(ngi); } put_nickinfo(ni); } } /* Add the memomax check callback if needed. */ if (!failed && need_memomax_check) add_callback(NULL, "load module", nick_memomax_callback); /* Close database. */ close_db(f); /* All done! */ return !failed || forceload; } /*************************************************************************/ static int save_nick_table(DBTable *nick_table, DBTable *nickgroup_table) { dbFILE *f; int i; NickInfo *ni; NickGroupInfo *ngi; static NickGroupInfo forbidden_ngi; /* dummy for forbidden nicks */ static time_t lastwarn = 0; if (!(f = open_db(NickDBName, "w", 11))) return 0; for (ni = nick_table->first(); ni; ni = nick_table->next()) { if (ni->nickgroup) ngi = get_nickgroupinfo(ni->nickgroup); else ngi = NULL; SAFE(write_int8(1, f)); SAFE(write_buffer(ni->nick, f)); if (ngi) { SAFE(write_buffer(ngi->pass.password, f)); SAFE(write_string(ngi->url, f)); SAFE(write_string(ngi->email, f)); } else { Password dummypass; init_password(&dummypass); if (!(ni->status & NS_VERBOTEN)) { module_log("nick %s has no NickGroupInfo, setting password" " to nick", ni->nick); encrypt_password(ni->nick, strlen(ni->nick), &dummypass); } SAFE(write_buffer(dummypass.password, f)); clear_password(&dummypass); SAFE(write_string(NULL, f)); SAFE(write_string(NULL, f)); } SAFE(write_string(ni->last_usermask, f)); SAFE(write_string(ni->last_realname, f)); SAFE(write_string(ni->last_quit, f)); SAFE(write_int32(ni->time_registered, f)); SAFE(write_int32(ni->last_seen, f)); SAFE(write_int16(ni->status, f)); if (ngi && irc_stricmp(ni->nick, ngi_mainnick(ngi)) != 0) { /* Not the main nick in the group; save it as a link */ SAFE(write_string(ngi_mainnick(ngi), f)); SAFE(write_int16(0, f)); SAFE(write_int16(0, f)); } else { int32 tmp32; /* Main nick in the group, or forbidden; save as a root nick */ SAFE(write_string(NULL, f)); SAFE(write_int16(0, f)); /* If it's forbidden, use a dummy NickGroupInfo from here on */ if (!ngi) ngi = &forbidden_ngi; /* Store top 16 bits of group ID in flags */ tmp32 = ngi->flags | 0x80000000 | (ngi->id & 0xFFFF0000)>>1; if (tmp32 & NF_KILL_IMMED) tmp32 &= ~NF_KILL_QUICK; SAFE(write_int32(tmp32, f)); SAFE(write_ptr((ngi->flags & NF_SUSPENDED) ? (void *)1 : NULL, f)); if (ngi->flags & NF_SUSPENDED) { SAFE(write_buffer(ngi->suspend_who, f)); SAFE(write_string(ngi->suspend_reason, f)); SAFE(write_int32(ngi->suspend_time, f)); SAFE(write_int32(ngi->suspend_expires, f)); } SAFE(write_int16(ngi->access_count, f)); ARRAY_FOREACH (i, ngi->access) SAFE(write_string(ngi->access[i], f)); SAFE(write_int16(ngi->memos.memos_count, f)); /* Note that we have to save the memo maximum here as a static * value; we save the real value (which may be MEMOMAX_DEFAULT) * in the extension area below. The same applies for channelmax * and language. */ if (ngi->memos.memomax == MEMOMAX_DEFAULT) SAFE(write_int16(MSMaxMemos, f)); else SAFE(write_int16(ngi->memos.memomax, f)); ARRAY_FOREACH (i, ngi->memos.memos) { SAFE(write_int32(ngi->memos.memos[i].number, f)); SAFE(write_int16(ngi->memos.memos[i].flags, f)); SAFE(write_int32(ngi->memos.memos[i].time, f)); SAFE(write_buffer(ngi->memos.memos[i].sender, f)); SAFE(write_string(ngi->memos.memos[i].text, f)); } /* Store bottom 16 bits of group ID in channelcount */ SAFE(write_int16(ngi->id & 0xFFFF, f)); if (ngi->channelmax == CHANMAX_DEFAULT) SAFE(write_int16(CSMaxReg, f)); else SAFE(write_int16(ngi->channelmax, f)); if (ngi->language == LANG_DEFAULT) SAFE(write_int16(DEF_LANGUAGE, f)); else SAFE(write_int16(ngi->language, f)); } put_nickgroupinfo(ngi); } /* for (ni) */ { /* This is an UGLY HACK but it simplifies loading. */ static char buf[256]; /* initialized to zero */ SAFE(write_buffer(buf, f)); } services_admins_count = services_opers_count = 0; SAFE(write_int32(LOCAL_VERSION_50, f)); for (ni = nick_table->first(); ni; ni = nick_table->next()) { SAFE(write_int8(1, f)); SAFE(write_string(ni->nick, f)); SAFE(write_string(ni->last_realmask, f)); SAFE(write_int32(ni->id_stamp, f)); } SAFE(write_int8(0, f)); for (ngi = nickgroup_table->first(); ngi; ngi = nickgroup_table->next()) { if (ngi->id == 0) { module_log("BUG: nickgroup with ID 0 found during write" " (skipping)"); continue; } SAFE(write_int8(1, f)); SAFE(write_int32(ngi->id, f)); SAFE(write_int32(ngi->flags, f)); SAFE(write_int32(ngi->authcode, f)); SAFE(write_time(ngi->authset, f)); SAFE(write_int16(ngi->authreason, f)); SAFE(write_int16(ngi->channelmax, f)); SAFE(write_int16(ngi->ajoin_count, f)); ARRAY_FOREACH (i, ngi->ajoin) SAFE(write_string(ngi->ajoin[i], f)); SAFE(write_int16(ngi->memos.memomax, f)); SAFE(write_int16(ngi->ignore_count, f)); ARRAY_FOREACH (i, ngi->ignore) SAFE(write_string(ngi->ignore[i], f)); SAFE(write_int16(ngi->language, f)); SAFE(write_int16(ngi->timezone, f)); SAFE(write_string(ngi->info, f)); SAFE(write_int16(ngi->os_priv, f)); if (ngi->os_priv >= NP_SERVADMIN) { strbcpy(services_admins[services_admins_count++], ngi_mainnick(ngi)); } else if (ngi->os_priv >= NP_SERVOPER) { strbcpy(services_opers[services_opers_count++], ngi_mainnick(ngi)); } } SAFE(write_int8(0, f)); SAFE(write_int32(LOCAL_VERSION, f)); for (ngi = nickgroup_table->first(); ngi; ngi = nickgroup_table->next()) { if (ngi->id == 0) { module_log("BUG: nickgroup with ID 0 found during write" " (skipping)"); continue; } SAFE(write_int8(1, f)); SAFE(write_int32(ngi->id, f)); SAFE(write_string(ngi->last_email, f)); SAFE(write_int16(ngi->memos.memos_count, f)); ARRAY_FOREACH (i, ngi->memos.memos) { SAFE(write_time(ngi->memos.memos[i].firstread, f)); SAFE(write_string(ngi->memos.memos[i].channel, f)); } SAFE(write_string(ngi->pass.cipher, f)); } SAFE(write_int8(0, f)); SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", NickDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", NickDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /********************** ChanServ database handling ***********************/ /*************************************************************************/ /* Helper functions to convert between old and new channel levels. */ static inline int16 convert_old_level(int16 old) { if (old < 0) return -convert_old_level(-old);/* avoid negative division */ else if (old <= 25) return old*10; /* 0.. 25 -> 0..250 (10x) */ else if (old <= 50) return 200 + old*2; /* 25.. 50 -> 250..300 ( 2x) */ else if (old <= 100) return 280 + old*2/5; /* 50.. 100 -> 300..320 ( 0.4x) */ else if (old <= 1000) return 300 + old/5; /* 100..1000 -> 320..500 ( 0.2x) */ else if (old <= 2000) return 400 + old/10; /* 1000..2000 -> 500..600 ( 0.1x) */ else return 500 + old/20; /* 2000..9999 -> 600..999 ( 0.05x) */ } static inline int16 convert_new_level(int16 new) { if (new < 0) return -convert_new_level(-new);/* avoid negative division */ else if (new <= 250) return new/10; /* 0..250 -> 0.. 25 */ else if (new <= 300) return new/2 - 100; /* 250..300 -> 25.. 50 */ else if (new <= 320) return new*5/2 - 700; /* 300..320 -> 50.. 100 */ else if (new <= 500) return new*5 - 1500; /* 320..500 -> 100..1000 */ else if (new <= 600) return new*10 - 4000; /* 500..600 -> 1000..2000 */ else return new*20 - 10000; /* 600..999 -> 2000..9980 */ } /*************************************************************************/ static ChannelInfo *load_one_channel(DBTable *table, dbFILE *f, int32 ver) { ChannelInfo *ci; NickInfo *ni; MemoInfo tmpmi; int16 tmp16, lev; int32 tmp32; int n_levels; char *s; int i; ci = table->newrec(); SAFE(read_buffer(ci->name, f)); module_log_debug(2, "loading channel %s", ci->name); SAFE(read_string(&s, f)); if (s) { ni = get_nickinfo(s); if (ni) { ci->founder = ni->nickgroup; put_nickinfo(ni); } free(s); } if (ver >= 7) { SAFE(read_string(&s, f)); if (s) { ni = get_nickinfo(s); if (ni) { ci->successor = ni->nickgroup; put_nickinfo(ni); } free(s); } /* Founder could be successor, which is bad, in vers 7,8 */ /* We can also have the case where two linked nicks were founder * and successor, which would give them the same group ID in this * version--remove the successor in this case as well */ if (ci->founder == ci->successor) ci->successor = 0; } init_password(&ci->founderpass); encrypt_password("a", 1, &ci->founderpass); /* get encryption type */ SAFE(read_buffer(ci->founderpass.password, f)); SAFE(read_string(&ci->desc, f)); if (!ci->desc) ci->desc = sstrdup(""); SAFE(read_string(&ci->url, f)); SAFE(read_string(&ci->email, f)); SAFE(read_int32(&tmp32, f)); ci->time_registered = tmp32; SAFE(read_int32(&tmp32, f)); ci->last_used = tmp32; SAFE(read_string(&ci->last_topic, f)); SAFE(read_buffer(ci->last_topic_setter, f)); SAFE(read_int32(&tmp32, f)); ci->last_topic_time = tmp32; SAFE(read_int32(&ci->flags, f)); ci->flags &= CF_ALLFLAGS; /* clear any invalid flags */ if (ver >= 9) { void *tmpptr; SAFE(read_ptr(&tmpptr, f)); if (tmpptr) { SAFE(read_buffer(ci->suspend_who, f)); SAFE(read_string(&ci->suspend_reason, f)); SAFE(read_int32(&tmp32, f)); ci->suspend_time = tmp32; SAFE(read_int32(&tmp32, f)); ci->suspend_expires = tmp32; ci->flags |= CF_SUSPENDED; } } SAFE(read_int16(&tmp16, f)); n_levels = tmp16; reset_levels(ci); for (i = 0; i < n_levels; i++) { SAFE(read_int16(&lev, f)); if (i < CA_SIZE) ci->levels[i] = convert_old_level(lev); } SAFE(read_int16(&ci->access_count, f)); if (ci->access_count) { ci->access = scalloc(ci->access_count, sizeof(ChanAccess)); ARRAY_FOREACH (i, ci->access) { ci->access[i].channel = ci; SAFE(read_int16(&tmp16, f)); /* in_use */ if (tmp16) { SAFE(read_int16(&lev, f)); ci->access[i].level = convert_old_level(lev); SAFE(read_string(&s, f)); if (s) { ni = get_nickinfo(s); if (ni) { ci->access[i].nickgroup = ni->nickgroup; put_nickinfo(ni); } free(s); } } } } else { ci->access = NULL; } SAFE(read_int16(&ci->akick_count, f)); if (ci->akick_count) { ci->akick = scalloc(ci->akick_count, sizeof(AutoKick)); ARRAY_FOREACH (i, ci->akick) { ci->akick[i].channel = ci; SAFE(read_int16(&tmp16, f)); /* in_use */ if (tmp16) { SAFE(read_int16(&tmp16, f)); /* is_nick */ SAFE(read_string(&s, f)); if (tmp16) { ci->akick[i].mask = smalloc(strlen(s)+5); sprintf(ci->akick[i].mask, "%s!*@*", s); free(s); } else { ci->akick[i].mask = s; } SAFE(read_string(&ci->akick[i].reason, f)); if (ver >= 8) SAFE(read_buffer(ci->akick[i].who, f)); else *ci->akick[i].who = 0; time(&ci->akick[i].set); ci->akick[i].lastused = 0; } /* if (in_use) */ } /* for (i = 0..ci->akick_count-1) */ } else { ci->akick = NULL; } if (ver < 10) { SAFE(read_int16(&tmp16, f)); ci->mlock.on = tmp16; SAFE(read_int16(&tmp16, f)); ci->mlock.off = tmp16; } else { SAFE(read_int32(&ci->mlock.on, f)); SAFE(read_int32(&ci->mlock.off, f)); } SAFE(read_int32(&ci->mlock.limit, f)); SAFE(read_string(&ci->mlock.key, f)); ci->mlock.on &= ~chanmode_reg; /* check_modes() takes care of this */ SAFE(read_int16(&tmpmi.memos_count, f)); SAFE(read_int16(&tmpmi.memomax, f)); if (tmpmi.memos_count) { for (i = 0; i < tmpmi.memos_count; i++) { Memo tmpmemo; SAFE(read_uint32(&tmpmemo.number, f)); SAFE(read_int16(&tmpmemo.flags, f)); SAFE(read_int32(&tmp32, f)); tmpmemo.time = tmp32; SAFE(read_buffer(tmpmemo.sender, f)); SAFE(read_string(&tmpmemo.text, f)); free(tmpmemo.text); } } SAFE(read_string(&ci->entry_message, f)); ci->c = NULL; return ci; fail: module_log("Read error on %s", f->filename); return NULL; } /*************************************************************************/ /* Load extension data for a channel. */ static int load_one_channel_ext(DBTable *table, dbFILE *f, int32 ver) { char *name; ChannelInfo *ci = NULL; ChannelInfo dummy_ci; /* for nonexistent channels */ int i; int16 count, tmp16; SAFE(read_string(&name, f)); if (!name) goto fail; module_log_debug(2, "loading channel extension %s", name); if (!(ci = get_channelinfo(name))) { module_log("Extension data found for nonexistent channel `%s'", name); ci = &dummy_ci; memset(ci, 0, sizeof(*ci)); } free(name); name = NULL; SAFE(read_int16(&tmp16, f)); /* was memomax */ if (ver >= 14) { if (ver >= 23) { SAFE(read_int16(&count, f)); if (count != ci->akick_count && ci != &dummy_ci) { module_log("warning: autokick mismatch in extension data" " for channel %s (corrupt database?): expected" " %d, got %d", ci->name, ci->akick_count, count); } } else { count = ci->akick_count; } for (i = 0; i < count; i++) { if (i < ci->akick_count) { SAFE(read_time(&ci->akick[i].set, f)); SAFE(read_time(&ci->akick[i].lastused, f)); } else { time_t t; SAFE(read_time(&t, f)); SAFE(read_time(&t, f)); } } } if (ver >= 16) { SAFE(read_string(&ci->mlock.link, f)); SAFE(read_string(&ci->mlock.flood, f)); } if (ver >= 25) SAFE(read_int32(&ci->mlock.joindelay, f)); if (ver >= 27) { SAFE(read_int32(&ci->mlock.joinrate1, f)); SAFE(read_int32(&ci->mlock.joinrate2, f)); } if (ver >= 20) { int16 lev; SAFE(read_int16(&count, f)); if (count) { reset_levels(ci); for (i = 0; i < count; i++) { SAFE(read_int16(&lev, f)); if (i < CA_SIZE) ci->levels[i] = lev; } if (ver == 20) { if (ci->levels[CA_AUTODEOP] == -10) ci->levels[CA_AUTODEOP] = -1; if (ci->levels[CA_NOJOIN] == -20) ci->levels[CA_NOJOIN] = -100; } } SAFE(read_int16(&count, f)); if (count != ci->access_count && ci != &dummy_ci) { module_log("warning: access count mismatch in extension data" " for channel %s (corrupt database?): expected %d," " got %d", ci->name, ci->access_count, count); } for (i = 0; i < count; i++) { SAFE(read_int16(&lev, f)); if (i < ci->access_count) ci->access[i].level = lev; } } if (ci == &dummy_ci) { free(ci->mlock.link); free(ci->mlock.flood); } else { put_channelinfo(ci); } return 1; fail: module_log("Read error on %s", f->filename); if (ci != &dummy_ci) put_channelinfo(ci); return 0; } /*************************************************************************/ /* Load version 5.1 extension data for a channel. */ static int load_one_channel_ext51(DBTable *table, dbFILE *f, int32 ver) { char *name; ChannelInfo *ci = NULL; ChannelInfo dummy_ci; /* for nonexistent channels */ char *s; SAFE(read_string(&name, f)); if (!name) goto fail; module_log_debug(2, "loading channel extension (5.1) %s", name); if (!(ci = get_channelinfo(name))) { module_log("5.1 extension data found for nonexistent channel `%s'", name); ci = &dummy_ci; memset(ci, 0, sizeof(*ci)); init_password(&ci->founderpass); } free(name); name = NULL; SAFE(read_string(&s, f)); if (s) ci->mlock.on = mode_string_to_flags(s, MODE_CHANNEL|MODE_NOERROR); free(s); SAFE(read_string(&s, f)); if (s) ci->mlock.off = mode_string_to_flags(s, MODE_CHANNEL|MODE_NOERROR); free(s); free((char *)ci->founderpass.cipher); SAFE(read_string((char **)&ci->founderpass.cipher, f)); if (ci == &dummy_ci) { clear_password(&ci->founderpass); } else { put_channelinfo(ci); } return 1; fail: module_log("Read error on %s", f->filename); if (ci != &dummy_ci) put_channelinfo(ci); return 0; } /*************************************************************************/ static int load_chan_table(DBTable *table) { dbFILE *f; int32 ver; int i, c; ChannelInfo *ci; int failed = 0; /* Open database. */ if (!(f = my_open_db_r(ChanDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; /* Load original data. */ for (i = 0; i < 256 && !failed; i++) { while ((c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in %s", ChanDBName); failed = 1; break; } ci = load_one_channel(table, f, ver); if (ci) { if (strcmp(ci->name, "#") == 0) { module_log("Deleting unsupported channel \"#\""); table->freerec(ci); } else if (!(ci->flags & CF_VERBOTEN) && !ci->founder) { /* Delete non-forbidden channels with no founder. These * can crop up if the nick and channel databases get out * of sync and the founder's nick has disappeared. Note * that we ignore the successor here, but since this * shouldn't happen normally anyway, no big deal. */ module_log("load channel database: Deleting founderless" " channel %s", ci->name); table->freerec(ci); } else { NickGroupInfo *ngi = get_nickgroupinfo(ci->founder); if (ngi) { ARRAY_EXTEND(ngi->channels); strbcpy(ngi->channels[ngi->channels_count-1],ci->name); put_nickgroupinfo(ngi); } table->insert(ci); } } else { failed = 1; break; } } } /* Load extension data if present. */ if (!failed && read_int32(&ver, f) == 0) { if (ver <= FILE_VERSION || ver > LOCAL_VERSION_50) { module_log("Invalid extension data version in %s", ChanDBName); failed = 1; } while (!failed && (c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in %s extension data", ChanDBName); failed = 1; } else { failed = !load_one_channel_ext(table, f, ver); } } } if (ver < 26) { /* Reset all AUTODEOP/NOJOIN levels to the defaults (version 4.x * databases may have them set to non-default levels, and version 5 * doesn't allow them to be changed) */ for (ci = table->first(); ci; ci = table->next()) { if (ci->levels) { ci->levels[CA_AUTODEOP] = -1; ci->levels[CA_NOJOIN] = -100; } } } /* Clean out all empty (mask==NULL) autokick entries */ for (ci = table->first(); ci; ci = table->next()) { int i; ARRAY_FOREACH (i, ci->akick) { if (!ci->akick[i].mask) { ARRAY_REMOVE(ci->akick, i); i--; } } } if (!failed && read_int32(&ver, f) == 0) { if (ver < FIRST_VERSION_51 || ver > LOCAL_VERSION) { module_log("Invalid 5.1 extension data version in %s", ChanDBName); failed = 1; } while (!failed && (c = getc_db(f)) != 0) { if (c != 1) { module_log("Invalid format in %s 5.1 extension data", ChanDBName); failed = 1; } else { failed = !load_one_channel_ext51(table, f, ver); } } } /* Close database and return. */ close_db(f); return !failed || forceload; } /*************************************************************************/ static int save_chan_table(DBTable *table) { dbFILE *f; int i; ChannelInfo *ci; NickGroupInfo *ngi; static time_t lastwarn = 0; if (!(f = open_db(ChanDBName, "w", 11))) return 0; for (ci = table->first(); ci; ci = table->next()) { SAFE(write_int8(1, f)); SAFE(write_buffer(ci->name, f)); if (ci->founder && (ngi = get_ngi_id(ci->founder))) { SAFE(write_string(ngi_mainnick(ngi), f)); put_nickgroupinfo(ngi); } else { SAFE(write_string(NULL, f)); } if (ci->successor && (ngi = get_ngi_id(ci->successor))) { SAFE(write_string(ngi_mainnick(ngi), f)); put_nickgroupinfo(ngi); } else { SAFE(write_string(NULL, f)); } SAFE(write_buffer(ci->founderpass.password, f)); SAFE(write_string(ci->desc, f)); SAFE(write_string(ci->url, f)); SAFE(write_string(ci->email, f)); SAFE(write_int32(ci->time_registered, f)); SAFE(write_int32(ci->last_used, f)); SAFE(write_string(ci->last_topic, f)); SAFE(write_buffer(ci->last_topic_setter, f)); SAFE(write_int32(ci->last_topic_time, f)); SAFE(write_int32(ci->flags, f)); SAFE(write_ptr(ci->flags & CF_SUSPENDED ? (void *)1 : NULL, f)); if (ci->flags & CF_SUSPENDED) { SAFE(write_buffer(ci->suspend_who, f)); SAFE(write_string(ci->suspend_reason, f)); SAFE(write_int32(ci->suspend_time, f)); SAFE(write_int32(ci->suspend_expires, f)); } if (ci->levels) { SAFE(write_int16(CA_SIZE, f)); for (i = 0; i < CA_SIZE; i++) SAFE(write_int16(convert_new_level(ci->levels[i]), f)); } else { SAFE(write_int16(CA_SIZE_4_5, f)); for (i = 0; i < CA_SIZE_4_5; i++) { if (i == CA_NOJOIN && (ci->flags & CF_RESTRICTED)) SAFE(write_int16(0, f)); else SAFE(write_int16(def_levels_4_5[i], f)); } } SAFE(write_int16(ci->access_count, f)); ARRAY_FOREACH (i, ci->access) { if (ci->access[i].nickgroup) ngi = get_ngi_id(ci->access[i].nickgroup); else ngi = NULL; SAFE(write_int16(ngi != NULL, f)); if (ngi) { SAFE(write_int16(convert_new_level(ci->access[i].level), f)); SAFE(write_string(ngi_mainnick(ngi), f)); put_nickgroupinfo(ngi); } } SAFE(write_int16(ci->akick_count, f)); ARRAY_FOREACH (i, ci->akick) { SAFE(write_int16((ci->akick[i].mask != NULL), f)); /* in_use */ if (ci->akick[i].mask) { SAFE(write_int16(0, f)); /* is_nick */ SAFE(write_string(ci->akick[i].mask, f)); SAFE(write_string(ci->akick[i].reason, f)); SAFE(write_buffer(ci->akick[i].who, f)); } } SAFE(write_int32(ci->mlock.on, f)); SAFE(write_int32(ci->mlock.off, f)); SAFE(write_int32(ci->mlock.limit, f)); SAFE(write_string(ci->mlock.key, f)); SAFE(write_int16(0, f)); /* memos_count */ SAFE(write_int16(MSMaxMemos, f)); /* memomax */ SAFE(write_string(ci->entry_message, f)); } /* for (ci) */ { /* This is an UGLY HACK but it simplifies loading. */ static char buf[256]; /* initialized to zero */ SAFE(write_buffer(buf, f)); } SAFE(write_int32(LOCAL_VERSION_50, f)); for (ci = table->first(); ci; ci = table->next()) { SAFE(write_int8(1, f)); SAFE(write_string(ci->name, f)); SAFE(write_int16(MEMOMAX_DEFAULT, f)); /* for 5.0's sake */ SAFE(write_int16(ci->akick_count, f)); ARRAY_FOREACH (i, ci->akick) { SAFE(write_time(ci->akick[i].set, f)); SAFE(write_time(ci->akick[i].lastused, f)); } SAFE(write_string(ci->mlock.link, f)); SAFE(write_string(ci->mlock.flood, f)); SAFE(write_int32(ci->mlock.joindelay, f)); SAFE(write_int32(ci->mlock.joinrate1, f)); SAFE(write_int32(ci->mlock.joinrate2, f)); if (ci->levels) { SAFE(write_int16(CA_SIZE, f)); for (i = 0; i < CA_SIZE; i++) SAFE(write_int16(ci->levels[i], f)); } else { SAFE(write_int16(0, f)); } SAFE(write_int16(ci->access_count, f)); ARRAY_FOREACH (i, ci->access) SAFE(write_int16(ci->access[i].level, f)); } SAFE(write_int8(0, f)); SAFE(write_int32(LOCAL_VERSION, f)); for (ci = table->first(); ci; ci = table->next()) { SAFE(write_string(mode_flags_to_string(ci->mlock.on,MODE_CHANNEL),f)); SAFE(write_string(mode_flags_to_string(ci->mlock.off,MODE_CHANNEL),f)); SAFE(write_string(ci->founderpass.cipher, f)); } SAFE(write_int8(0, f)); SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", ChanDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", ChanDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /********************** OperServ database handling ***********************/ /*************************************************************************/ static int load_oper_table(DBTable *table) { dbFILE *f; int32 ver; int16 i, n; DBField *field; void *record; /* pointer to OperServ's data structure */ int8 no_supass = 1; Password *supass = NULL; if (!(record = table->first())) { module_log("BUG: record missing from OperServ table!"); return 0; } if (table->next()) { module_log("BUG: too many records in OperServ table!"); return 0; } if (!(f = my_open_db_r(OperDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; services_admins_count = services_opers_count = 0; SAFE(read_int16(&n, f)); for (i = 0; i < n; i++) { char *s; SAFE(read_string(&s, f)); if (s && i < MAX_SERVADMINS) strbcpy(services_admins[services_admins_count++], s); free(s); } SAFE(read_int16(&n, f)); for (i = 0; i < n; i++) { char *s; SAFE(read_string(&s, f)); if (s && i < MAX_SERVOPERS) strbcpy(services_opers[services_opers_count++], s); free(s); } if (ver >= 7) { int32 tmp32; SAFE(read_int32(&tmp32, f)); for (field = table->fields; field->name; field++) { if (strcmp(field->name, "maxusercnt") == 0) { if (field->type != DBTYPE_INT32) { module_log("BUG: oper.maxusercnt type is not INT32!"); goto fail; } *((int32 *)DB_FIELDPTR(record,field)) = tmp32; break; } } SAFE(read_int32(&tmp32, f)); for (field = table->fields; field->name; field++) { if (strcmp(field->name, "maxusertime") == 0) { if (field->type != DBTYPE_TIME) { module_log("BUG: oper.maxusertime type is not TIME!"); goto fail; } *((time_t *)DB_FIELDPTR(record,field)) = tmp32; break; } } } if (ver >= 9) { SAFE(read_int8(&no_supass, f)); for (field = table->fields; field->name; field++) { if (strcmp(field->name, "no_supass") == 0) { if (field->type != DBTYPE_INT8) { module_log("BUG: oper.no_supass type is not INT8!"); goto fail; } *((int8 *)DB_FIELDPTR(record,field)) = no_supass; break; } } if (!no_supass) { Password tmppass; init_password(&tmppass); encrypt_password("a", 1, &tmppass); SAFE(read_buffer(tmppass.password, f)); for (field = table->fields; field->name; field++) { if (strcmp(field->name, "supass") == 0) { if (field->type != DBTYPE_PASSWORD) { module_log("BUG: oper.supass type is not PASSWORD!"); goto fail; } supass = (Password *)DB_FIELDPTR(record,field); init_password(supass); copy_password(supass, &tmppass); break; } } } } if (read_int32(&ver, f) == 0) { if (ver < FIRST_VERSION_51 || ver > LOCAL_VERSION) { module_log("Invalid 5.1 extension data version in %s", OperDBName); close_db(f); return 0; } SAFE(read_string((char **)&supass->cipher, f)); } close_db(f); return 1; fail: close_db(f); module_log("Read error on %s", OperDBName); return 0; } /*************************************************************************/ static int save_oper_table(DBTable *table) { dbFILE *f; int16 i; void *record; DBField *field; static time_t lastwarn = 0; int8 no_supass = 1; Password *supass = NULL; if (!(record = table->first())) { module_log("BUG: record missing from OperServ table!"); return 0; } if (table->next()) { module_log("BUG: too many records in OperServ table!"); return 0; } if (!(f = open_db(OperDBName, "w", 11))) return 0; SAFE(write_int16(services_admins_count, f)); ARRAY_FOREACH (i, services_admins) SAFE(write_string(services_admins[i], f)); SAFE(write_int16(services_opers_count, f)); ARRAY_FOREACH (i, services_opers) SAFE(write_string(services_opers[i], f)); for (field = table->fields; field->name; field++) { if (strcmp(field->name, "maxusercnt") == 0) { if (field->type != DBTYPE_INT32) { module_log("BUG: oper.maxusercnt type is not INT32!"); goto fail; } SAFE(write_int32(*((int32 *)DB_FIELDPTR(record,field)), f)); break; } } for (field = table->fields; field->name; field++) { if (strcmp(field->name, "maxusertime") == 0) { if (field->type != DBTYPE_TIME) { module_log("BUG: oper.maxusertime type is not TIME!"); goto fail; } SAFE(write_int32((int32) *((time_t *)DB_FIELDPTR(record,field)), f)); break; } } for (field = table->fields; field->name; field++) { if (strcmp(field->name, "no_supass") == 0) { if (field->type != DBTYPE_INT8) { module_log("BUG: oper.no_supass type is not INT8!"); goto fail; } no_supass = *((int8 *)DB_FIELDPTR(record,field)); SAFE(write_int8(no_supass, f)); break; } } if (!no_supass) { for (field = table->fields; field->name; field++) { if (strcmp(field->name, "supass") == 0) { if (field->type != DBTYPE_PASSWORD) { module_log("BUG: oper.supass type is not PASSWORD!"); goto fail; } supass = (Password *)DB_FIELDPTR(record,field); SAFE(write_buffer(supass->password, f)); break; } } } SAFE(write_int32(LOCAL_VERSION, f)); if (!no_supass) SAFE(write_string(supass->cipher, f)); SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", OperDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", OperDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /************************ News database handling *************************/ /*************************************************************************/ static int load_news_table(DBTable *table) { dbFILE *f; int32 ver; int i; int16 count; if (!(f = my_open_db_r(NewsDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; #if CLEAN_COMPILE count = 0; #endif SAFE(read_int16(&count, f)); for (i = 0; i < count; i++) { int32 tmp32; NewsItem *news = table->newrec(); SAFE(read_int16(&news->type, f)); SAFE(read_int32(&news->num, f)); SAFE(read_string(&news->text, f)); SAFE(read_buffer(news->who, f)); SAFE(read_int32(&tmp32, f)); news->time = tmp32; table->insert(news); } close_db(f); return 1; fail: close_db(f); module_log("Read error on %s", NewsDBName); return 0; } /*************************************************************************/ static int save_news_table(DBTable *table) { dbFILE *f; int count, i; NewsItem *news; static time_t lastwarn = 0; if (!(f = open_db(NewsDBName, "w", 11))) return 0; count = 0; for (news = table->first(); news; news = table->next()) count++; if (count > 32767) count = 32767; // avoid overflow write_int16((int16)count, f); i = 0; for (news = table->first(), i = 0; i < count; news = table->next(), i++) { if (!news) { module_log("BUG: news item count changed while saving!"); wallops(NULL, "Error saving %s! Please check log file.", NewsDBName); restore_db(f); return 0; } SAFE(write_int16(news->type, f)); SAFE(write_int32(news->num, f)); SAFE(write_string(news->text, f)); SAFE(write_buffer(news->who, f)); SAFE(write_int32(news->time, f)); } SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", NewsDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", NewsDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /********************** Autokill database handling ***********************/ /*************************************************************************/ static int load_akill_table(DBTable *akill_table, DBTable *exclude_table) { dbFILE *f; int32 ver; if (!(f = my_open_db_r(AutokillDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; if (!read_maskdata(akill_table, MD_AKILL, AutokillDBName, f)) return 0; if (getc_db(f) == 1) { if (!read_maskdata(exclude_table, MD_EXCLUDE, AutokillDBName, f)) return 0; } close_db(f); return 1; } /*************************************************************************/ static int save_akill_table(DBTable *akill_table, DBTable *exclude_table) { dbFILE *f; static time_t lastwarn = 0; if (!(f = open_db(AutokillDBName, "w", 11))) return 0; if (!write_maskdata(akill_table, MD_AKILL, AutokillDBName, f)) return 0; SAFE(write_int8(1, f)); if (!write_maskdata(exclude_table, MD_EXCLUDE, AutokillDBName, f)) return 0; SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", AutokillDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", AutokillDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /********************** Exception database handling **********************/ /*************************************************************************/ static int load_exception_table(DBTable *table) { dbFILE *f; int32 ver; if (!(f = my_open_db_r(ExceptionDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; if (!read_maskdata(table, MD_EXCEPTION, ExceptionDBName, f)) return 0; close_db(f); return 1; } /*************************************************************************/ static int save_exception_table(DBTable *table) { dbFILE *f; static time_t lastwarn = 0; if (!(f = open_db(ExceptionDBName, "w", 11))) return 0; if (!write_maskdata(table, MD_EXCEPTION, ExceptionDBName, f)) return 0; SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", ExceptionDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", ExceptionDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /*********************** S-line database handling ************************/ /*************************************************************************/ static int load_sline_table(DBTable *sgline_table, DBTable *sqline_table, DBTable *szline_table) { dbFILE *f; int32 ver; if (!(f = my_open_db_r(SlineDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; if (!read_maskdata(sgline_table, MD_SGLINE, SlineDBName, f)) return 0; if (!read_maskdata(sqline_table, MD_SQLINE, SlineDBName, f)) return 0; if (!read_maskdata(szline_table, MD_SZLINE, SlineDBName, f)) return 0; close_db(f); return 1; } /*************************************************************************/ static int save_sline_table(DBTable *sgline_table, DBTable *sqline_table, DBTable *szline_table) { dbFILE *f; static time_t lastwarn = 0; if (!(f = open_db(SlineDBName, "w", 11))) return 0; if (!write_maskdata(sgline_table, MD_SGLINE, SlineDBName, f)) return 0; if (!write_maskdata(sqline_table, MD_SQLINE, SlineDBName, f)) return 0; if (!write_maskdata(szline_table, MD_SZLINE, SlineDBName, f)) return 0; SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", SlineDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", SlineDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /********************** StatServ database handling ***********************/ /*************************************************************************/ static ServerStats *load_one_serverstats(DBTable *table, dbFILE *f) { ServerStats *ss; int32 tmp32; ss = table->newrec(); SAFE(read_string(&ss->name, f)); SAFE(read_int32(&tmp32, f)); ss->t_join = tmp32; SAFE(read_int32(&tmp32, f)); /* t_quit */ /* Avoid join>=quit staying true on load (which would indicate that the * server is online even before any server connections are processed) */ ss->t_quit = time(NULL)-1; if (ss->t_join >= ss->t_quit) ss->t_join = ss->t_quit-1; SAFE(read_string(&ss->quit_message, f)); return ss; fail: module_log("Read error on %s", f->filename); return NULL; } /*************************************************************************/ static int load_one_serverstats_ext(DBTable *table, dbFILE *f, int32 ver) { ServerStats *ss = NULL; char *servername; SAFE(read_string(&servername, f)); if (!servername) goto fail; ss = get_serverstats(servername); if (!ss) { module_log("Extension data found for nonexistent server `%s'", servername); free(servername); return 0; } free(servername); SAFE(read_time(&ss->t_join, f)); put_serverstats(ss); return 1; fail: module_log("Read error on %s", f->filename); put_serverstats(ss); return 0; } /*************************************************************************/ static int load_stat_servers_table(DBTable *table) { dbFILE *f; int32 ver, i, nservers; int16 tmp16; int failed = 0; ServerStats *ss; /* Open database. */ if (!(f = my_open_db_r(StatDBName, &ver))) return 1; else if (f == OPENDB_ERROR) return 0; /* Load original data. */ SAFE(read_int16(&tmp16, f)); nservers = tmp16; for (i = 0; i < nservers && !failed; i++) { ss = load_one_serverstats(table, f); if (ss) table->insert(ss); else failed = 1; } /* Load extension data if present. */ if (!failed && read_int32(&ver, f) == 0) { int32 moreservers; if (ver <= FILE_VERSION || ver > LOCAL_VERSION_50) { module_log("Invalid extension data version in %s", StatDBName); } else { SAFE(read_int32(&moreservers, f)); for (i = 0; i < moreservers && !failed; i++) { ss = load_one_serverstats(table, f); if (ss) table->insert(ss); else failed = 1; } nservers += moreservers; for (i = 0; i < nservers && !failed; i++) failed = !load_one_serverstats_ext(table, f, ver); } } /* Close database and return. */ close_db(f); return !failed || forceload; fail: close_db(f); module_log("Read error on %s", StatDBName); return 0; } /*************************************************************************/ static int save_stat_servers_table(DBTable *table) { dbFILE *f; int32 count, realcount, i; ServerStats *ss; static time_t lastwarn = 0; if (!(f = open_db(StatDBName, "w", 11))) return 0; realcount = 0; for (ss = table->first(); ss; ss = table->next()) realcount++; if (realcount > 32767) /* Well, you never know... */ count = 32767; else count = realcount; SAFE(write_int16((int16)count, f)); for (ss = table->first(), i = 0; i < count; ss = table->next(), i++) { if (!ss) { module_log("BUG: save_stat_servers_table(): ss NULL but i <" " count!"); wallops(NULL, "Error saving %s! Please check log file.", StatDBName); restore_db(f); return 0; } SAFE(write_string(ss->name, f)); SAFE(write_int32(ss->t_join, f)); SAFE(write_int32(ss->t_quit, f)); SAFE(write_string(ss->quit_message, f)); } SAFE(write_int32(LOCAL_VERSION_50, f)); if (realcount > count) { SAFE(write_int32(realcount-count, f)); for (; i < realcount; ss = table->next(), i++) { if (!ss) { module_log("BUG: save_stat_servers_table(): ss NULL but i <" " realcount!"); wallops(NULL, "Error saving %s! Please check log file.", StatDBName); restore_db(f); return 0; } SAFE(write_string(ss->name, f)); SAFE(write_int32(ss->t_join, f)); SAFE(write_int32(ss->t_quit, f)); SAFE(write_string(ss->quit_message, f)); } } else { SAFE(write_int32(0, f)); } for (ss = table->first(); ss; ss = table->next()) { SAFE(write_string(ss->name, f)); SAFE(write_time(ss->t_join, f)); } SAFE(close_db(f)); return 1; fail: restore_db(f); module_log_perror("Write error on %s", StatDBName); if (time(NULL) - lastwarn > WarningTimeout) { wallops(NULL, "Write error on %s: %s", StatDBName, strerror(errno)); lastwarn = time(NULL); } return 0; } /*************************************************************************/ /*********************** Generic database handling ***********************/ /*************************************************************************/ /* Routines used for databases not part of the v4/v5.0 set */ #define INCLUDE_IN_VERSION4 #define standard_load_table load_generic_table #define standard_save_table save_generic_table #include "standard.c" #undef INCLUDE_IN_VERSION4 #undef standard_load_table #undef standard_save_table /*************************************************************************/ /***************************** Module stuff ******************************/ /*************************************************************************/ ConfigDirective module_config[] = { { "AutokillDB", { { CD_STRING, CF_DIRREQ, &AutokillDBName } } }, { "ChanServDB", { { CD_STRING, CF_DIRREQ, &ChanDBName } } }, { "ExceptionDB", { { CD_STRING, CF_DIRREQ, &ExceptionDBName } } }, { "NewsDB", { { CD_STRING, CF_DIRREQ, &NewsDBName } } }, { "NickServDB", { { CD_STRING, CF_DIRREQ, &NickDBName } } }, { "OperServDB", { { CD_STRING, CF_DIRREQ, &OperDBName } } }, { "SlineDB", { { CD_STRING, CF_DIRREQ, &SlineDBName } } }, { "StatServDB", { { CD_STRING, CF_DIRREQ, &StatDBName } } }, { NULL } };   static DBModule dbmodule_version4 = { .load_table = version4_load_table, .save_table = version4_save_table, }; /*************************************************************************/ int init_module(void) { if (!init_extsyms(MODULE_NAME)) { exit_module(0); return 0; } if (!register_dbmodule(&dbmodule_version4)) { module_log("Unable to register module with database core"); exit_module(0); return 0; } return 1; } /*************************************************************************/ int exit_module(int shutdown) { unregister_dbmodule(&dbmodule_version4); exit_extsyms(); return 1; } /*************************************************************************/ /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */


 
Alıntı ile Cevapla

IRCForumlari.NET Reklamlar
sohbet odaları eglen sohbet reklamver