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

IRCForumları - IRC ve mIRC Kullanıcılarının Buluşma Noktası (https://www.ircforumlari.net/)
-   Services Hazır Kodlar (https://www.ircforumlari.net/services-hazir-kodlar/)
-   -   IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR) (https://www.ircforumlari.net/services-hazir-kodlar/340381-ircservices-profil-takim-yas-burc-sehir.html)

toXic 09 Eylül 2010 17:51

Cevap: IRCServices PROFIL (Geliştirildi.)
 
Kod:

    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.

PRaNGaLaR 09 Eylül 2010 18:59

Cevap: IRCServices PROFIL (Geliştirildi.)
 
Benim Nereye eklemem Gerekiyor

Kod:

/* 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:
*/


toXic 09 Eylül 2010 19:04

Cevap: IRCServices PROFIL (Geliştirildi.)
 
Toplam 1 Eklenti bulunuyor.
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.

SeKeRCi 09 Eylül 2010 20:18

Cevap: IRCServices PROFIL (Geliştirildi.)
 
Güzel paylaşım tebrikler

KasperSky 01 Şubat 2012 19:10

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- Kodu:

/* 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:
 */ 


toXic 01 Şubat 2012 23:37

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.

KasperSky 02 Şubat 2012 10:13

Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)
 
son aşamadaki version4.c yi eklemedim, servisleri başlattığım zaten şöyle bir hata veriyor;
PHP- Kodu:

[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.

toXic 02 Şubat 2012 14:52

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.

CroAtoN 27 Nisan 2012 14:31

Cevap: IRCServices PROFIL (TAKIM/YAS/BURC/SEHIR)
 
Bunu yaptim ama modulleri indiremiyorum yardımcı olur musunuz? burda bir bir denilen yaptim tek moduller yok

CroAtoN 27 Nisan 2012 14:35

Cevap: IRCServices PROFIL (Geliştirildi.)
 
Alıntı:

toXic Nickli Üyeden Alıntı (Mesaj 1040512685)
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üm Zamanlar GMT +3 Olarak Ayarlanmış. Şuanki Zaman: 21:51.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2025, vBulletin Solutions, Inc.
Search Engine Friendly URLs by vBSEO
Copyright ©2004 - 2025 IRCForumlari.Net Sparhawk