IRCForumları - IRC ve mIRC Kullanıcılarının Buluşma Noktası
  sohbet

 Kayıt ol  Topluluk
4Beğeni(ler)

Yeni Konu aç Cevapla
 
LinkBack Seçenekler Stil
Alt 09 Eylül 2010, 17:51   #41
Çevrimdışı
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.)




Kod:   Kodu kopyalamak için üzerine çift tıklayın!
count = mem = 0; for (ngi = first_nickgroupinfo(); ngi; ngi = next_nickgroupinfo()) { count++; mem += sizeof(*ngi); if (ngi->url) mem += strlen(ngi->url)+1; if (ngi->email) mem += strlen(ngi->email)+1; if (ngi->info) mem += strlen(ngi->info)+1;

Böyle bir kısım var senin kullandiğin services versiyonu ileri olduğu için değişiktir.

 
Alıntı ile Cevapla

IRCForumlari.NET Reklamlar
sohbet odaları reklam ver Benimmekan Mobil Sohbet
Alt 09 Eylül 2010, 18:59   #42
Çevrimdışı
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

Alt 09 Eylül 2010, 19:04   #43
Çevrimdışı
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.)




Sanırım Kullandiğiniz versiyon ( hiç incelemedim ) o yapiyi kendiliğinden destekliyor o kodlari es geçebilirsiniz. O Kodlari eklemeden 1 den fazla üst üste /ns set burc Yengec komutunu kullaniniz. Eğer işlevini doğru şekilde yerine getiriyorsa bir sorun olmayacaktir.

Ayrica modulleri tek bir modul olarak buradan indirebilirsiniz.

Burdan İndir Bu forumdaki ekleri görübilmek için 25 mesaja sahip olmanız gerekir. Sizin 0 Mesajınız var.

Konu toXic tarafından (09 Eylül 2010 Saat 19:11 ) değiştirilmiştir.
 
Alıntı ile Cevapla

Alt 09 Eylül 2010, 20:18   #44
Çevrimdışı
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.)




Güzel paylaşım tebrikler

 
Alıntı ile Cevapla

Alt 01 Şubat 2012, 19:10   #45
Çevrimdışı
Kullanıcıların profil bilgileri misafirlere kapatılmıştır.
IF Ticaret Sayısı: (0)
IF Ticaret Yüzdesi:(%)
Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)




son aşamadaki version4.c ye bende ekleyemedim. Eklemeye çalıştığım yerde hata verdi bakabilirmisin @[Üye Olmadan Linkleri Göremezsiniz. Üye Olmak için TIKLAYIN...]?

PHP 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: <achurch[MENTION=117372]ach[/MENTION]urch.org>
 * 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 0services_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_tableDBTable *nickgroup_table);
static 
int save_nick_table(DBTable *nick_tableDBTable *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_tableDBTable *exclude_table);
static 
int save_akill_table(DBTable *akill_tableDBTable *exclude_table);
static 
int load_exception_table(DBTable *table);
static 
int save_exception_table(DBTable *table);
static 
int load_sline_table(DBTable *sgline_tableDBTable *sqline_table,
                            
DBTable *szline_table);
static 
int save_sline_table(DBTable *sgline_tableDBTable *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_tablenickgroup_table);
        
nick_table nickgroup_table NULL;
    }
    if (
akill_table && exclude_table) {
        
retval load_akill_table(akill_tableexclude_table);
        
akill_table exclude_table NULL;
    }
    if (
sgline_table && sqline_table && szline_table) {
        
retval load_sline_table(sgline_tablesqline_tableszline_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_tablenickgroup_table);
        
nick_table nickgroup_table NULL;
        return 
retval;
    }
    if (
akill_table && exclude_table) {
        
int retval save_akill_table(akill_tableexclude_table);
        
akill_table exclude_table NULL;
        return 
retval;
    }
    if (
sgline_table && sqline_table && szline_table) {
        
int retval =
            
save_sline_table(sgline_tablesqline_tableszline_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 *dbnameint32 *ver_ret)
{
    
dbFILE *f;
    
int32 ver;

    
open_db(dbname"r"0);
    if (!
f)
        return 
NULL;
    
ver get_file_version(f);
    if (
ver || 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 *tableuint8 type, const char *dbname,
                         
dbFILE *f)
{
    
int32 ver;
    
MaskData *md;
    
int16 count;
    
int i;

#if CLEAN_COMPILE
    
count 0;
#endif
    
SAFE(read_int16(&countf));
    for (
0counti++) {
        
int32 t---2;
        
md table->newrec();
        
SAFE(read_string(&md->maskf));
        if (
type == MD_EXCEPTION) {
            
SAFE(read_int16(&md->limitf));
            
SAFE(read_buffer(md->whof));
            
SAFE(read_string(&md->reasonf));
        } else {
            
SAFE(read_string(&md->reasonf));
            
SAFE(read_buffer(md->whof));
        }
        
SAFE(read_int32(&t---2f));
        
md->time t---2;
        
SAFE(read_int32(&t---2f));
        
md->expires t---2;
        
md->num i+1;
        
table->insert(md);
    }
    if (
read_int32(&verf) == 0) {
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION) {
            
module_log("Invalid extension data version in %s"dbname);
            return 
0;
        }
        for (
0counti++) {
            
/* O(n^2), but we can't help it if we want to be robust */
            
for (md table->first(); mdmd table->next()) {
                if (
md->num == i+1)
                    break;
            }
            if (
md) {
                
SAFE(read_time(&md->timef));
                
SAFE(read_time(&md->expiresf));
                
SAFE(read_time(&md->lastusedf));
            }
        }
    }
    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 *tableuint8 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(); mdmd table->next())
        
count++;
    
write_int16(countf);
    
/* 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(); mdmd table->next()) {
        
SAFE(write_string(md->maskf));
        if (
type == MD_EXCEPTION) {
            
SAFE(write_int16(md->limitf));
            
SAFE(write_buffer(md->whof));
            
SAFE(write_string(md->reasonf));
        } else {
            
SAFE(write_string(md->reasonf));
            
SAFE(write_buffer(md->whof));
        }
        
SAFE(write_int32(md->timef));
        
SAFE(write_int32(md->expiresf));
    }
    
SAFE(write_int32(LOCAL_VERSION_50f));
    for (
md table->first(); mdmd table->next()) {
        
SAFE(write_time(md->timef));
        
SAFE(write_time(md->expiresf));
        
SAFE(write_time(md->lastusedf));
    }
    
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"dbnamestrerror(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_tableDBTable *nickgroup_table,
                               
dbFILE *fint32 ver)
{
    
NickInfo *ni;
    
NickGroupInfo *ngi;
    
int16 tmp16;
    
int32 t---2;
    
int i;
    
char passbuf[PASSMAX];
    
char *url, *email;

    
ni nick_table->newrec();
    
SAFE(read_buffer(ni->nickf));
    
module_log_debug(2"loading nick %s"ni->nick);
    
SAFE(read_buffer(passbuff));
    
SAFE(read_string(&urlf));
    
SAFE(read_string(&emailf));
    
SAFE(read_string(&ni->last_usermaskf));
    if (!
ni->last_usermask)
        
ni->last_usermask sstrdup("@");
    
SAFE(read_string(&ni->last_realnamef));
    if (!
ni->last_realname)
        
ni->last_realname sstrdup("");
    
SAFE(read_string(&ni->last_quitf));
    
SAFE(read_int32(&t---2f));
    
ni->time_registered t---2;
    
SAFE(read_int32(&t---2f));
    
ni->last_seen t---2;
    
SAFE(read_int16(&ni->statusf));
    
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_realmaskf));
    
SAFE(read_int16(&tmp16f));  /* linkcount */
    
if (ni->last_realmask) {
        
SAFE(read_int16(&tmp16f));  /* 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.passwordpassbufPASSMAX);
        
ngi->url url;
        
ngi->email email;
        
SAFE(read_int32(&ngi->flagsf));
        if (
ngi->flags NF_KILL_IMMED)
            
ngi->flags |= NF_KILL_QUICK;
        
ngi->flags |= NF_NOGROUP;
        if (
ver >= 9) {
            
void *tmpptr;
            
SAFE(read_ptr(&tmpptrf));
            if (
tmpptr)
                
ngi->flags |= NF_SUSPENDED;
            else
                
ngi->flags &= ~NF_SUSPENDED;
        } else if (
ver == && (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_whof));
            
SAFE(read_string(&ngi->suspend_reasonf));
            
SAFE(read_int32(&t---2f));
            
ngi->suspend_time t---2;
            
SAFE(read_int32(&t---2f));
            
ngi->suspend_expires t---2;
        }
        
SAFE(read_int16(&ngi->access_countf));
        if (
ngi->access_count) {
            
char **access;
            
access smalloc(sizeof(char *) * ngi->access_count);
            
ngi->access access;
            
ARRAY_FOREACH (ingi->access)
                
SAFE(read_string(&ngi->access[i], f));
        }
        
SAFE(read_int16(&ngi->memos.memos_countf));
        
SAFE(read_int16(&ngi->memos.memomaxf));
        
/*
         * 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 (ingi->memos.memos) {
                
SAFE(read_uint32(&ngi->memos.memos[i].numberf));
                
SAFE(read_int16(&ngi->memos.memos[i].flagsf));
                
SAFE(read_int32(&t---2f));
                
ngi->memos.memos[i].time t---2;
                if (
ngi->memos.memos[i].flags MF_UNREAD)
                    
ngi->memos.memos[i].firstread 0;
                else
                    
ngi->memos.memos[i].firstread t---2;
                
SAFE(read_buffer(ngi->memos.memos[i].senderf));
                
ngi->memos.memos[i].channel NULL;
                
SAFE(read_string(&ngi->memos.memos[i].textf));
            }
        }
        
/* Channel counts are recalculated by open_channel_db() */
        
SAFE(read_int16(&tmp16f));  /* 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) << | ((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(&tmp16f));  /* channelmax */
        
ngi->channelmax CHANMAX_DEFAULT;
        
SAFE(read_int16(&ngi->languagef));
        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_tableDBTable *nickgroup_table,
                             
dbFILE *fint32 ver)
{
    
char *nick;
    
NickInfo *ni NULL;
    
NickInfo dummy_ni;  /* for nonexistent nicks */

    
SAFE(read_string(&nickf));
    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(ni0sizeof(*ni));
    }
    
free(nick);
    
nick NULL;
    
free(ni->last_realmask);  /* copied from last_usermask */
    
SAFE(read_string(&ni->last_realmaskf));
    if (
ver >= 19)
        
SAFE(read_uint32(&ni->id_stampf));
    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 *tabledbFILE *fint32 ver)
{
    
uint32 group;
    
NickGroupInfo *ngi NULL;
    
NickGroupInfo dummy_ngi;  /* for nonexistent nick groups */
    
int i;

    
SAFE(read_uint32(&groupf));
    
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(ngi0sizeof(*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(ngi0sizeof(*ngi));
    }
    
SAFE(read_int32(&ngi->flagsf));
    
SAFE(read_int32(&ngi->authcodef));
    
SAFE(read_time(&ngi->authsetf));
    if (
ver >= 24) {
        
SAFE(read_int16(&ngi->authreasonf));
    } else {
        switch ((
ngi->authcode 0x300) >> 8) {
            case 
ngi->authreason NICKAUTH_REGISTER;  break;
            case 
ngi->authreason NICKAUTH_SET_EMAIL; break;
            case 
ngi->authreason NICKAUTH_SETAUTH;   break;
            default: 
ngi->authreason 0;                  break;
        }
    }
    
SAFE(read_int16(&ngi->channelmaxf));
    if (
ver >= 18) {
        
SAFE(read_int16(&ngi->ajoin_countf));
        if (
ngi->ajoin_count) {
            
ngi->ajoin smalloc(sizeof(char *) * ngi->ajoin_count);
            
ARRAY_FOREACH (ingi->ajoin)
                
SAFE(read_string(&ngi->ajoin[i], f));
        }
    }
    
SAFE(read_int16(&ngi->memos.memomaxf));
    if (
ver >= 17) {
        
SAFE(read_int16(&ngi->ignore_countf));
        if (
ngi->ignore_count) {
            
ngi->ignore smalloc(sizeof(char *) * ngi->ignore_count);
            
ARRAY_FOREACH (ingi->ignore)
                
SAFE(read_string(&ngi->ignore[i], f));
        }
    }
    
SAFE(read_int16(&ngi->languagef));
    if (!
have_language(ngi->language))
        
ngi->language LANG_DEFAULT;
    if (
ver >= 15)
        
SAFE(read_int16(&ngi->timezonef));
    
SAFE(read_string(&ngi->infof));
    if (
ver >= 13)
        
SAFE(read_int16(&ngi->os_privf));
    if (
ngi == &dummy_ngi) {
        
ARRAY_FOREACH (ingi->ajoin)
            
free(ngi->ajoin[i]);
        
free(ngi->ajoin);
        
ARRAY_FOREACH (ingi->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 *tabledbFILE *fint32 ver)
{
    
uint16 tmp16;
    
uint32 group;
    
NickGroupInfo *ngi NULL;
    
NickGroupInfo dummy_ngi;  /* for nonexistent nick groups */
    
int i;

    
SAFE(read_uint32(&groupf));
    
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(ngi0sizeof(*ngi));
        
init_password(&ngi->pass);
    }
    
SAFE(read_string(&ngi->last_emailf));
    
SAFE(read_uint16(&tmp16f));
    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_counttmp16);
    }
    for (
0tmp16i++) {
        
time_t t;
        
char *s;
        
SAFE(read_time(&tf));
        
SAFE(read_string(&sf));
        if (
ngi != &dummy_ngi && 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.cipherf));
    if (
ngi == &dummy_ngi) {
        
ARRAY_FOREACH (ingi->ajoin)
            
free(ngi->ajoin[i]);
        
free(ngi->ajoin);
        
ARRAY_FOREACH (ingi->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(); ngingi 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_tableDBTable *nickgroup_table)
{
    
dbFILE *f;
    
int32 ver;
    
int ic;
    
NickInfo *ni;
    
NickGroupInfo *ngi;
    
int failed 0need_memomax_check 1;

    
/* Open database. */
    
if (!(my_open_db_r(NickDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

    
/* Load original data. */
    
for (0256 && !failedi++) {
        while ((
getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in nick.db");
                
failed 1;
            }
            
ni load_one_nick(nick_tablenickgroup_tablefver);
            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(); ngingi nickgroup_table->next()) {
        if (
ngi->flags NF_NOGROUP) {
#define NEWNICKGROUP_TRIES 1000
            
int tries;
            for (
tries 0tries NEWNICKGROUP_TRIEStries++) {
                
uint32 id rand() + rand();
                if (
id == || 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 (ingi->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(); nini nick_table->next()) {
        if (
ni->last_realmask) {
            
char *ni->last_realmask;
            
ni->last_realmask = (char *)get_nickinfo(s);
            
free(s);
        }
    }
    for (
ni nick_table->first(); nini 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->nickgroupni->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(); nini 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(&verf) == 0) {
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION_50) {
            
module_log("Invalid extension data version in nick.db");
            
failed 1;
        } else {
            while (!
failed && (getc_db(f)) != 0) {
                if (
!= 1) {
                    
module_log("Invalid format in nick.db extension data");
                    
failed 1;
                } else if (!
load_one_nick_ext(nick_tablenickgroup_table,
                                              
fver)) {
                    
failed 1;
                }
            }
            while (!
failed && (getc_db(f)) != 0) {
                if (
!= 1) {
                    
module_log("Invalid format in nick.db extension data");
                    
failed 1;
                } else if (!
load_one_nickgroup_ext(nickgroup_tablefver)) {
                    
failed 1;
                }
            }
        }
        
need_memomax_check 0;
    }
    if (
read_int32(&verf) == 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 && (getc_db(f)) != 0) {
                if (
!= 1) {
                    
module_log("Invalid format in nick.db extension (5.1)"
                               " data"
);
                    
failed 1;
                } else if (!
load_one_nickgroup_ext51(nickgroup_tablefver)){
                    
failed 1;
                }
            }
        }
    }

    if (!
failed && ver 13) {
        
/* Need to restore Services admin/oper privs from oper.db lists */
        
NickGroupInfo *ngi;
        
ARRAY_FOREACH (iservices_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 (iservices_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_tableDBTable *nickgroup_table)
{
    
dbFILE *f;
    
int i;
    
NickInfo *ni;
    
NickGroupInfo *ngi;
    static 
NickGroupInfo forbidden_ngi;  /* dummy for forbidden nicks */
    
static time_t lastwarn 0;

    if (!(
open_db(NickDBName"w"11)))
        return 
0;
    for (
ni nick_table->first(); nini nick_table->next()) {
        if (
ni->nickgroup)
            
ngi get_nickgroupinfo(ni->nickgroup);
        else
            
ngi NULL;
        
SAFE(write_int8(1f));
        
SAFE(write_buffer(ni->nickf));
        if (
ngi) {
            
SAFE(write_buffer(ngi->pass.passwordf));
            
SAFE(write_string(ngi->urlf));
            
SAFE(write_string(ngi->emailf));
        } 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->nickstrlen(ni->nick), &dummypass);
            }
            
SAFE(write_buffer(dummypass.passwordf));
            
clear_password(&dummypass);
            
SAFE(write_string(NULLf));
            
SAFE(write_string(NULLf));
        }
        
SAFE(write_string(ni->last_usermaskf));
        
SAFE(write_string(ni->last_realnamef));
        
SAFE(write_string(ni->last_quitf));
        
SAFE(write_int32(ni->time_registeredf));
        
SAFE(write_int32(ni->last_seenf));
        
SAFE(write_int16(ni->statusf));
        if (
ngi && irc_stricmp(ni->nickngi_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(0f));
            
SAFE(write_int16(0f));
        } else {
            
int32 t---2;
            
/* Main nick in the group, or forbidden; save as a root nick */
            
SAFE(write_string(NULLf));
            
SAFE(write_int16(0f));
            
/* 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 */
            
t---ngi->flags 0x80000000 | (ngi->id 0xFFFF0000)>>1;
            if (
t---NF_KILL_IMMED)
                
t---&= ~NF_KILL_QUICK;
            
SAFE(write_int32(t---2f));
            
SAFE(write_ptr((ngi->flags NF_SUSPENDED) ? (void *)NULLf));
            if (
ngi->flags NF_SUSPENDED) {
                
SAFE(write_buffer(ngi->suspend_whof));
                
SAFE(write_string(ngi->suspend_reasonf));
                
SAFE(write_int32(ngi->suspend_timef));
                
SAFE(write_int32(ngi->suspend_expiresf));
            }
            
SAFE(write_int16(ngi->access_countf));
            
ARRAY_FOREACH (ingi->access)
                
SAFE(write_string(ngi->access[i], f));
            
SAFE(write_int16(ngi->memos.memos_countf));
            
/* 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(MSMaxMemosf));
            else
                
SAFE(write_int16(ngi->memos.memomaxf));
            
ARRAY_FOREACH (ingi->memos.memos) {
                
SAFE(write_int32(ngi->memos.memos[i].numberf));
                
SAFE(write_int16(ngi->memos.memos[i].flagsf));
                
SAFE(write_int32(ngi->memos.memos[i].timef));
                
SAFE(write_buffer(ngi->memos.memos[i].senderf));
                
SAFE(write_string(ngi->memos.memos[i].textf));
            }
            
/* Store bottom 16 bits of group ID in channelcount */
            
SAFE(write_int16(ngi->id 0xFFFFf));
            if (
ngi->channelmax == CHANMAX_DEFAULT)
                
SAFE(write_int16(CSMaxRegf));
            else
                
SAFE(write_int16(ngi->channelmaxf));
            if (
ngi->language == LANG_DEFAULT)
                
SAFE(write_int16(DEF_LANGUAGEf));
            else
                
SAFE(write_int16(ngi->languagef));
        }
        
put_nickgroupinfo(ngi);
    } 
/* for (ni) */
    
{
        
/* This is an UGLY HACK but it simplifies loading. */
        
static char buf[256];  /* initialized to zero */
        
SAFE(write_buffer(buff));
    }

    
services_admins_count services_opers_count 0;
    
SAFE(write_int32(LOCAL_VERSION_50f));
    for (
ni nick_table->first(); nini nick_table->next()) {
        
SAFE(write_int8(1f));
        
SAFE(write_string(ni->nickf));
        
SAFE(write_string(ni->last_realmaskf));
        
SAFE(write_int32(ni->id_stampf));
    }
    
SAFE(write_int8(0f));
    for (
ngi nickgroup_table->first(); ngingi nickgroup_table->next()) {
        if (
ngi->id == 0) {
            
module_log("BUG: nickgroup with ID 0 found during write"
                       " (skipping)"
);
            continue;
        }
        
SAFE(write_int8(1f));
        
SAFE(write_int32(ngi->idf));
        
SAFE(write_int32(ngi->flagsf));
        
SAFE(write_int32(ngi->authcodef));
        
SAFE(write_time(ngi->authsetf));
        
SAFE(write_int16(ngi->authreasonf));
        
SAFE(write_int16(ngi->channelmaxf));
        
SAFE(write_int16(ngi->ajoin_countf));
        
ARRAY_FOREACH (ingi->ajoin)
            
SAFE(write_string(ngi->ajoin[i], f));
        
SAFE(write_int16(ngi->memos.memomaxf));
        
SAFE(write_int16(ngi->ignore_countf));
        
ARRAY_FOREACH (ingi->ignore)
            
SAFE(write_string(ngi->ignore[i], f));
        
SAFE(write_int16(ngi->languagef));
        
SAFE(write_int16(ngi->timezonef));
        
SAFE(write_string(ngi->infof));
        
SAFE(write_string(ngi->yasf));
        
SAFE(write_string(ngi->burcf));
        
SAFE(write_string(ngi->sehirf));
        
SAFE(write_string(ngi->takimf));
        
SAFE(write_int16(ngi->os_privf));
        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(0f));

    
SAFE(write_int32(LOCAL_VERSIONf));
    for (
ngi nickgroup_table->first(); ngingi nickgroup_table->next()) {
        if (
ngi->id == 0) {
            
module_log("BUG: nickgroup with ID 0 found during write"
                       " (skipping)"
);
            continue;
        }
        
SAFE(write_int8(1f));
        
SAFE(write_int32(ngi->idf));
        
SAFE(write_string(ngi->last_emailf));
        
SAFE(write_int16(ngi->memos.memos_countf));
        
ARRAY_FOREACH (ingi->memos.memos) {
            
SAFE(write_time(ngi->memos.memos[i].firstreadf));
            
SAFE(write_string(ngi->memos.memos[i].channelf));
        }
        
SAFE(write_string(ngi->pass.cipherf));
    }
    
SAFE(write_int8(0f));

    
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"NickDBNamestrerror(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/
100;             /* 250..300 ->   25..  50 */
    
else if (new <= 320)
        return new*
5/700;           /* 300..320 ->   50.. 100 */
    
else if (new <= 500)
        return new*
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 *tabledbFILE *fint32 ver)
{
    
ChannelInfo *ci;
    
NickInfo *ni;
    
MemoInfo tmpmi;
    
int16 tmp16lev;
    
int32 t---2;
    
int n_levels;
    
char *s;
    
int i;

    
ci table->newrec();
    
SAFE(read_buffer(ci->namef));
    
module_log_debug(2"loading channel %s"ci->name);
    
SAFE(read_string(&sf));
    if (
s) {
        
ni get_nickinfo(s);
        if (
ni) {
            
ci->founder ni->nickgroup;
            
put_nickinfo(ni);
        }
        
free(s);
    }
    if (
ver >= 7) {
        
SAFE(read_string(&sf));
        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.passwordf));
    
SAFE(read_string(&ci->descf));
    if (!
ci->desc)
        
ci->desc sstrdup("");
    
SAFE(read_string(&ci->urlf));
    
SAFE(read_string(&ci->emailf));
    
SAFE(read_int32(&t---2f));
    
ci->time_registered t---2;
    
SAFE(read_int32(&t---2f));
    
ci->last_used t---2;
    
SAFE(read_string(&ci->last_topicf));
    
SAFE(read_buffer(ci->last_topic_setterf));
    
SAFE(read_int32(&t---2f));
    
ci->last_topic_time t---2;
    
SAFE(read_int32(&ci->flagsf));
    
ci->flags &= CF_ALLFLAGS;  /* clear any invalid flags */
    
if (ver >= 9) {
        
void *tmpptr;
        
SAFE(read_ptr(&tmpptrf));
        if (
tmpptr) {
            
SAFE(read_buffer(ci->suspend_whof));
            
SAFE(read_string(&ci->suspend_reasonf));
            
SAFE(read_int32(&t---2f));
            
ci->suspend_time t---2;
            
SAFE(read_int32(&t---2f));
            
ci->suspend_expires t---2;
            
ci->flags |= CF_SUSPENDED;
        }
    }
    
SAFE(read_int16(&tmp16f));
    
n_levels tmp16;
    
reset_levels(ci);
    for (
0n_levelsi++) {
        
SAFE(read_int16(&levf));
        if (
CA_SIZE)
            
ci->levels[i] = convert_old_level(lev);
    }

    
SAFE(read_int16(&ci->access_countf));
    if (
ci->access_count) {
        
ci->access scalloc(ci->access_countsizeof(ChanAccess));
        
ARRAY_FOREACH (ici->access) {
            
ci->access[i].channel ci;
            
SAFE(read_int16(&tmp16f));  /* in_use */
            
if (tmp16) {
                
SAFE(read_int16(&levf));
                
ci->access[i].level convert_old_level(lev);
                
SAFE(read_string(&sf));
                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_countf));
    if (
ci->akick_count) {
        
ci->akick scalloc(ci->akick_countsizeof(AutoKick));
        
ARRAY_FOREACH (ici->akick) {
            
ci->akick[i].channel ci;
            
SAFE(read_int16(&tmp16f));  /* in_use */
            
if (tmp16) {
                
SAFE(read_int16(&tmp16f));  /* is_nick */
                
SAFE(read_string(&sf));
                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].reasonf));
                if (
ver >= 8)
                    
SAFE(read_buffer(ci->akick[i].whof));
                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(&tmp16f));
        
ci->mlock.on tmp16;
        
SAFE(read_int16(&tmp16f));
        
ci->mlock.off tmp16;
    } else {
        
SAFE(read_int32(&ci->mlock.onf));
        
SAFE(read_int32(&ci->mlock.offf));
    }
    
SAFE(read_int32(&ci->mlock.limitf));
    
SAFE(read_string(&ci->mlock.keyf));
    
ci->mlock.on &= ~chanmode_reg;  /* check_modes() takes care of this */

    
SAFE(read_int16(&tmpmi.memos_countf));
    
SAFE(read_int16(&tmpmi.memomaxf));
    if (
tmpmi.memos_count) {
        for (
0tmpmi.memos_counti++) {
            
Memo tmpmemo;
            
SAFE(read_uint32(&tmpmemo.numberf));
            
SAFE(read_int16(&tmpmemo.flagsf));
            
SAFE(read_int32(&t---2f));
            
tmpmemo.time t---2;
            
SAFE(read_buffer(tmpmemo.senderf));
            
SAFE(read_string(&tmpmemo.textf));
            
free(tmpmemo.text);
        }
    }

    
SAFE(read_string(&ci->entry_messagef));

    
ci->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 *tabledbFILE *fint32 ver)
{
    
char *name;
    
ChannelInfo *ci NULL;
    
ChannelInfo dummy_ci;  /* for nonexistent channels */
    
int i;
    
int16 counttmp16;

    
SAFE(read_string(&namef));
    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(ci0sizeof(*ci));
    }
    
free(name);
    
name NULL;
    
SAFE(read_int16(&tmp16f));  /* was memomax */
    
if (ver >= 14) {
        if (
ver >= 23) {
            
SAFE(read_int16(&countf));
            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->nameci->akick_countcount);
            }
        } else {
            
count ci->akick_count;
        }
        for (
0counti++) {
            if (
ci->akick_count) {
                
SAFE(read_time(&ci->akick[i].setf));
                
SAFE(read_time(&ci->akick[i].lastusedf));
            } else {
                
time_t t;
                
SAFE(read_time(&tf));
                
SAFE(read_time(&tf));
            }
        }
    }
    if (
ver >= 16) {
        
SAFE(read_string(&ci->mlock.linkf));
        
SAFE(read_string(&ci->mlock.floodf));
    }
    if (
ver >= 25)
        
SAFE(read_int32(&ci->mlock.joindelayf));
    if (
ver >= 27) {
        
SAFE(read_int32(&ci->mlock.joinrate1f));
        
SAFE(read_int32(&ci->mlock.joinrate2f));
    }
    if (
ver >= 20) {
        
int16 lev;
        
SAFE(read_int16(&countf));
        if (
count) {
            
reset_levels(ci);
            for (
0counti++) {
                
SAFE(read_int16(&levf));
                if (
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(&countf));
        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->nameci->access_countcount);
        }
        for (
0counti++) {
            
SAFE(read_int16(&levf));
            if (
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 *tabledbFILE *fint32 ver)
{
    
char *name;
    
ChannelInfo *ci NULL;
    
ChannelInfo dummy_ci;  /* for nonexistent channels */
    
char *s;

    
SAFE(read_string(&namef));
    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(ci0sizeof(*ci));
        
init_password(&ci->founderpass);
    }
    
free(name);
    
name NULL;
    
SAFE(read_string(&sf));
    if (
s)
        
ci->mlock.on mode_string_to_flags(sMODE_CHANNEL|MODE_NOERROR);
    
free(s);
    
SAFE(read_string(&sf));
    if (
s)
        
ci->mlock.off mode_string_to_flags(sMODE_CHANNEL|MODE_NOERROR);
    
free(s);
    
free((char *)ci->founderpass.cipher);
    
SAFE(read_string((char **)&ci->founderpass.cipherf));
    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 ic;
    
ChannelInfo *ci;
    
int failed 0;

    
/* Open database. */
    
if (!(my_open_db_r(ChanDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

    
/* Load original data. */
    
for (0256 && !failedi++) {
        while ((
getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in %s"ChanDBName);
                
failed 1;
                break;
            }
            
ci load_one_channel(tablefver);
            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(&verf) == 0) {
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION_50) {
            
module_log("Invalid extension data version in %s"ChanDBName);
            
failed 1;
        }
        while (!
failed && (getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in %s extension data"ChanDBName);
                
failed 1;
            } else {
                
failed = !load_one_channel_ext(tablefver);
            }
        }
    }
    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(); cici 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(); cici table->next()) {
        
int i;
        
ARRAY_FOREACH (ici->akick) {
            if (!
ci->akick[i].mask) {
                
ARRAY_REMOVE(ci->akicki);
                
i--;
            }
        }
    }

    if (!
failed && read_int32(&verf) == 0) {
        if (
ver FIRST_VERSION_51 || ver LOCAL_VERSION) {
            
module_log("Invalid 5.1 extension data version in %s"ChanDBName);
            
failed 1;
        }
        while (!
failed && (getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in %s 5.1 extension data",
                           
ChanDBName);
                
failed 1;
            } else {
                
failed = !load_one_channel_ext51(tablefver);
            }
        }
    }

    
/* 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 (!(
open_db(ChanDBName"w"11)))
        return 
0;

    for (
ci table->first(); cici table->next()) {
        
SAFE(write_int8(1f));
        
SAFE(write_buffer(ci->namef));
        if (
ci->founder && (ngi get_ngi_id(ci->founder))) {
            
SAFE(write_string(ngi_mainnick(ngi), f));
            
put_nickgroupinfo(ngi);
        } else {
            
SAFE(write_string(NULLf));
        }
        if (
ci->successor && (ngi get_ngi_id(ci->successor))) {
            
SAFE(write_string(ngi_mainnick(ngi), f));
            
put_nickgroupinfo(ngi);
        } else {
            
SAFE(write_string(NULLf));
        }
        
SAFE(write_buffer(ci->founderpass.passwordf));
        
SAFE(write_string(ci->descf));
        
SAFE(write_string(ci->urlf));
        
SAFE(write_string(ci->emailf));
        
SAFE(write_int32(ci->time_registeredf));
        
SAFE(write_int32(ci->last_usedf));
        
SAFE(write_string(ci->last_topicf));
        
SAFE(write_buffer(ci->last_topic_setterf));
        
SAFE(write_int32(ci->last_topic_timef));
        
SAFE(write_int32(ci->flagsf));
        
SAFE(write_ptr(ci->flags CF_SUSPENDED ? (void *)NULLf));
        if (
ci->flags CF_SUSPENDED) {
            
SAFE(write_buffer(ci->suspend_whof));
            
SAFE(write_string(ci->suspend_reasonf));
            
SAFE(write_int32(ci->suspend_timef));
            
SAFE(write_int32(ci->suspend_expiresf));
        }

        if (
ci->levels) {
            
SAFE(write_int16(CA_SIZEf));
            for (
0CA_SIZEi++)
                
SAFE(write_int16(convert_new_level(ci->levels[i]), f));
        } else {
            
SAFE(write_int16(CA_SIZE_4_5f));
            for (
0CA_SIZE_4_5i++) {
                if (
== CA_NOJOIN && (ci->flags CF_RESTRICTED))
                    
SAFE(write_int16(0f));
                else
                    
SAFE(write_int16(def_levels_4_5[i], f));
            }
        }

        
SAFE(write_int16(ci->access_countf));
        
ARRAY_FOREACH (ici->access) {
            if (
ci->access[i].nickgroup)
                
ngi get_ngi_id(ci->access[i].nickgroup);
            else
                
ngi NULL;
            
SAFE(write_int16(ngi != NULLf));
            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_countf));
        
ARRAY_FOREACH (ici->akick) {
            
SAFE(write_int16((ci->akick[i].mask != NULL), f));  /* in_use */
            
if (ci->akick[i].mask) {
                
SAFE(write_int16(0f));  /* is_nick */
                
SAFE(write_string(ci->akick[i].maskf));
                
SAFE(write_string(ci->akick[i].reasonf));
                
SAFE(write_buffer(ci->akick[i].whof));
            }
        }

        
SAFE(write_int32(ci->mlock.onf));
        
SAFE(write_int32(ci->mlock.offf));
        
SAFE(write_int32(ci->mlock.limitf));
        
SAFE(write_string(ci->mlock.keyf));

        
SAFE(write_int16(0f));  /* memos_count */
        
SAFE(write_int16(MSMaxMemosf));  /* memomax */

        
SAFE(write_string(ci->entry_messagef));

    } 
/* for (ci) */

    
{
        
/* This is an UGLY HACK but it simplifies loading. */
        
static char buf[256];  /* initialized to zero */
        
SAFE(write_buffer(buff));
    }

    
SAFE(write_int32(LOCAL_VERSION_50f));
    for (
ci table->first(); cici table->next()) {
        
SAFE(write_int8(1f));
        
SAFE(write_string(ci->namef));
        
SAFE(write_int16(MEMOMAX_DEFAULTf));  /* for 5.0's sake */
        
SAFE(write_int16(ci->akick_countf));
        
ARRAY_FOREACH (ici->akick) {
            
SAFE(write_time(ci->akick[i].setf));
            
SAFE(write_time(ci->akick[i].lastusedf));
        }
        
SAFE(write_string(ci->mlock.linkf));
        
SAFE(write_string(ci->mlock.floodf));
        
SAFE(write_int32(ci->mlock.joindelayf));
        
SAFE(write_int32(ci->mlock.joinrate1f));
        
SAFE(write_int32(ci->mlock.joinrate2f));
        if (
ci->levels) {
            
SAFE(write_int16(CA_SIZEf));
            for (
0CA_SIZEi++)
                
SAFE(write_int16(ci->levels[i], f));
        } else {
            
SAFE(write_int16(0f));
        }
        
SAFE(write_int16(ci->access_countf));
        
ARRAY_FOREACH (ici->access)
            
SAFE(write_int16(ci->access[i].levelf));
    }
    
SAFE(write_int8(0f));

    
SAFE(write_int32(LOCAL_VERSIONf));
    for (
ci table->first(); cici 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.cipherf));
    }
    
SAFE(write_int8(0f));

    
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"ChanDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/********************** OperServ database handling ***********************/
/*************************************************************************/

static int load_oper_table(DBTable *table)
{
    
dbFILE *f;
    
int32 ver;
    
int16 in;
    
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 (!(
my_open_db_r(OperDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

    
services_admins_count services_opers_count 0;
    
SAFE(read_int16(&nf));
    for (
0ni++) {
        
char *s;
        
SAFE(read_string(&sf));
        if (
&& MAX_SERVADMINS)
            
strbcpy(services_admins[services_admins_count++], s);
        
free(s);
    }
    
SAFE(read_int16(&nf));
    for (
0ni++) {
        
char *s;
        
SAFE(read_string(&sf));
        if (
&& MAX_SERVOPERS)
            
strbcpy(services_opers[services_opers_count++], s);
        
free(s);
    }
    if (
ver >= 7) {
        
int32 t---2;
        
SAFE(read_int32(&t---2f));
        for (
field table->fieldsfield->namefield++) {
            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)) = t---2;
                break;
            }
        }
        
SAFE(read_int32(&t---2f));
        for (
field table->fieldsfield->namefield++) {
            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)) = t---2;
                break;
            }
        }
    }
    if (
ver >= 9) {
        
SAFE(read_int8(&no_supassf));
        for (
field table->fieldsfield->namefield++) {
            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.passwordf));
            for (
field table->fieldsfield->namefield++) {
                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(&verf) == 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->cipherf));
    }

    
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 (!(
open_db(OperDBName"w"11)))
        return 
0;

    
SAFE(write_int16(services_admins_countf));
    
ARRAY_FOREACH (iservices_admins)
        
SAFE(write_string(services_admins[i], f));

    
SAFE(write_int16(services_opers_countf));
    
ARRAY_FOREACH (iservices_opers)
        
SAFE(write_string(services_opers[i], f));

    for (
field table->fieldsfield->namefield++) {
        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->fieldsfield->namefield++) {
        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->fieldsfield->namefield++) {
        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_supassf));
            break;
        }
    }
    if (!
no_supass) {
        for (
field table->fieldsfield->namefield++) {
            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->passwordf));
                break;
            }
        }
    }

    
SAFE(write_int32(LOCAL_VERSIONf));
    if (!
no_supass)
        
SAFE(write_string(supass->cipherf));

    
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"OperDBNamestrerror(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 (!(
my_open_db_r(NewsDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

#if CLEAN_COMPILE
    
count 0;
#endif
    
SAFE(read_int16(&countf));
    for (
0counti++) {
        
int32 t---2;
        
NewsItem *news table->newrec();
        
SAFE(read_int16(&news->typef));
        
SAFE(read_int32(&news->numf));
        
SAFE(read_string(&news->textf));
        
SAFE(read_buffer(news->whof));
        
SAFE(read_int32(&t---2f));
        
news->time t---2;
        
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 counti;
    
NewsItem *news;
    static 
time_t lastwarn 0;

    if (!(
open_db(NewsDBName"w"11)))
        return 
0;

    
count 0;
    for (
news table->first(); newsnews table->next())
        
count++;
    if (
count 32767)
        
count 32767;  // avoid overflow
    
write_int16((int16)countf);
    
0;
    for (
news table->first(), 0countnews 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->typef));
        
SAFE(write_int32(news->numf));
        
SAFE(write_string(news->textf));
        
SAFE(write_buffer(news->whof));
        
SAFE(write_int32(news->timef));
    }

    
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"NewsDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/********************** Autokill database handling ***********************/
/*************************************************************************/

static int load_akill_table(DBTable *akill_tableDBTable *exclude_table)
{
    
dbFILE *f;
    
int32 ver;

    if (!(
my_open_db_r(AutokillDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;
    if (!
read_maskdata(akill_tableMD_AKILLAutokillDBNamef))
        return 
0;
    if (
getc_db(f) == 1) {
        if (!
read_maskdata(exclude_tableMD_EXCLUDEAutokillDBNamef))
            return 
0;
    }
    
close_db(f);
    return 
1;
}

/*************************************************************************/

static int save_akill_table(DBTable *akill_tableDBTable *exclude_table)
{
    
dbFILE *f;
    static 
time_t lastwarn 0;

    if (!(
open_db(AutokillDBName"w"11)))
        return 
0;
    if (!
write_maskdata(akill_tableMD_AKILLAutokillDBNamef))
        return 
0;
    
SAFE(write_int8(1f));
    if (!
write_maskdata(exclude_tableMD_EXCLUDEAutokillDBNamef))
        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 (!(
my_open_db_r(ExceptionDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;
    if (!
read_maskdata(tableMD_EXCEPTIONExceptionDBNamef))
        return 
0;
    
close_db(f);
    return 
1;
}

/*************************************************************************/

static int save_exception_table(DBTable *table)
{
    
dbFILE *f;
    static 
time_t lastwarn 0;

    if (!(
open_db(ExceptionDBName"w"11)))
        return 
0;
    if (!
write_maskdata(tableMD_EXCEPTIONExceptionDBNamef))
        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_tableDBTable *sqline_table,
                            
DBTable *szline_table)
{
    
dbFILE *f;
    
int32 ver;

    if (!(
my_open_db_r(SlineDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;
    if (!
read_maskdata(sgline_tableMD_SGLINESlineDBNamef))
        return 
0;
    if (!
read_maskdata(sqline_tableMD_SQLINESlineDBNamef))
        return 
0;
    if (!
read_maskdata(szline_tableMD_SZLINESlineDBNamef))
        return 
0;
    
close_db(f);
    return 
1;
}

/*************************************************************************/

static int save_sline_table(DBTable *sgline_tableDBTable *sqline_table,
                            
DBTable *szline_table)
{
    
dbFILE *f;
    static 
time_t lastwarn 0;

    if (!(
open_db(SlineDBName"w"11)))
        return 
0;
    if (!
write_maskdata(sgline_tableMD_SGLINESlineDBNamef))
        return 
0;
    if (!
write_maskdata(sqline_tableMD_SQLINESlineDBNamef))
        return 
0;
    if (!
write_maskdata(szline_tableMD_SZLINESlineDBNamef))
        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"SlineDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/********************** StatServ database handling ***********************/
/*************************************************************************/

static ServerStats *load_one_serverstats(DBTable *tabledbFILE *f)
{
    
ServerStats *ss;
    
int32 t---2;

    
ss table->newrec();
    
SAFE(read_string(&ss->namef));
    
SAFE(read_int32(&t---2f));
    
ss->t_join t---2;
    
SAFE(read_int32(&t---2f));  /* 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_messagef));
    return 
ss;

  
fail:
    
module_log("Read error on %s"f->filename);
    return 
NULL;
}

/*************************************************************************/

static int load_one_serverstats_ext(DBTable *tabledbFILE *fint32 ver)
{
    
ServerStats *ss NULL;
    
char *servername;

    
SAFE(read_string(&servernamef));
    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_joinf));
    
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 verinservers;
    
int16 tmp16;
    
int failed 0;
    
ServerStats *ss;

    
/* Open database. */
    
if (!(my_open_db_r(StatDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

    
/* Load original data. */
    
SAFE(read_int16(&tmp16f));
    
nservers tmp16;
    for (
0nservers && !failedi++) {
        
ss load_one_serverstats(tablef);
        if (
ss)
            
table->insert(ss);
        else
            
failed 1;
    }

    
/* Load extension data if present. */
    
if (!failed && read_int32(&verf) == 0) {
        
int32 moreservers;
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION_50) {
            
module_log("Invalid extension data version in %s"StatDBName);
        } else {
            
SAFE(read_int32(&moreserversf));
            for (
0moreservers && !failedi++) {
                
ss load_one_serverstats(tablef);
                if (
ss)
                    
table->insert(ss);
                else
                    
failed 1;
            }
            
nservers += moreservers;
            for (
0nservers && !failedi++)
                
failed = !load_one_serverstats_ext(tablefver);
        }
    }

    
/* 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 countrealcounti;
    
ServerStats *ss;
    static 
time_t lastwarn 0;

    if (!(
open_db(StatDBName"w"11)))
        return 
0;

    
realcount 0;
    for (
ss table->first(); ssss table->next())
        
realcount++;
    if (
realcount 32767)  /* Well, you never know... */
        
count 32767;
    else
        
count realcount;
    
SAFE(write_int16((int16)countf));

    for (
ss table->first(), 0countss 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->namef));
        
SAFE(write_int32(ss->t_joinf));
        
SAFE(write_int32(ss->t_quitf));
        
SAFE(write_string(ss->quit_messagef));
    }

    
SAFE(write_int32(LOCAL_VERSION_50f));
    if (
realcount count) {
        
SAFE(write_int32(realcount-countf));
        for (; 
realcountss 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->namef));
            
SAFE(write_int32(ss->t_joinf));
            
SAFE(write_int32(ss->t_quitf));
            
SAFE(write_string(ss->quit_messagef));
        }
    } else {
        
SAFE(write_int32(0f));
    }
    for (
ss table->first(); ssss table->next()) {
        
SAFE(write_string(ss->namef));
        
SAFE(write_time(ss->t_joinf));
    }

    
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"StatDBNamestrerror(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_STRINGCF_DIRREQ, &AutokillDBName } } },
    { 
"ChanServDB",       { { CD_STRINGCF_DIRREQ, &ChanDBName } } },
    { 
"ExceptionDB",      { { CD_STRINGCF_DIRREQ, &ExceptionDBName } } },
    { 
"NewsDB",           { { CD_STRINGCF_DIRREQ, &NewsDBName } } },
    { 
"NickServDB",       { { CD_STRINGCF_DIRREQ, &NickDBName } } },
    { 
"OperServDB",       { { CD_STRINGCF_DIRREQ, &OperDBName } } },
    { 
"SlineDB",          { { CD_STRINGCF_DIRREQ, &SlineDBName } } },
    { 
"StatServDB",       { { CD_STRINGCF_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

Alt 01 Şubat 2012, 23:37   #46
Çevrimdışı
Kullanıcıların profil bilgileri misafirlere kapatılmıştır.
IF Ticaret Sayısı: (0)
IF Ticaret Yüzdesi:(%)
Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)




Arabanın bozuk olduğunu değil neden bozuk olduğunu söylersen yardimci olurum. Neden bozuk olduğunu söylemek ise hata mesajini vermendir.

 
Alıntı ile Cevapla

Alt 02 Şubat 2012, 10:13   #47
Çevrimdışı
Kullanıcıların profil bilgileri misafirlere kapatılmıştır.
IF Ticaret Sayısı: (0)
IF Ticaret Yüzdesi:(%)
Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)




son aşamadaki version4.c yi eklemedim, servisleri başlattığım zaten şöyle bir hata veriyor;
PHP Kod:   Kodu kopyalamak için üzerine çift tıklayın!
[Feb 02 10:10:42 2012IRC Services 5.1.24 starting up
[Feb 02 10:10:42 2012String NICK_SET_YAS_CHANGED missing from default language 

dil dosyasında satır kaydırmış olabilirim diye iki kere kontrol ettim ve dosyaları -w işlevi ile açıyorum.

 
Alıntı ile Cevapla

Alt 02 Şubat 2012, 14:52   #48
Çevrimdışı
Kullanıcıların profil bilgileri misafirlere kapatılmıştır.
IF Ticaret Sayısı: (0)
IF Ticaret Yüzdesi:(%)
Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)




63 versiyonunu kullanmani öneririm.

set.c ve index ten

Alıntı:
notice_lang(s_NickServ, u, NICK_SET_YAS_CHANGED, nick, param);

kismini kaldir. Diğerleride ayni sorunu verirse ayni şekilde kaldir. zaten tr.l den veri gönderilmedi.

 
Alıntı ile Cevapla

Alt 27 Nisan 2012, 14:31   #49
Çevrimdışı
Kullanıcıların profil bilgileri misafirlere kapatılmıştır.
IF Ticaret Sayısı: (0)
IF Ticaret Yüzdesi:(%)
Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)




Bunu yaptim ama modulleri indiremiyorum yardımcı olur musunuz? burda bir bir denilen yaptim tek moduller yok

__________________
Türkiye’nin ilk Marka Tescilli “Aşk Hikayesi” Sohbet Sitesi
https://
Kullanıcı imzalarındaki bağlantı ve resimleri görebilmek için en az 20 mesaja sahip olmanız gerekir ya da üye girişi yapmanız gerekir.
google_ad_section_end -->
 
Alıntı ile Cevapla

Alt 27 Nisan 2012, 14:35   #50
Çevrimdışı
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.)




toXic Nickli Üyeden Alıntı
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Sanırım Kullandiğiniz versiyon ( hiç incelemedim ) o yapiyi kendiliğinden destekliyor o kodlari es geçebilirsiniz. O Kodlari eklemeden 1 den fazla üst üste /ns set burc Yengec komutunu kullaniniz. Eğer işlevini doğru şekilde yerine getiriyorsa bir sorun olmayacaktir.

Ayrica modulleri tek bir modul olarak buradan indirebilirsiniz.



bu txt i nereye atacagiz oldugu gibi

__________________
Türkiye’nin ilk Marka Tescilli “Aşk Hikayesi” Sohbet Sitesi
https://
Kullanıcı imzalarındaki bağlantı ve resimleri görebilmek için en az 20 mesaja sahip olmanız gerekir ya da üye girişi yapmanız gerekir.
google_ad_section_end -->
 
Alıntı ile Cevapla

Cevapla

Etiketler
profil, takim or yas or burc or sehir


Konuyu Toplam 1 Üye okuyor. (0 Kayıtlı üye ve 1 Misafir)
 

Yetkileriniz
Konu Acma Yetkiniz Yok
Cevap Yazma Yetkiniz Yok
Eklenti Yükleme Yetkiniz Yok
Mesajınızı Değiştirme Yetkiniz Yok

BB code is Açık
Smileler Açık
[IMG] Kodları Açık
HTML-Kodu Kapalı
Trackbacks are Kapalı
Pingbacks are Açık
Refbacks are Açık


Benzer Konular
Konu Konuyu Başlatan Forum Cevaplar Son Mesaj
Takim,Yaş,Burc TCL Olabilir mi ? No_FeaR Eggdrop, NeoStats, BNC 6 26 Kasım 2014 17:57
MSN YAS BURC SEHIR.. Vb. INFO DA GOZUKMUYOR SecurityMaster IRCServices 5 07 Temmuz 2011 15:53
IRCServices versionları için /NS SET MSN,YAS,BURC,SEHIR NeTDeLiSi Services Hazır Kodlar 15 26 Kasım 2010 19:57
ircservices MSN YAS BURC SEHIR tr.l Sorunu XXXL IRCServices 1 07 Eylül 2008 02:17