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




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

PHP Kod:   Kodu kopyalamak için üzerine çift tıklayın!
/* Routines to load/save Services databases in the obsolete format used
 * by version 4.x (and 5.0).
 *
 * IRC Services is copyright (c) 1996-2009 Andrew Church.
 *     E-mail: <achurch[MENTION=117372]ach[/MENTION]urch.org>
 * Parts written by Andrew Kempe and others.
 * This program is free but copyrighted software; see the file GPL.txt for
 * details.
 */

#include "services.h"
#include "modules.h"
#include "conffile.h"
#include "databases.h"
#include "hash.h"
#include "language.h"
#include "encrypt.h"

#include "modules/nickserv/nickserv.h"
#include "modules/chanserv/chanserv.h"
#include "modules/memoserv/memoserv.h"
#include "modules/operserv/operserv.h"
#include "modules/operserv/maskdata.h"
#include "modules/operserv/akill.h"
#include "modules/operserv/news.h"
#include "modules/operserv/sline.h"
#include "modules/statserv/statserv.h"

#include "extsyms.h"

/* Avoid symbol clashes with database/standard when using static modules */
#define check_file_version version4_check_file_version
#define get_file_version version4_get_file_version
#define write_file_version version4_write_file_version
#define open_db version4_open_db
#define restore_db version4_restore_db
#define close_db version4_close_db
#define read_int8 version4_read_int8
#define read_uint8 version4_read_uint8
#define write_int8 version4_write_int8
#define read_int16 version4_read_int16
#define read_uint16 version4_read_uint16
#define write_int16 version4_write_int16
#define read_int32 version4_read_int32
#define read_uint32 version4_read_uint32
#define write_int32 version4_write_int32
#define read_time version4_read_time
#define write_time version4_write_time
#define read_ptr version4_read_ptr
#define write_ptr version4_write_ptr
#define read_string version4_read_string
#define write_string version4_write_string
#include "fileutil.c"

#define SAFE(x) do { if ((x) < 0) goto fail; } while (0)

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

#define FILE_VERSION      11    /* Must remain constant */
#define LOCAL_VERSION    100    /* For extensions to database files */
#define FIRST_VERSION_51 100    /* First extension version in 5.1 */
#define LOCAL_VERSION_50  27    /* Version we show to 5.0 */

/* LOCAL_VERSION change history:
 * [5.1]
 *   100: First version
 * [5.0]
 *    27: Added Bahamut +j handling (ci->mlock.joinrate{1,2} fields)
 *    26: Forced AUTODEOP and NOJOIN to default values
 *    25: Added trircd +J handling (ci->mlock.joindelay field)
 *    24: Moved nickname authentication reason into its own field (no
 *           longer stored as part of authentication code)
 *    23: Added count to autokick entries in channel extension data
 *    22: Fixed bug causing nickgroups with ID 0 to get written out
 *    21: AUTODEOP and NOJOIN levels changed from -10/-20 to -1/-100
 *    20: Access levels changed; v5 level data and access entry levels
 *           added to channel extension data
 *    19: Added last IDENTIFY stamp to nickname extension data
 *    18: Added autojoin functionality; added autojoin list to nickgroup
 *           extension data
 *    17: Added memo ignore functionality; added ignore list to nickgroup
 *           extension data
 *    16: Added Unreal +L/+f handling; added respective fields to channel
 *           extension data
 *    15: Added nick timezones; added timezone field to nickgroup extension
 *           data
 *    14: Added autokick time and lastused fields (saved to channel
 *           extension data)
 *    13: Added nickname privilege level to nickgroup extension data
 */


/* Default channel entries in version 4.5: */
#define CA_SIZE_4_5             18
#define ACCLEV_INVALID_4_5      -10000
static int def_levels_4_5[CA_SIZE_4_5] = {
    
/* CA_INVITE */         5,
    
/* CA_AKICK */         10,
    
/* CA_SET */ ACCLEV_INVALID_4_5,
    
/* CA_UNBAN */          5,
    
/* CA_AUTOOP */         5,
    
/* CA_AUTODEOP */      -1,
    
/* CA_AUTOVOICE */      3,
    
/* CA_OPDEOP */         5,
    
/* CA_ACCESS_LIST */    0,
    
/* CA_CLEAR */ ACCLEV_INVALID_4_5,
    
/* CA_NOJOIN */        -2,
    
/* CA_ACCESS_CHANGE */ 10,
    
/* CA_MEMO */          10,
    
/* CA_VOICE */          3,
    
/* CA_AUTOHALFOP */     4,
    
/* CA_HALFOP */         4,
    
/* CA_AUTOPROTECT */   10,
    
/* CA_PROTECT */       10,
};

/* For handling servadmins/servopers in 4.5.x databases: */
#define MAX_SERVOPERS   256
#define MAX_SERVADMINS  256
static nickname_t services_admins[MAX_SERVADMINS];
static 
nickname_t services_opers[MAX_SERVOPERS];
static 
int services_admins_count 0services_opers_count 0;

/* Database file names (loaded from modules.conf): */
static char *NickDBName;
static 
char *ChanDBName;
static 
char *OperDBName;
static 
char *NewsDBName;
static 
char *AutokillDBName;
static 
char *ExceptionDBName;
static 
char *SlineDBName;
static 
char *StatDBName;

/*************************************************************************/
/**************************** Table load/save ****************************/
/*************************************************************************/

/* Forward declarations of individual load/save routines */

static int load_nick_table(DBTable *nick_tableDBTable *nickgroup_table);
static 
int save_nick_table(DBTable *nick_tableDBTable *nickgroup_table);
static 
int load_chan_table(DBTable *table);
static 
int save_chan_table(DBTable *table);
static 
int load_oper_table(DBTable *table);
static 
int save_oper_table(DBTable *table);
static 
int load_news_table(DBTable *table);
static 
int save_news_table(DBTable *table);
static 
int load_akill_table(DBTable *akill_tableDBTable *exclude_table);
static 
int save_akill_table(DBTable *akill_tableDBTable *exclude_table);
static 
int load_exception_table(DBTable *table);
static 
int save_exception_table(DBTable *table);
static 
int load_sline_table(DBTable *sgline_tableDBTable *sqline_table,
                            
DBTable *szline_table);
static 
int save_sline_table(DBTable *sgline_tableDBTable *sqline_table,
                            
DBTable *szline_table);
static 
int load_stat_servers_table(DBTable *table);
static 
int save_stat_servers_table(DBTable *table);
static 
int load_generic_table(DBTable *table);
static 
int save_generic_table(DBTable *table);

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

static int version4_load_table(DBTable *table)
{
    
int retval 1;

    
/* In order to load nicknames properly, we need access to both nick
     * and nickgroup tables, so we save the value of each table when it's
     * passed in, and only call load_nick_table() when we have both values
     * (after which we clear them for the next time around). */
    
static DBTable *nick_table NULL, *nickgroup_table NULL;
    
/* Likewise for the autokill/exclude and S-line tables. */
    
static DBTable *akill_table NULL, *exclude_table NULL,
                   *
sgline_table NULL, *sqline_table NULL,
                   *
szline_table NULL;

    
/* Most load routines have to go through the data multiple times to
     * read it in, due to the workarounds used to maintain backwards
     * compatibility.  The expiration timestamps may not be correct during
     * this time, so disable expiration while the load is in progress. */
    
int saved_noexpire noexpire;
    
noexpire 1;

    if (
strcmp(table->name"nick") == 0) {
        
nick_table table;
    } else if (
strcmp(table->name"nickgroup") == 0) {
        
nickgroup_table table;
    } else if (
strcmp(table->name"nick-access") == 0
            
|| strcmp(table->name"nick-autojoin") == 0
            
|| strcmp(table->name"memo") == 0
            
|| strcmp(table->name"memo-ignore") == 0) {
        
/* ignore */
    
} else if (strcmp(table->name"chan") == 0) {
        
retval load_chan_table(table);
    } else if (
strcmp(table->name"chan-access") == 0
            
|| strcmp(table->name"chan-akick") == 0) {
        
/* ignore */
    
} else if (strcmp(table->name"oper") == 0) {
        
retval load_oper_table(table);
    } else if (
strcmp(table->name"news") == 0) {
        
retval load_news_table(table);
    } else if (
strcmp(table->name"akill") == 0) {
        
akill_table table;
    } else if (
strcmp(table->name"exclude") == 0) {
        
exclude_table table;
    } else if (
strcmp(table->name"exception") == 0) {
        
retval load_exception_table(table);
    } else if (
strcmp(table->name"sgline") == 0) {
        
sgline_table table;
    } else if (
strcmp(table->name"sqline") == 0) {
        
sqline_table table;
    } else if (
strcmp(table->name"szline") == 0) {
        
szline_table table;
    } else if (
strcmp(table->name"stat-servers") == 0) {
        
retval load_stat_servers_table(table);
    } else {
        
retval load_generic_table(table);
    }
    if (
nick_table && nickgroup_table) {
        
/* Got both tables, run the load routine and clear the variables */
        
retval load_nick_table(nick_tablenickgroup_table);
        
nick_table nickgroup_table NULL;
    }
    if (
akill_table && exclude_table) {
        
retval load_akill_table(akill_tableexclude_table);
        
akill_table exclude_table NULL;
    }
    if (
sgline_table && sqline_table && szline_table) {
        
retval load_sline_table(sgline_tablesqline_tableszline_table);
        
sgline_table sqline_table szline_table NULL;
    }

    
noexpire saved_noexpire;

    if (
retval && table->postload && !(*table->postload)()) {
        
module_log_perror("Table %s postload routine failed"table->name);
        
retval 0;
    }

    return 
retval;
}

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

static int version4_save_table(DBTable *table)
{
    
/* See version4_load_table() for why we need these */
    
static DBTable *nick_table NULL, *nickgroup_table NULL,
                   *
akill_table NULL, *exclude_table NULL,
                   *
sgline_table NULL, *sqline_table NULL,
                   *
szline_table NULL;

    if (
strcmp(table->name"nick") == 0) {
        
nick_table table;
    } else if (
strcmp(table->name"nickgroup") == 0) {
        
nickgroup_table table;
    } else if (
strcmp(table->name"nick-access") == 0
            
|| strcmp(table->name"nick-autojoin") == 0
            
|| strcmp(table->name"memo") == 0
            
|| strcmp(table->name"memo-ignore") == 0) {
        
/* ignore */
    
} else if (strcmp(table->name"chan") == 0) {
        return 
save_chan_table(table);
    } else if (
strcmp(table->name"chan-access") == 0
            
|| strcmp(table->name"chan-akick") == 0) {
        
/* ignore */
    
} else if (strcmp(table->name"oper") == 0) {
        return 
save_oper_table(table);
    } else if (
strcmp(table->name"news") == 0) {
        return 
save_news_table(table);
    } else if (
strcmp(table->name"akill") == 0) {
        
akill_table table;
    } else if (
strcmp(table->name"exclude") == 0) {
        
exclude_table table;
    } else if (
strcmp(table->name"exception") == 0) {
        return 
save_exception_table(table);
    } else if (
strcmp(table->name"sgline") == 0) {
        
sgline_table table;
    } else if (
strcmp(table->name"sqline") == 0) {
        
sqline_table table;
    } else if (
strcmp(table->name"szline") == 0) {
        
szline_table table;
    } else if (
strcmp(table->name"stat-servers") == 0) {
        return 
save_stat_servers_table(table);
    } else {
        return 
save_generic_table(table);
    }
    if (
nick_table && nickgroup_table) {
        
int retval save_nick_table(nick_tablenickgroup_table);
        
nick_table nickgroup_table NULL;
        return 
retval;
    }
    if (
akill_table && exclude_table) {
        
int retval save_akill_table(akill_tableexclude_table);
        
akill_table exclude_table NULL;
        return 
retval;
    }
    if (
sgline_table && sqline_table && szline_table) {
        
int retval =
            
save_sline_table(sgline_tablesqline_tableszline_table);
        
sgline_table sqline_table szline_table NULL;
        return 
retval;
    }

    return 
1;
}

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

/* Common routine to open a file for reading and check version number. */

#define OPENDB_ERROR    ((dbFILE *)PTR_INVALID)

static dbFILE *my_open_db_r(const char *dbnameint32 *ver_ret)
{
    
dbFILE *f;
    
int32 ver;

    
open_db(dbname"r"0);
    if (!
f)
        return 
NULL;
    
ver get_file_version(f);
    if (
ver || ver 11) {
        if (
ver == -1) {
            
module_log("Unable to read version number from %s",
                
dbname);
        } else {
            
module_log("Invalid version number %d on %s"ver,
                
dbname);
        }
        
close_db(f);
        return 
OPENDB_ERROR;
    }
    *
ver_ret ver;
    return 
f;
}

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

/* Read a MaskData category from a file. */

static int read_maskdata(DBTable *tableuint8 type, const char *dbname,
                         
dbFILE *f)
{
    
int32 ver;
    
MaskData *md;
    
int16 count;
    
int i;

#if CLEAN_COMPILE
    
count 0;
#endif
    
SAFE(read_int16(&countf));
    for (
0counti++) {
        
int32 t---2;
        
md table->newrec();
        
SAFE(read_string(&md->maskf));
        if (
type == MD_EXCEPTION) {
            
SAFE(read_int16(&md->limitf));
            
SAFE(read_buffer(md->whof));
            
SAFE(read_string(&md->reasonf));
        } else {
            
SAFE(read_string(&md->reasonf));
            
SAFE(read_buffer(md->whof));
        }
        
SAFE(read_int32(&t---2f));
        
md->time t---2;
        
SAFE(read_int32(&t---2f));
        
md->expires t---2;
        
md->num i+1;
        
table->insert(md);
    }
    if (
read_int32(&verf) == 0) {
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION) {
            
module_log("Invalid extension data version in %s"dbname);
            return 
0;
        }
        for (
0counti++) {
            
/* O(n^2), but we can't help it if we want to be robust */
            
for (md table->first(); mdmd table->next()) {
                if (
md->num == i+1)
                    break;
            }
            if (
md) {
                
SAFE(read_time(&md->timef));
                
SAFE(read_time(&md->expiresf));
                
SAFE(read_time(&md->lastusedf));
            }
        }
    }
    return 
1;

  
fail:
    
close_db(f);
    
module_log("Read error on %s"dbname);
    return 
0;
}

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

/* Write a MaskData category to a file. */

static int write_maskdata(DBTable *tableuint8 type, const char *dbname,
                          
dbFILE *f)
{
    static 
time_t lastwarn[256];
    
MaskData *md;
    
int count;
    
int save_noexpire noexpire;

    
count 0;
    for (
md table->first(); mdmd table->next())
        
count++;
    
write_int16(countf);
    
/* Disable expiration for the remainder of this function.  This is a
     * kludge to ensure that nothing expires while we're writing it out. */
    
noexpire 1;
    for (
md table->first(); mdmd table->next()) {
        
SAFE(write_string(md->maskf));
        if (
type == MD_EXCEPTION) {
            
SAFE(write_int16(md->limitf));
            
SAFE(write_buffer(md->whof));
            
SAFE(write_string(md->reasonf));
        } else {
            
SAFE(write_string(md->reasonf));
            
SAFE(write_buffer(md->whof));
        }
        
SAFE(write_int32(md->timef));
        
SAFE(write_int32(md->expiresf));
    }
    
SAFE(write_int32(LOCAL_VERSION_50f));
    for (
md table->first(); mdmd table->next()) {
        
SAFE(write_time(md->timef));
        
SAFE(write_time(md->expiresf));
        
SAFE(write_time(md->lastusedf));
    }
    
noexpire save_noexpire;
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"dbname);
    if (
time(NULL) - lastwarn[type] > WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"dbnamestrerror(errno));
        
lastwarn[type] = time(NULL);
    }
    
noexpire save_noexpire;
    return 
0;
}

/*************************************************************************/
/********************** NickServ database handling ***********************/
/*************************************************************************/

#define NGI_TEMP_ID     0xFFFFFFFFU  /* until we know the real group */

static NickInfo *load_one_nick(DBTable *nick_tableDBTable *nickgroup_table,
                               
dbFILE *fint32 ver)
{
    
NickInfo *ni;
    
NickGroupInfo *ngi;
    
int16 tmp16;
    
int32 t---2;
    
int i;
    
char passbuf[PASSMAX];
    
char *url, *email;

    
ni nick_table->newrec();
    
SAFE(read_buffer(ni->nickf));
    
module_log_debug(2"loading nick %s"ni->nick);
    
SAFE(read_buffer(passbuff));
    
SAFE(read_string(&urlf));
    
SAFE(read_string(&emailf));
    
SAFE(read_string(&ni->last_usermaskf));
    if (!
ni->last_usermask)
        
ni->last_usermask sstrdup("@");
    
SAFE(read_string(&ni->last_realnamef));
    if (!
ni->last_realname)
        
ni->last_realname sstrdup("");
    
SAFE(read_string(&ni->last_quitf));
    
SAFE(read_int32(&t---2f));
    
ni->time_registered t---2;
    
SAFE(read_int32(&t---2f));
    
ni->last_seen t---2;
    
SAFE(read_int16(&ni->statusf));
    
ni->status &= NS_PERMANENT;
    
/* Old-style links were hierarchical; if this nick was linked to
     * another, the name of the parent link, else NULL, was stored here.
     * Store that value in ni->last_realmask, which coincidentally was
     * not saved before version 5.0, and resolve links later. */
    
SAFE(read_string(&ni->last_realmaskf));
    
SAFE(read_int16(&tmp16f));  /* linkcount */
    
if (ni->last_realmask) {
        
SAFE(read_int16(&tmp16f));  /* channelcount */
        
free(url);
        
free(email);
    } else {
        
ngi nickgroup_table->newrec();
        
ngi->id NGI_TEMP_ID;
        
ARRAY_EXTEND(ngi->nicks);
        
strbcpy(ngi->nicks[0], ni->nick);
        
init_password(&ngi->pass);
        
encrypt_password("a"1, &ngi->pass);  /* get encryption type */
        
memcpy(ngi->pass.passwordpassbufPASSMAX);
        
ngi->url url;
        
ngi->email email;
        
SAFE(read_int32(&ngi->flagsf));
        if (
ngi->flags NF_KILL_IMMED)
            
ngi->flags |= NF_KILL_QUICK;
        
ngi->flags |= NF_NOGROUP;
        if (
ver >= 9) {
            
void *tmpptr;
            
SAFE(read_ptr(&tmpptrf));
            if (
tmpptr)
                
ngi->flags |= NF_SUSPENDED;
            else
                
ngi->flags &= ~NF_SUSPENDED;
        } else if (
ver == && (ngi->flags 0x10000000)) {
            
/* In version 8, 0x10000000 was NI_SUSPENDED */
            
ngi->flags |= NF_SUSPENDED;
        } else {
            
ngi->flags &= ~NF_SUSPENDED;  /* just in case */
        
}
        if (
ngi->flags NF_SUSPENDED) {
            
SAFE(read_buffer(ngi->suspend_whof));
            
SAFE(read_string(&ngi->suspend_reasonf));
            
SAFE(read_int32(&t---2f));
            
ngi->suspend_time t---2;
            
SAFE(read_int32(&t---2f));
            
ngi->suspend_expires t---2;
        }
        
SAFE(read_int16(&ngi->access_countf));
        if (
ngi->access_count) {
            
char **access;
            
access smalloc(sizeof(char *) * ngi->access_count);
            
ngi->access access;
            
ARRAY_FOREACH (ingi->access)
                
SAFE(read_string(&ngi->access[i], f));
        }
        
SAFE(read_int16(&ngi->memos.memos_countf));
        
SAFE(read_int16(&ngi->memos.memomaxf));
        
/*
         * Note that at this stage we have no way of comparing this to the
         * default memo max (MSMaxMemos) because the MemoServ module is not
         * loaded.  If this is a 5.x database, this is not a problem,
         * because the correct memo max value will be stored in the
         * extension data, but if not, we need to check and change the
         * value to MEMOMAX_DEFAULT as needed.  This is handled by a
         * callback (nick_memomax_callback() below) which triggers when the
         * MemoServ module is loaded.  The callback is added by
         * open_nick_db() if needed.
         */
        
if (ngi->memos.memos_count) {
            
Memo *memos;
            
memos smalloc(sizeof(Memo) * ngi->memos.memos_count);
            
ngi->memos.memos memos;
            
ARRAY_FOREACH (ingi->memos.memos) {
                
SAFE(read_uint32(&ngi->memos.memos[i].numberf));
                
SAFE(read_int16(&ngi->memos.memos[i].flagsf));
                
SAFE(read_int32(&t---2f));
                
ngi->memos.memos[i].time t---2;
                if (
ngi->memos.memos[i].flags MF_UNREAD)
                    
ngi->memos.memos[i].firstread 0;
                else
                    
ngi->memos.memos[i].firstread t---2;
                
SAFE(read_buffer(ngi->memos.memos[i].senderf));
                
ngi->memos.memos[i].channel NULL;
                
SAFE(read_string(&ngi->memos.memos[i].textf));
            }
        }
        
/* Channel counts are recalculated by open_channel_db() */
        
SAFE(read_int16(&tmp16f));  /* channelcount */
        /* If this is a 5.x database, we now get the real nickgroup value
         * from bits 30-15 of the flags and the 16 bits we just read; the
         * real flags value is stored in the extension data. */
        
if (ngi->flags 0x80000000) {
            
ngi->id = (ngi->flags 0x7FFF8000) << | ((int)tmp16 0xFFFF);
            
ngi->flags &= ~NF_NOGROUP;
        }
        
/* There was no way to set channel limits, so must be the default.
         * Note that if this is a 5.x database, the correct value for this
         * field (as well as memomax and language) will be read from the
         * extension data. */
        
SAFE(read_int16(&tmp16f));  /* channelmax */
        
ngi->channelmax CHANMAX_DEFAULT;
        
SAFE(read_int16(&ngi->languagef));
        if (!
have_language(ngi->language))
            
ngi->language LANG_DEFAULT;
        
/* Ver 4.x had no way to say "use the default language", so set that
         * for all nicks that are using DEF_LANGUAGE */
        
if (ngi->language == DEF_LANGUAGE)
            
ngi->language LANG_DEFAULT;
        
ngi->timezone TIMEZONE_DEFAULT;
        
ni->nickgroup ngi->id;
        if (
ngi->id != 0) {
            
nickgroup_table->insert(ngi);
        } else {
            
nickgroup_table->freerec(ngi);
            if (!(
ni->status NS_VERBOTEN)) {
                
module_log("warning: nick %s has no nick group but is not"
                           " forbidden (corrupt database or BUG?)"
ni->nick);
            }
        }
    }
    return 
ni;

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

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

/* Load extension data for a nick.  Returns zero on success, nonzero on
 * failure.
 */

static int load_one_nick_ext(DBTable *nick_tableDBTable *nickgroup_table,
                             
dbFILE *fint32 ver)
{
    
char *nick;
    
NickInfo *ni NULL;
    
NickInfo dummy_ni;  /* for nonexistent nicks */

    
SAFE(read_string(&nickf));
    if (!
nick)
        goto 
fail;
    
module_log_debug(2"loading nick extension %s"nick);
    if (!(
ni get_nickinfo(nick))) {
        
module_log("Extension data found for nonexistent nick `%s'"nick);
        
ni = &dummy_ni;
        
memset(ni0sizeof(*ni));
    }
    
free(nick);
    
nick NULL;
    
free(ni->last_realmask);  /* copied from last_usermask */
    
SAFE(read_string(&ni->last_realmaskf));
    if (
ver >= 19)
        
SAFE(read_uint32(&ni->id_stampf));
    if (
ni == &dummy_ni)
        
free(ni->last_realmask);
    else
        
put_nickinfo(ni);
    return 
1;

  
fail:
    
module_log("Read error on %s"f->filename);
    if (
ni != &dummy_ni)
        
put_nickinfo(ni);
    return 
0;
}

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

/* Load extension data for a nick group. */

static int load_one_nickgroup_ext(DBTable *tabledbFILE *fint32 ver)
{
    
uint32 group;
    
NickGroupInfo *ngi NULL;
    
NickGroupInfo dummy_ngi;  /* for nonexistent nick groups */
    
int i;

    
SAFE(read_uint32(&groupf));
    
module_log_debug(2"loading nickgroup extension %u"group);
    if (!
group) {
        if (
ver 22) {
            
module_log("Ignoring nickgroup 0 (bug in previous versions)");
            
ngi = &dummy_ngi;
            
memset(ngi0sizeof(*ngi));
        } else {
            goto 
fail;
        }
    } else if (!(
ngi get_nickgroupinfo(group))) {
        
module_log("Extension data found for nonexistent nick group %u",
                   
group);
        
ngi = &dummy_ngi;
        
memset(ngi0sizeof(*ngi));
    }
    
SAFE(read_int32(&ngi->flagsf));
    
SAFE(read_int32(&ngi->authcodef));
    
SAFE(read_time(&ngi->authsetf));
    if (
ver >= 24) {
        
SAFE(read_int16(&ngi->authreasonf));
    } else {
        switch ((
ngi->authcode 0x300) >> 8) {
            case 
ngi->authreason NICKAUTH_REGISTER;  break;
            case 
ngi->authreason NICKAUTH_SET_EMAIL; break;
            case 
ngi->authreason NICKAUTH_SETAUTH;   break;
            default: 
ngi->authreason 0;                  break;
        }
    }
    
SAFE(read_int16(&ngi->channelmaxf));
    if (
ver >= 18) {
        
SAFE(read_int16(&ngi->ajoin_countf));
        if (
ngi->ajoin_count) {
            
ngi->ajoin smalloc(sizeof(char *) * ngi->ajoin_count);
            
ARRAY_FOREACH (ingi->ajoin)
                
SAFE(read_string(&ngi->ajoin[i], f));
        }
    }
    
SAFE(read_int16(&ngi->memos.memomaxf));
    if (
ver >= 17) {
        
SAFE(read_int16(&ngi->ignore_countf));
        if (
ngi->ignore_count) {
            
ngi->ignore smalloc(sizeof(char *) * ngi->ignore_count);
            
ARRAY_FOREACH (ingi->ignore)
                
SAFE(read_string(&ngi->ignore[i], f));
        }
    }
    
SAFE(read_int16(&ngi->languagef));
    if (!
have_language(ngi->language))
        
ngi->language LANG_DEFAULT;
    if (
ver >= 15)
        
SAFE(read_int16(&ngi->timezonef));
    
SAFE(read_string(&ngi->infof));
    if (
ver >= 13)
        
SAFE(read_int16(&ngi->os_privf));
    if (
ngi == &dummy_ngi) {
        
ARRAY_FOREACH (ingi->ajoin)
            
free(ngi->ajoin[i]);
        
free(ngi->ajoin);
        
ARRAY_FOREACH (ingi->ignore)
            
free(ngi->ignore[i]);
        
free(ngi->ignore);
    } else {
        
put_nickgroupinfo(ngi);
    }
    return 
1;

  
fail:
    
module_log("Read error on %s"f->filename);
    if (
ngi != &dummy_ngi)
        
put_nickgroupinfo(ngi);
    return 
0;
}

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

/* Load version 5.1 extension data for a nick group. */

static int load_one_nickgroup_ext51(DBTable *tabledbFILE *fint32 ver)
{
    
uint16 tmp16;
    
uint32 group;
    
NickGroupInfo *ngi NULL;
    
NickGroupInfo dummy_ngi;  /* for nonexistent nick groups */
    
int i;

    
SAFE(read_uint32(&groupf));
    
module_log_debug(2"loading nickgroup extension %u"group);
    if (!
group) {
        goto 
fail;
    } else if (!(
ngi get_nickgroupinfo(group))) {
        
module_log("5.1 extension data found for nonexistent nick group %u",
                   
group);
        
ngi = &dummy_ngi;
        
memset(ngi0sizeof(*ngi));
        
init_password(&ngi->pass);
    }
    
SAFE(read_string(&ngi->last_emailf));
    
SAFE(read_uint16(&tmp16f));
    if (
ngi != &dummy_ngi && tmp16 != ngi->memos.memos_count) {
        
module_log("Warning: memo count mismatch on nickgroup %u"
                   " (main data: %d, ext51 data: %d)"
ngi->id,
                   
ngi->memos.memos_counttmp16);
    }
    for (
0tmp16i++) {
        
time_t t;
        
char *s;
        
SAFE(read_time(&tf));
        
SAFE(read_string(&sf));
        if (
ngi != &dummy_ngi && ngi->memos.memos_count) {
            
ngi->memos.memos[i].firstread t;
            
ngi->memos.memos[i].channel s;
        } else {
            
free(s);
        }
    }
    
free((char *)ngi->pass.cipher);
    
SAFE(read_string((char **)&ngi->pass.cipherf));
    if (
ngi == &dummy_ngi) {
        
ARRAY_FOREACH (ingi->ajoin)
            
free(ngi->ajoin[i]);
        
free(ngi->ajoin);
        
ARRAY_FOREACH (ingi->ignore)
            
free(ngi->ignore[i]);
        
free(ngi->ignore);
        
clear_password(&ngi->pass);
    } else {
        
put_nickgroupinfo(ngi);
    }
    return 
1;

  
fail:
    
module_log("Read error on %s"f->filename);
    if (
ngi != &dummy_ngi)
        
put_nickgroupinfo(ngi);
    return 
0;
}

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

static int nick_memomax_callback(Module *mod, const char *name)
{
    
NickGroupInfo *ngi;

    if (
strcmp(name"memoserv/main") != 0)
        return 
0;
    for (
ngi first_nickgroupinfo(); ngingi next_nickgroupinfo()) {
        if (
ngi->memos.memomax == MSMaxMemos)
            
ngi->memos.memomax MEMOMAX_DEFAULT;
    }
    
/* We only need to do this once */
    
remove_callback(NULL"load module"nick_memomax_callback);
    return 
0;
}

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

static int load_nick_table(DBTable *nick_tableDBTable *nickgroup_table)
{
    
dbFILE *f;
    
int32 ver;
    
int ic;
    
NickInfo *ni;
    
NickGroupInfo *ngi;
    
int failed 0need_memomax_check 1;

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

    
/* Load original data. */
    
for (0256 && !failedi++) {
        while ((
getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in nick.db");
                
failed 1;
            }
            
ni load_one_nick(nick_tablenickgroup_tablefver);
            if (
ni) {
                
nick_table->insert(ni);
            } else {
                
failed 1;
            }
        }
    }

    
/* Assign nickgroup IDs to groups that don't have them (e.g. from a
     * 4.5 database) */
    
for (ngi nickgroup_table->first(); ngingi nickgroup_table->next()) {
        if (
ngi->flags NF_NOGROUP) {
#define NEWNICKGROUP_TRIES 1000
            
int tries;
            for (
tries 0tries NEWNICKGROUP_TRIEStries++) {
                
uint32 id rand() + rand();
                if (
id == || id == NGI_TEMP_ID)
                    
id 1;
                if (!
get_nickgroupinfo(id)) {
                    
ngi->id id;
                    break;
                }
            }
            if (
tries >= NEWNICKGROUP_TRIES) {
                
module_log("load_nick_table(): unable to assign new ID to"
                           " nickgroup for nick %s--dropping"
ngi->nicks[0]);
                
ARRAY_FOREACH (ingi->nicks) {
                    if ((
ni get_nickinfo(ngi->nicks[i])) != NULL)
                        
del_nickinfo(ni);
                }
                
del_nickgroupinfo(ngi);
            }
        }
    }

    
/* Resolve links.  First point each last_realmask field at the
     * NickInfo * of the appropriate nick; then copy the nickgroup ID from
     * each root nick to all of its children, effectively collapsing the
     * link hierarchies to a single level, and add the child nicks to the
     * root nickgroup's nick array.
     */
    
for (ni nick_table->first(); nini nick_table->next()) {
        if (
ni->last_realmask) {
            
char *ni->last_realmask;
            
ni->last_realmask = (char *)get_nickinfo(s);
            
free(s);
        }
    }
    for (
ni nick_table->first(); nini nick_table->next()) {
        if (
ni->last_realmask) {
            
NickInfo *root = (NickInfo *)ni->last_realmask;
            
NickGroupInfo *ngi;
            while (
root->last_realmask)
                
root = (NickInfo *)root->last_realmask;
            
ni->nickgroup root->nickgroup;
            
ngi get_nickgroupinfo(ni->nickgroup);
            if (!
ngi) {
                
module_log("BUG: Unable to find nickgroup %u for linked"
                           " nick %s (parent = %s, root = %s)"
,
                           
ni->nickgroupni->nick,
                           ((
NickInfo *)ni->last_realmask)->nick,
                           
root->nick);
            } else {
                
ARRAY_EXTEND(ngi->nicks);
                
strbcpy(ngi->nicks[ngi->nicks_count-1], ni->nick);
                
put_nickgroupinfo(ngi);
            }
        }
        if (!
ni->nickgroup && !(ni->status NS_VERBOTEN)) {
            
module_log("Nick %s has no settings (linked to missing nick?),"
                       " deleting"
ni->nick);
            if (
ni->last_realmask)
                
put_nickinfo((NickInfo *)ni->last_realmask);
            
ni->last_realmask NULL;  /* Don't free someone else's NickInfo */
            
del_nickinfo(ni);
        }
    }

    
/* Copy all last_usermask fields to last_realmask. */
    
for (ni nick_table->first(); nini nick_table->next()) {
        if (
ni->last_realmask)
            
put_nickinfo((NickInfo *)ni->last_realmask);
        
ni->last_realmask sstrdup(ni->last_usermask);
    }

    
/* Load extension data if present. */
    
ver 0;
    if (
read_int32(&verf) == 0) {
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION_50) {
            
module_log("Invalid extension data version in nick.db");
            
failed 1;
        } else {
            while (!
failed && (getc_db(f)) != 0) {
                if (
!= 1) {
                    
module_log("Invalid format in nick.db extension data");
                    
failed 1;
                } else if (!
load_one_nick_ext(nick_tablenickgroup_table,
                                              
fver)) {
                    
failed 1;
                }
            }
            while (!
failed && (getc_db(f)) != 0) {
                if (
!= 1) {
                    
module_log("Invalid format in nick.db extension data");
                    
failed 1;
                } else if (!
load_one_nickgroup_ext(nickgroup_tablefver)) {
                    
failed 1;
                }
            }
        }
        
need_memomax_check 0;
    }
    if (
read_int32(&verf) == 0) {
        if (
ver FIRST_VERSION_51 || ver LOCAL_VERSION) {
            
module_log("Invalid extension (5.1) data version in nick.db");
            
failed 1;
        } else {
            while (!
failed && (getc_db(f)) != 0) {
                if (
!= 1) {
                    
module_log("Invalid format in nick.db extension (5.1)"
                               " data"
);
                    
failed 1;
                } else if (!
load_one_nickgroup_ext51(nickgroup_tablefver)){
                    
failed 1;
                }
            }
        }
    }

    if (!
failed && ver 13) {
        
/* Need to restore Services admin/oper privs from oper.db lists */
        
NickGroupInfo *ngi;
        
ARRAY_FOREACH (iservices_admins) {
            
ni get_nickinfo(services_admins[i]);
            if (
ni != NULL && (ngi get_ngi(ni)) != NULL) {
                
ngi->os_priv NP_SERVADMIN;
                
put_nickgroupinfo(ngi);
            }
            
put_nickinfo(ni);
        }
        
ARRAY_FOREACH (iservices_opers) {
            
ni get_nickinfo(services_opers[i]);
            if (
ni != NULL && (ngi get_ngi(ni)) != NULL) {
                
ngi->os_priv NP_SERVOPER;
                
put_nickgroupinfo(ngi);
            }
            
put_nickinfo(ni);
        }
    }

    
/* Add the memomax check callback if needed. */
    
if (!failed && need_memomax_check)
        
add_callback(NULL"load module"nick_memomax_callback);

    
/* Close database. */
    
close_db(f);

    
/* All done! */
    
return !failed || forceload;
}

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

static int save_nick_table(DBTable *nick_tableDBTable *nickgroup_table)
{
    
dbFILE *f;
    
int i;
    
NickInfo *ni;
    
NickGroupInfo *ngi;
    static 
NickGroupInfo forbidden_ngi;  /* dummy for forbidden nicks */
    
static time_t lastwarn 0;

    if (!(
open_db(NickDBName"w"11)))
        return 
0;
    for (
ni nick_table->first(); nini nick_table->next()) {
        if (
ni->nickgroup)
            
ngi get_nickgroupinfo(ni->nickgroup);
        else
            
ngi NULL;
        
SAFE(write_int8(1f));
        
SAFE(write_buffer(ni->nickf));
        if (
ngi) {
            
SAFE(write_buffer(ngi->pass.passwordf));
            
SAFE(write_string(ngi->urlf));
            
SAFE(write_string(ngi->emailf));
        } else {
            
Password dummypass;
            
init_password(&dummypass);
            if (!(
ni->status NS_VERBOTEN)) {
                
module_log("nick %s has no NickGroupInfo, setting password"
                           " to nick"
ni->nick);
                
encrypt_password(ni->nickstrlen(ni->nick), &dummypass);
            }
            
SAFE(write_buffer(dummypass.passwordf));
            
clear_password(&dummypass);
            
SAFE(write_string(NULLf));
            
SAFE(write_string(NULLf));
        }
        
SAFE(write_string(ni->last_usermaskf));
        
SAFE(write_string(ni->last_realnamef));
        
SAFE(write_string(ni->last_quitf));
        
SAFE(write_int32(ni->time_registeredf));
        
SAFE(write_int32(ni->last_seenf));
        
SAFE(write_int16(ni->statusf));
        if (
ngi && irc_stricmp(ni->nickngi_mainnick(ngi)) != 0) {
            
/* Not the main nick in the group; save it as a link */
            
SAFE(write_string(ngi_mainnick(ngi), f));
            
SAFE(write_int16(0f));
            
SAFE(write_int16(0f));
        } else {
            
int32 t---2;
            
/* Main nick in the group, or forbidden; save as a root nick */
            
SAFE(write_string(NULLf));
            
SAFE(write_int16(0f));
            
/* If it's forbidden, use a dummy NickGroupInfo from here on */
            
if (!ngi)
                
ngi = &forbidden_ngi;
            
/* Store top 16 bits of group ID in flags */
            
t---ngi->flags 0x80000000 | (ngi->id 0xFFFF0000)>>1;
            if (
t---NF_KILL_IMMED)
                
t---&= ~NF_KILL_QUICK;
            
SAFE(write_int32(t---2f));
            
SAFE(write_ptr((ngi->flags NF_SUSPENDED) ? (void *)NULLf));
            if (
ngi->flags NF_SUSPENDED) {
                
SAFE(write_buffer(ngi->suspend_whof));
                
SAFE(write_string(ngi->suspend_reasonf));
                
SAFE(write_int32(ngi->suspend_timef));
                
SAFE(write_int32(ngi->suspend_expiresf));
            }
            
SAFE(write_int16(ngi->access_countf));
            
ARRAY_FOREACH (ingi->access)
                
SAFE(write_string(ngi->access[i], f));
            
SAFE(write_int16(ngi->memos.memos_countf));
            
/* Note that we have to save the memo maximum here as a static
             * value; we save the real value (which may be MEMOMAX_DEFAULT)
             * in the extension area below.  The same applies for channelmax
             * and language. */
            
if (ngi->memos.memomax == MEMOMAX_DEFAULT)
                
SAFE(write_int16(MSMaxMemosf));
            else
                
SAFE(write_int16(ngi->memos.memomaxf));
            
ARRAY_FOREACH (ingi->memos.memos) {
                
SAFE(write_int32(ngi->memos.memos[i].numberf));
                
SAFE(write_int16(ngi->memos.memos[i].flagsf));
                
SAFE(write_int32(ngi->memos.memos[i].timef));
                
SAFE(write_buffer(ngi->memos.memos[i].senderf));
                
SAFE(write_string(ngi->memos.memos[i].textf));
            }
            
/* Store bottom 16 bits of group ID in channelcount */
            
SAFE(write_int16(ngi->id 0xFFFFf));
            if (
ngi->channelmax == CHANMAX_DEFAULT)
                
SAFE(write_int16(CSMaxRegf));
            else
                
SAFE(write_int16(ngi->channelmaxf));
            if (
ngi->language == LANG_DEFAULT)
                
SAFE(write_int16(DEF_LANGUAGEf));
            else
                
SAFE(write_int16(ngi->languagef));
        }
        
put_nickgroupinfo(ngi);
    } 
/* for (ni) */
    
{
        
/* This is an UGLY HACK but it simplifies loading. */
        
static char buf[256];  /* initialized to zero */
        
SAFE(write_buffer(buff));
    }

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

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

    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"NickDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"NickDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/********************** ChanServ database handling ***********************/
/*************************************************************************/

/* Helper functions to convert between old and new channel levels. */

static inline int16 convert_old_level(int16 old)
{
    if (
old 0)
        return -
convert_old_level(-old);/* avoid negative division */
    
else if (old <= 25)
        return 
old*10;                  /*    0..  25 ->   0..250 (10x) */
    
else if (old <= 50)
        return 
200 old*2;             /*   25..  50 -> 250..300 ( 2x) */
    
else if (old <= 100)
        return 
280 old*2/5;           /*   50.. 100 -> 300..320 ( 0.4x) */
    
else if (old <= 1000)
        return 
300 old/5;             /*  100..1000 -> 320..500 ( 0.2x) */
    
else if (old <= 2000)
        return 
400 old/10;            /* 1000..2000 -> 500..600 ( 0.1x) */
    
else
        return 
500 old/20;            /* 2000..9999 -> 600..999 ( 0.05x) */
}

static 
inline int16 convert_new_level(int16 new)
{
    if (new < 
0)
        return -
convert_new_level(-new);/* avoid negative division */
    
else if (new <= 250)
        return new/
10;                  /*   0..250 ->    0..  25 */
    
else if (new <= 300)
        return new/
100;             /* 250..300 ->   25..  50 */
    
else if (new <= 320)
        return new*
5/700;           /* 300..320 ->   50.. 100 */
    
else if (new <= 500)
        return new*
1500;            /* 320..500 ->  100..1000 */
    
else if (new <= 600)
        return new*
10 4000;           /* 500..600 -> 1000..2000 */
    
else
        return new*
20 10000;          /* 600..999 -> 2000..9980 */
}

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

static ChannelInfo *load_one_channel(DBTable *tabledbFILE *fint32 ver)
{
    
ChannelInfo *ci;
    
NickInfo *ni;
    
MemoInfo tmpmi;
    
int16 tmp16lev;
    
int32 t---2;
    
int n_levels;
    
char *s;
    
int i;

    
ci table->newrec();
    
SAFE(read_buffer(ci->namef));
    
module_log_debug(2"loading channel %s"ci->name);
    
SAFE(read_string(&sf));
    if (
s) {
        
ni get_nickinfo(s);
        if (
ni) {
            
ci->founder ni->nickgroup;
            
put_nickinfo(ni);
        }
        
free(s);
    }
    if (
ver >= 7) {
        
SAFE(read_string(&sf));
        if (
s) {
            
ni get_nickinfo(s);
            if (
ni) {
                
ci->successor ni->nickgroup;
                
put_nickinfo(ni);
            }
            
free(s);
        }
        
/* Founder could be successor, which is bad, in vers 7,8 */
        /* We can also have the case where two linked nicks were founder
         * and successor, which would give them the same group ID in this
         * version--remove the successor in this case as well */
        
if (ci->founder == ci->successor)
            
ci->successor 0;
    }
    
init_password(&ci->founderpass);
    
encrypt_password("a"1, &ci->founderpass);  /* get encryption type */
    
SAFE(read_buffer(ci->founderpass.passwordf));
    
SAFE(read_string(&ci->descf));
    if (!
ci->desc)
        
ci->desc sstrdup("");
    
SAFE(read_string(&ci->urlf));
    
SAFE(read_string(&ci->emailf));
    
SAFE(read_int32(&t---2f));
    
ci->time_registered t---2;
    
SAFE(read_int32(&t---2f));
    
ci->last_used t---2;
    
SAFE(read_string(&ci->last_topicf));
    
SAFE(read_buffer(ci->last_topic_setterf));
    
SAFE(read_int32(&t---2f));
    
ci->last_topic_time t---2;
    
SAFE(read_int32(&ci->flagsf));
    
ci->flags &= CF_ALLFLAGS;  /* clear any invalid flags */
    
if (ver >= 9) {
        
void *tmpptr;
        
SAFE(read_ptr(&tmpptrf));
        if (
tmpptr) {
            
SAFE(read_buffer(ci->suspend_whof));
            
SAFE(read_string(&ci->suspend_reasonf));
            
SAFE(read_int32(&t---2f));
            
ci->suspend_time t---2;
            
SAFE(read_int32(&t---2f));
            
ci->suspend_expires t---2;
            
ci->flags |= CF_SUSPENDED;
        }
    }
    
SAFE(read_int16(&tmp16f));
    
n_levels tmp16;
    
reset_levels(ci);
    for (
0n_levelsi++) {
        
SAFE(read_int16(&levf));
        if (
CA_SIZE)
            
ci->levels[i] = convert_old_level(lev);
    }

    
SAFE(read_int16(&ci->access_countf));
    if (
ci->access_count) {
        
ci->access scalloc(ci->access_countsizeof(ChanAccess));
        
ARRAY_FOREACH (ici->access) {
            
ci->access[i].channel ci;
            
SAFE(read_int16(&tmp16f));  /* in_use */
            
if (tmp16) {
                
SAFE(read_int16(&levf));
                
ci->access[i].level convert_old_level(lev);
                
SAFE(read_string(&sf));
                if (
s) {
                    
ni get_nickinfo(s);
                    if (
ni) {
                        
ci->access[i].nickgroup ni->nickgroup;
                        
put_nickinfo(ni);
                    }
                    
free(s);
                }
            }
        }
    } else {
        
ci->access NULL;
    }

    
SAFE(read_int16(&ci->akick_countf));
    if (
ci->akick_count) {
        
ci->akick scalloc(ci->akick_countsizeof(AutoKick));
        
ARRAY_FOREACH (ici->akick) {
            
ci->akick[i].channel ci;
            
SAFE(read_int16(&tmp16f));  /* in_use */
            
if (tmp16) {
                
SAFE(read_int16(&tmp16f));  /* is_nick */
                
SAFE(read_string(&sf));
                if (
tmp16) {
                    
ci->akick[i].mask smalloc(strlen(s)+5);
                    
sprintf(ci->akick[i].mask"%s!*@*"s);
                    
free(s);
                } else {
                    
ci->akick[i].mask s;
                }
                
SAFE(read_string(&ci->akick[i].reasonf));
                if (
ver >= 8)
                    
SAFE(read_buffer(ci->akick[i].whof));
                else
                    *
ci->akick[i].who 0;
                
time(&ci->akick[i].set);
                
ci->akick[i].lastused 0;
            } 
/* if (in_use) */
        
/* for (i = 0..ci->akick_count-1) */
    
} else {
        
ci->akick NULL;
    }

    if (
ver 10) {
        
SAFE(read_int16(&tmp16f));
        
ci->mlock.on tmp16;
        
SAFE(read_int16(&tmp16f));
        
ci->mlock.off tmp16;
    } else {
        
SAFE(read_int32(&ci->mlock.onf));
        
SAFE(read_int32(&ci->mlock.offf));
    }
    
SAFE(read_int32(&ci->mlock.limitf));
    
SAFE(read_string(&ci->mlock.keyf));
    
ci->mlock.on &= ~chanmode_reg;  /* check_modes() takes care of this */

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

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

    
ci->NULL;

    return 
ci;

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

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

/* Load extension data for a channel. */

static int load_one_channel_ext(DBTable *tabledbFILE *fint32 ver)
{
    
char *name;
    
ChannelInfo *ci NULL;
    
ChannelInfo dummy_ci;  /* for nonexistent channels */
    
int i;
    
int16 counttmp16;

    
SAFE(read_string(&namef));
    if (!
name)
        goto 
fail;
    
module_log_debug(2"loading channel extension %s"name);
    if (!(
ci get_channelinfo(name))) {
        
module_log("Extension data found for nonexistent channel `%s'"name);
        
ci = &dummy_ci;
        
memset(ci0sizeof(*ci));
    }
    
free(name);
    
name NULL;
    
SAFE(read_int16(&tmp16f));  /* was memomax */
    
if (ver >= 14) {
        if (
ver >= 23) {
            
SAFE(read_int16(&countf));
            if (
count != ci->akick_count && ci != &dummy_ci) {
                
module_log("warning: autokick mismatch in extension data"
                           " for channel %s (corrupt database?): expected"
                           " %d, got %d"
ci->nameci->akick_countcount);
            }
        } else {
            
count ci->akick_count;
        }
        for (
0counti++) {
            if (
ci->akick_count) {
                
SAFE(read_time(&ci->akick[i].setf));
                
SAFE(read_time(&ci->akick[i].lastusedf));
            } else {
                
time_t t;
                
SAFE(read_time(&tf));
                
SAFE(read_time(&tf));
            }
        }
    }
    if (
ver >= 16) {
        
SAFE(read_string(&ci->mlock.linkf));
        
SAFE(read_string(&ci->mlock.floodf));
    }
    if (
ver >= 25)
        
SAFE(read_int32(&ci->mlock.joindelayf));
    if (
ver >= 27) {
        
SAFE(read_int32(&ci->mlock.joinrate1f));
        
SAFE(read_int32(&ci->mlock.joinrate2f));
    }
    if (
ver >= 20) {
        
int16 lev;
        
SAFE(read_int16(&countf));
        if (
count) {
            
reset_levels(ci);
            for (
0counti++) {
                
SAFE(read_int16(&levf));
                if (
CA_SIZE)
                    
ci->levels[i] = lev;
            }
            if (
ver == 20) {
                if (
ci->levels[CA_AUTODEOP] == -10)
                    
ci->levels[CA_AUTODEOP] = -1;
                if (
ci->levels[CA_NOJOIN] == -20)
                    
ci->levels[CA_NOJOIN] = -100;
            }
        }
        
SAFE(read_int16(&countf));
        if (
count != ci->access_count && ci != &dummy_ci) {
            
module_log("warning: access count mismatch in extension data"
                       " for channel %s (corrupt database?): expected %d,"
                       " got %d"
ci->nameci->access_countcount);
        }
        for (
0counti++) {
            
SAFE(read_int16(&levf));
            if (
ci->access_count)
                
ci->access[i].level lev;
        }
    }
    if (
ci == &dummy_ci) {
        
free(ci->mlock.link);
        
free(ci->mlock.flood);
    } else {
        
put_channelinfo(ci);
    }
    return 
1;

  
fail:
    
module_log("Read error on %s"f->filename);
    if (
ci != &dummy_ci)
        
put_channelinfo(ci);
    return 
0;
}

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

/* Load version 5.1 extension data for a channel. */

static int load_one_channel_ext51(DBTable *tabledbFILE *fint32 ver)
{
    
char *name;
    
ChannelInfo *ci NULL;
    
ChannelInfo dummy_ci;  /* for nonexistent channels */
    
char *s;

    
SAFE(read_string(&namef));
    if (!
name)
        goto 
fail;
    
module_log_debug(2"loading channel extension (5.1) %s"name);
    if (!(
ci get_channelinfo(name))) {
        
module_log("5.1 extension data found for nonexistent channel `%s'",
                   
name);
        
ci = &dummy_ci;
        
memset(ci0sizeof(*ci));
        
init_password(&ci->founderpass);
    }
    
free(name);
    
name NULL;
    
SAFE(read_string(&sf));
    if (
s)
        
ci->mlock.on mode_string_to_flags(sMODE_CHANNEL|MODE_NOERROR);
    
free(s);
    
SAFE(read_string(&sf));
    if (
s)
        
ci->mlock.off mode_string_to_flags(sMODE_CHANNEL|MODE_NOERROR);
    
free(s);
    
free((char *)ci->founderpass.cipher);
    
SAFE(read_string((char **)&ci->founderpass.cipherf));
    if (
ci == &dummy_ci) {
        
clear_password(&ci->founderpass);
    } else {
        
put_channelinfo(ci);
    }
    return 
1;

  
fail:
    
module_log("Read error on %s"f->filename);
    if (
ci != &dummy_ci)
        
put_channelinfo(ci);
    return 
0;
}

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

static int load_chan_table(DBTable *table)
{
    
dbFILE *f;
    
int32 ver;
    
int ic;
    
ChannelInfo *ci;
    
int failed 0;

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

    
/* Load original data. */
    
for (0256 && !failedi++) {
        while ((
getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in %s"ChanDBName);
                
failed 1;
                break;
            }
            
ci load_one_channel(tablefver);
            if (
ci) {
                if (
strcmp(ci->name"#") == 0) {
                    
module_log("Deleting unsupported channel \"#\"");
                    
table->freerec(ci);
                } else if (!(
ci->flags CF_VERBOTEN) && !ci->founder) {
                    
/* Delete non-forbidden channels with no founder.  These
                     * can crop up if the nick and channel databases get out
                     * of sync and the founder's nick has disappeared.  Note
                     * that we ignore the successor here, but since this
                     * shouldn't happen normally anyway, no big deal.
                     */
                    
module_log("load channel database: Deleting founderless"
                               " channel %s"
ci->name);
                    
table->freerec(ci);
                } else {
                    
NickGroupInfo *ngi get_nickgroupinfo(ci->founder);
                    if (
ngi) {
                        
ARRAY_EXTEND(ngi->channels);
                        
strbcpy(ngi->channels[ngi->channels_count-1],ci->name);
                        
put_nickgroupinfo(ngi);
                    }
                    
table->insert(ci);
                }
            } else {
                
failed 1;
                break;
            }
        }
    }

    
/* Load extension data if present. */
    
if (!failed && read_int32(&verf) == 0) {
        if (
ver <= FILE_VERSION || ver LOCAL_VERSION_50) {
            
module_log("Invalid extension data version in %s"ChanDBName);
            
failed 1;
        }
        while (!
failed && (getc_db(f)) != 0) {
            if (
!= 1) {
                
module_log("Invalid format in %s extension data"ChanDBName);
                
failed 1;
            } else {
                
failed = !load_one_channel_ext(tablefver);
            }
        }
    }
    if (
ver 26) {
        
/* Reset all AUTODEOP/NOJOIN levels to the defaults (version 4.x
         * databases may have them set to non-default levels, and version 5
         * doesn't allow them to be changed) */
        
for (ci table->first(); cici table->next()) {
            if (
ci->levels) {
                
ci->levels[CA_AUTODEOP] = -1;
                
ci->levels[CA_NOJOIN] = -100;
            }
        }
    }
    
/* Clean out all empty (mask==NULL) autokick entries */
    
for (ci table->first(); cici table->next()) {
        
int i;
        
ARRAY_FOREACH (ici->akick) {
            if (!
ci->akick[i].mask) {
                
ARRAY_REMOVE(ci->akicki);
                
i--;
            }
        }
    }

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

    
/* Close database and return. */
    
close_db(f);
    return !
failed || forceload;
}

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

static int save_chan_table(DBTable *table)
{
    
dbFILE *f;
    
int i;
    
ChannelInfo *ci;
    
NickGroupInfo *ngi;
    static 
time_t lastwarn 0;

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

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

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

        
SAFE(write_int16(ci->access_countf));
        
ARRAY_FOREACH (ici->access) {
            if (
ci->access[i].nickgroup)
                
ngi get_ngi_id(ci->access[i].nickgroup);
            else
                
ngi NULL;
            
SAFE(write_int16(ngi != NULLf));
            if (
ngi) {
                
SAFE(write_int16(convert_new_level(ci->access[i].level), f));
                
SAFE(write_string(ngi_mainnick(ngi), f));
                
put_nickgroupinfo(ngi);
            
          }
        }

        
SAFE(write_int16(ci->akick_countf));
        
ARRAY_FOREACH (ici->akick) {
            
SAFE(write_int16((ci->akick[i].mask != NULL), f));  /* in_use */
            
if (ci->akick[i].mask) {
                
SAFE(write_int16(0f));  /* is_nick */
                
SAFE(write_string(ci->akick[i].maskf));
                
SAFE(write_string(ci->akick[i].reasonf));
                
SAFE(write_buffer(ci->akick[i].whof));
            }
        }

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

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

        
SAFE(write_string(ci->entry_messagef));

    } 
/* for (ci) */

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

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

    
SAFE(write_int32(LOCAL_VERSIONf));
    for (
ci table->first(); cici table->next()) {
        
SAFE(write_string(mode_flags_to_string(ci->mlock.on,MODE_CHANNEL),f));
        
SAFE(write_string(mode_flags_to_string(ci->mlock.off,MODE_CHANNEL),f));
        
SAFE(write_string(ci->founderpass.cipherf));
    }
    
SAFE(write_int8(0f));

    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"ChanDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"ChanDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

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

static int load_oper_table(DBTable *table)
{
    
dbFILE *f;
    
int32 ver;
    
int16 in;
    
DBField *field;
    
void *record;  /* pointer to OperServ's data structure */
    
int8 no_supass 1;
    
Password *supass NULL;

    if (!(
record table->first())) {
        
module_log("BUG: record missing from OperServ table!");
        return 
0;
    }
    if (
table->next()) {
        
module_log("BUG: too many records in OperServ table!");
        return 
0;
    }

    if (!(
my_open_db_r(OperDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

    
services_admins_count services_opers_count 0;
    
SAFE(read_int16(&nf));
    for (
0ni++) {
        
char *s;
        
SAFE(read_string(&sf));
        if (
&& MAX_SERVADMINS)
            
strbcpy(services_admins[services_admins_count++], s);
        
free(s);
    }
    
SAFE(read_int16(&nf));
    for (
0ni++) {
        
char *s;
        
SAFE(read_string(&sf));
        if (
&& MAX_SERVOPERS)
            
strbcpy(services_opers[services_opers_count++], s);
        
free(s);
    }
    if (
ver >= 7) {
        
int32 t---2;
        
SAFE(read_int32(&t---2f));
        for (
field table->fieldsfield->namefield++) {
            if (
strcmp(field->name"maxusercnt") == 0) {
                if (
field->type != DBTYPE_INT32) {
                    
module_log("BUG: oper.maxusercnt type is not INT32!");
                    goto 
fail;
                }
                *((
int32 *)DB_FIELDPTR(record,field)) = t---2;
                break;
            }
        }
        
SAFE(read_int32(&t---2f));
        for (
field table->fieldsfield->namefield++) {
            if (
strcmp(field->name"maxusertime") == 0) {
                if (
field->type != DBTYPE_TIME) {
                    
module_log("BUG: oper.maxusertime type is not TIME!");
                    goto 
fail;
                }
                *((
time_t *)DB_FIELDPTR(record,field)) = t---2;
                break;
            }
        }
    }
    if (
ver >= 9) {
        
SAFE(read_int8(&no_supassf));
        for (
field table->fieldsfield->namefield++) {
            if (
strcmp(field->name"no_supass") == 0) {
                if (
field->type != DBTYPE_INT8) {
                    
module_log("BUG: oper.no_supass type is not INT8!");
                    goto 
fail;
                }
                *((
int8 *)DB_FIELDPTR(record,field)) = no_supass;
                break;
            }
        }
        if (!
no_supass) {
            
Password tmppass;
            
init_password(&tmppass);
            
encrypt_password("a"1, &tmppass);
            
SAFE(read_buffer(tmppass.passwordf));
            for (
field table->fieldsfield->namefield++) {
                if (
strcmp(field->name"supass") == 0) {
                    if (
field->type != DBTYPE_PASSWORD) {
                        
module_log("BUG: oper.supass type is not PASSWORD!");
                        goto 
fail;
                    }
                    
supass = (Password *)DB_FIELDPTR(record,field);
                    
init_password(supass);
                    
copy_password(supass, &tmppass);
                    break;
                }
            }
        }
    }

    if (
read_int32(&verf) == 0) {
        if (
ver FIRST_VERSION_51 || ver LOCAL_VERSION) {
            
module_log("Invalid 5.1 extension data version in %s"OperDBName);
            
close_db(f);
            return 
0;
        }
        
SAFE(read_string((char **)&supass->cipherf));
    }

    
close_db(f);
    return 
1;

  
fail:
    
close_db(f);
    
module_log("Read error on %s"OperDBName);
    return 
0;
}

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

static int save_oper_table(DBTable *table)
{
    
dbFILE *f;
    
int16 i;
    
void *record;
    
DBField *field;
    static 
time_t lastwarn 0;
    
int8 no_supass 1;
    
Password *supass NULL;

    if (!(
record table->first())) {
        
module_log("BUG: record missing from OperServ table!");
        return 
0;
    }
    if (
table->next()) {
        
module_log("BUG: too many records in OperServ table!");
        return 
0;
    }

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

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

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

    for (
field table->fieldsfield->namefield++) {
        if (
strcmp(field->name"maxusercnt") == 0) {
            if (
field->type != DBTYPE_INT32) {
                
module_log("BUG: oper.maxusercnt type is not INT32!");
                goto 
fail;
            }
            
SAFE(write_int32(*((int32 *)DB_FIELDPTR(record,field)), f));
            break;
        }
    }
    for (
field table->fieldsfield->namefield++) {
        if (
strcmp(field->name"maxusertime") == 0) {
            if (
field->type != DBTYPE_TIME) {
                
module_log("BUG: oper.maxusertime type is not TIME!");
                goto 
fail;
            }
            
SAFE(write_int32((int32) *((time_t *)DB_FIELDPTR(record,field)),
                             
f));
            break;
        }
    }
    for (
field table->fieldsfield->namefield++) {
        if (
strcmp(field->name"no_supass") == 0) {
            if (
field->type != DBTYPE_INT8) {
                
module_log("BUG: oper.no_supass type is not INT8!");
                goto 
fail;
            }
            
no_supass = *((int8 *)DB_FIELDPTR(record,field));
            
SAFE(write_int8(no_supassf));
            break;
        }
    }
    if (!
no_supass) {
        for (
field table->fieldsfield->namefield++) {
            if (
strcmp(field->name"supass") == 0) {
                if (
field->type != DBTYPE_PASSWORD) {
                    
module_log("BUG: oper.supass type is not PASSWORD!");
                    goto 
fail;
                }
                
supass = (Password *)DB_FIELDPTR(record,field);
                
SAFE(write_buffer(supass->passwordf));
                break;
            }
        }
    }

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

    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"OperDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"OperDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/************************ News database handling *************************/
/*************************************************************************/

static int load_news_table(DBTable *table)
{
    
dbFILE *f;
    
int32 ver;
    
int i;
    
int16 count;

    if (!(
my_open_db_r(NewsDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;

#if CLEAN_COMPILE
    
count 0;
#endif
    
SAFE(read_int16(&countf));
    for (
0counti++) {
        
int32 t---2;
        
NewsItem *news table->newrec();
        
SAFE(read_int16(&news->typef));
        
SAFE(read_int32(&news->numf));
        
SAFE(read_string(&news->textf));
        
SAFE(read_buffer(news->whof));
        
SAFE(read_int32(&t---2f));
        
news->time t---2;
        
table->insert(news);
    }

    
close_db(f);
    return 
1;

  
fail:
    
close_db(f);
    
module_log("Read error on %s"NewsDBName);
    return 
0;
}

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

static int save_news_table(DBTable *table)
{
    
dbFILE *f;
    
int counti;
    
NewsItem *news;
    static 
time_t lastwarn 0;

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

    
count 0;
    for (
news table->first(); newsnews table->next())
        
count++;
    if (
count 32767)
        
count 32767;  // avoid overflow
    
write_int16((int16)countf);
    
0;
    for (
news table->first(), 0countnews table->next(), i++) {
        if (!
news) {
            
module_log("BUG: news item count changed while saving!");
            
wallops(NULL"Error saving %s!  Please check log file.",
                    
NewsDBName);
            
restore_db(f);
            return 
0;
        }
        
SAFE(write_int16(news->typef));
        
SAFE(write_int32(news->numf));
        
SAFE(write_string(news->textf));
        
SAFE(write_buffer(news->whof));
        
SAFE(write_int32(news->timef));
    }

    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"NewsDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"NewsDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

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

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

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

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

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

    if (!(
open_db(AutokillDBName"w"11)))
        return 
0;
    if (!
write_maskdata(akill_tableMD_AKILLAutokillDBNamef))
        return 
0;
    
SAFE(write_int8(1f));
    if (!
write_maskdata(exclude_tableMD_EXCLUDEAutokillDBNamef))
        return 
0;
    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"AutokillDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"AutokillDBName,
                
strerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/********************** Exception database handling **********************/
/*************************************************************************/

static int load_exception_table(DBTable *table)
{
    
dbFILE *f;
    
int32 ver;

    if (!(
my_open_db_r(ExceptionDBName, &ver)))
        return 
1;
    else if (
== OPENDB_ERROR)
        return 
0;
    if (!
read_maskdata(tableMD_EXCEPTIONExceptionDBNamef))
        return 
0;
    
close_db(f);
    return 
1;
}

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

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

    if (!(
open_db(ExceptionDBName"w"11)))
        return 
0;
    if (!
write_maskdata(tableMD_EXCEPTIONExceptionDBNamef))
        return 
0;
    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"ExceptionDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"ExceptionDBName,
                
strerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/*********************** S-line database handling ************************/
/*************************************************************************/

static int load_sline_table(DBTable *sgline_tableDBTable *sqline_table,
                            
DBTable *szline_table)
{
    
dbFILE *f;
    
int32 ver;

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

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

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

    if (!(
open_db(SlineDBName"w"11)))
        return 
0;
    if (!
write_maskdata(sgline_tableMD_SGLINESlineDBNamef))
        return 
0;
    if (!
write_maskdata(sqline_tableMD_SQLINESlineDBNamef))
        return 
0;
    if (!
write_maskdata(szline_tableMD_SZLINESlineDBNamef))
        return 
0;
    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"SlineDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"SlineDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

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

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

    
ss table->newrec();
    
SAFE(read_string(&ss->namef));
    
SAFE(read_int32(&t---2f));
    
ss->t_join t---2;
    
SAFE(read_int32(&t---2f));  /* t_quit */
    /* Avoid join>=quit staying true on load (which would indicate that the
     * server is online even before any server connections are processed) */
    
ss->t_quit time(NULL)-1;
    if (
ss->t_join >= ss->t_quit)
        
ss->t_join ss->t_quit-1;
    
SAFE(read_string(&ss->quit_messagef));
    return 
ss;

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

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

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

    
SAFE(read_string(&servernamef));
    if (!
servername)
        goto 
fail;
    
ss get_serverstats(servername);
    if (!
ss) {
        
module_log("Extension data found for nonexistent server `%s'",
                   
servername);
        
free(servername);
        return 
0;
    }
    
free(servername);
    
SAFE(read_time(&ss->t_joinf));
    
put_serverstats(ss);
    return 
1;

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

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

static int load_stat_servers_table(DBTable *table)
{
    
dbFILE *f;
    
int32 verinservers;
    
int16 tmp16;
    
int failed 0;
    
ServerStats *ss;

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

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

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

    
/* Close database and return. */
    
close_db(f);
    return !
failed || forceload;

  
fail:
    
close_db(f);
    
module_log("Read error on %s"StatDBName);
    return 
0;
}

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

static int save_stat_servers_table(DBTable *table)
{
    
dbFILE *f;
    
int32 countrealcounti;
    
ServerStats *ss;
    static 
time_t lastwarn 0;

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

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

    for (
ss table->first(), 0countss table->next(), i++) {
        if (!
ss) {
            
module_log("BUG: save_stat_servers_table(): ss NULL but i <"
                       " count!"
);
            
wallops(NULL"Error saving %s!  Please check log file.",
                    
StatDBName);
            
restore_db(f);
            return 
0;
        }
        
SAFE(write_string(ss->namef));
        
SAFE(write_int32(ss->t_joinf));
        
SAFE(write_int32(ss->t_quitf));
        
SAFE(write_string(ss->quit_messagef));
    }

    
SAFE(write_int32(LOCAL_VERSION_50f));
    if (
realcount count) {
        
SAFE(write_int32(realcount-countf));
        for (; 
realcountss table->next(), i++) {
            if (!
ss) {
                
module_log("BUG: save_stat_servers_table(): ss NULL but i <"
                           " realcount!"
);
                
wallops(NULL"Error saving %s!  Please check log file.",
                        
StatDBName);
                
restore_db(f);
                return 
0;
            }
            
SAFE(write_string(ss->namef));
            
SAFE(write_int32(ss->t_joinf));
            
SAFE(write_int32(ss->t_quitf));
            
SAFE(write_string(ss->quit_messagef));
        }
    } else {
        
SAFE(write_int32(0f));
    }
    for (
ss table->first(); ssss table->next()) {
        
SAFE(write_string(ss->namef));
        
SAFE(write_time(ss->t_joinf));
    }

    
SAFE(close_db(f));
    return 
1;

  
fail:
    
restore_db(f);
    
module_log_perror("Write error on %s"StatDBName);
    if (
time(NULL) - lastwarn WarningTimeout) {
        
wallops(NULL"Write error on %s: %s"StatDBNamestrerror(errno));
        
lastwarn time(NULL);
    }
    return 
0;
}

/*************************************************************************/
/*********************** Generic database handling ***********************/
/*************************************************************************/

/* Routines used for databases not part of the v4/v5.0 set */

#define INCLUDE_IN_VERSION4
#define standard_load_table load_generic_table
#define standard_save_table save_generic_table
#include "standard.c"
#undef INCLUDE_IN_VERSION4
#undef standard_load_table
#undef standard_save_table

/*************************************************************************/
/***************************** Module stuff ******************************/
/*************************************************************************/

ConfigDirective module_config[] = {
    { 
"AutokillDB",       { { CD_STRINGCF_DIRREQ, &AutokillDBName } } },
    { 
"ChanServDB",       { { CD_STRINGCF_DIRREQ, &ChanDBName } } },
    { 
"ExceptionDB",      { { CD_STRINGCF_DIRREQ, &ExceptionDBName } } },
    { 
"NewsDB",           { { CD_STRINGCF_DIRREQ, &NewsDBName } } },
    { 
"NickServDB",       { { CD_STRINGCF_DIRREQ, &NickDBName } } },
    { 
"OperServDB",       { { CD_STRINGCF_DIRREQ, &OperDBName } } },
    { 
"SlineDB",          { { CD_STRINGCF_DIRREQ, &SlineDBName } } },
    { 
"StatServDB",       { { CD_STRINGCF_DIRREQ, &StatDBName } } },
    { 
NULL }
};


static 
DBModule dbmodule_version4 = {
    .
load_table version4_load_table,
    .
save_table version4_save_table,
};

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

int init_module(void)
{
    if (!
init_extsyms(MODULE_NAME)) {
        
exit_module(0);
        return 
0;
    }

    if (!
register_dbmodule(&dbmodule_version4)) {
        
module_log("Unable to register module with database core");
        
exit_module(0);
        return 
0;
    }

    return 
1;
}

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

int exit_module(int shutdown)
{
    
unregister_dbmodule(&dbmodule_version4);
    
exit_extsyms();
    return 
1;
}

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

/*
 * Local variables:
 *   c-file-style: "stroustrup"
 *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
 *   indent-tabs-mode: nil
 * End:
 *
 * vim: expandtab shiftwidth=4:
 */ 


 
Alıntı ile Cevapla

IRCForumlari.NET Reklamlar
sohbet odaları eglen sohbet reklamver