/*
* file_c.c -- File cache management
*/
#include <dirent.h>
#include "copyright.h"
#include "config.h"
#include "config.h"
#include "interface.h"
#include "mudconf.h"
#include "command.h"
#include "file_c.h"
#include "alloc.h"
#include "externs.h"
typedef struct filecache_hdr FCACHE;
typedef struct filecache_block_hdr FBLKHDR;
typedef struct filecache_block FBLOCK;
struct filecache_hdr {
char *filename;
FBLOCK *fileblock;
const char *desc;
};
struct filecache_block {
struct filecache_block_hdr {
struct filecache_block *nxt;
int nchars;
} hdr;
char data[MBUF_SIZE - sizeof(FBLKHDR)];
};
#define FBLOCK_SIZE (MBUF_SIZE - sizeof(FBLKHDR))
FCACHE fcache[] = {
{mudconf.conn_file, NULL, "Conn"}
,
{mudconf.site_file, NULL, "Conn/Badsite"}
,
{mudconf.down_file, NULL, "Conn/Down"}
,
{mudconf.full_file, NULL, "Conn/Full"}
,
{mudconf.guest_file, NULL, "Conn/Guest"}
,
{mudconf.creg_file, NULL, "Conn/Reg"}
,
{mudconf.crea_file, NULL, "Crea/Newuser"}
,
{mudconf.regf_file, NULL, "Crea/RegFaill"}
,
{mudconf.motd_file, NULL, "Motd"}
,
{mudconf.wizmotd_file, NULL, "Wizmotd"}
,
{mudconf.quit_file, NULL, "Quit"}
,
{NULL, NULL, NULL}
};
NAMETAB list_files[] = {
{(char *) "badsite_connect", 1, CA_WIZARD, FC_CONN_SITE},
{(char *) "connect", 2, CA_WIZARD, FC_CONN},
{(char *) "create_register", 2, CA_WIZARD, FC_CREA_REG},
{(char *) "down", 1, CA_WIZARD, FC_CONN_DOWN},
{(char *) "full", 1, CA_WIZARD, FC_CONN_FULL},
{(char *) "guest_motd", 1, CA_WIZARD, FC_CONN_GUEST},
{(char *) "motd", 1, CA_WIZARD, FC_MOTD},
{(char *) "newuser", 1, CA_WIZARD, FC_CREA_NEW},
{(char *) "quit", 1, CA_WIZARD, FC_QUIT},
{(char *) "register_connect", 1, CA_WIZARD, FC_CONN_REG},
{(char *) "wizard_motd", 1, CA_WIZARD, FC_WIZMOTD},
{NULL, 0, 0, 0}
};
#define MAX_CONN 100
int fcache_conn_c = 0;
FCACHE fcache_conn[MAX_CONN];
void do_list_file(dbref player, dbref cause, int extra, char *arg)
{
int flagvalue;
flagvalue = search_nametab(player, list_files, arg);
if(flagvalue < 0) {
display_nametab(player, list_files,
(char *) "Unknown file. Use one of:", 1);
return;
}
fcache_send(player, flagvalue);
}
static FBLOCK *fcache_fill(FBLOCK * fp, char ch)
{
FBLOCK *tfp;
if(fp->hdr.nchars >= (MBUF_SIZE - sizeof(FBLKHDR))) {
/*
* We filled the current buffer. Go get a new one.
*/
tfp = fp;
fp = (FBLOCK *) alloc_mbuf("fcache_fill");
fp->hdr.nxt = NULL;
fp->hdr.nchars = 0;
tfp->hdr.nxt = fp;
}
fp->data[fp->hdr.nchars++] = ch;
return fp;
}
static int fcache_read(FBLOCK ** cp, char *filename)
{
int n, nmax, tchars, fd;
char *buff;
FBLOCK *fp, *tfp;
/*
* Free a prior buffer chain
*/
fp = *cp;
while (fp != NULL) {
tfp = fp->hdr.nxt;
free_mbuf(fp);
fp = tfp;
}
*cp = NULL;
/*
* Read the text file into a new chain
*/
if((fd = open(filename, O_RDONLY)) == -1) {
/*
* Failure: log the event
*/
log_error(LOG_PROBLEMS, "FIL", "OPEN", "Couldn't open file '%s'.",
filename);
return -1;
}
buff = alloc_lbuf("fcache_read.temp");
/*
* Set up the initial cache buffer to make things easier
*/
fp = (FBLOCK *) alloc_mbuf("fcache_read.first");
fp->hdr.nxt = NULL;
fp->hdr.nchars = 0;
*cp = fp;
tchars = 0;
/*
* Process the file, one lbuf at a time
*/
nmax = read(fd, buff, LBUF_SIZE);
while (nmax > 0) {
for(n = 0; n < nmax; n++) {
switch (buff[n]) {
case '\n':
fp = fcache_fill(fp, '\r');
fp = fcache_fill(fp, '\n');
tchars += 2;
case '\0':
case '\r':
break;
default:
fp = fcache_fill(fp, buff[n]);
tchars++;
}
}
nmax = read(fd, buff, LBUF_SIZE);
}
free_lbuf(buff);
close(fd);
/*
* If we didn't read anything in, toss the initial buffer
*/
if(fp->hdr.nchars == 0) {
*cp = NULL;
free_mbuf(fp);
}
return tchars;
}
void fcache_read_dir(char *dir, FCACHE foo[], int *cnt, int max)
{
DIR *d;
struct dirent *de;
char buf[LBUF_SIZE];
bzero(&foo[0], sizeof(FCACHE) * max);
if(!(d = opendir(dir)))
return;
for(*cnt = 0; *cnt < max;) {
if(!(de = readdir(d)))
break;
if(de->d_name[0] == '.')
continue;
if(!strstr(de->d_name, ".txt"))
continue;
sprintf(buf, "%s/%s", dir, de->d_name);
fcache_read(&(foo[*cnt].fileblock), buf);
(*cnt)++;
}
closedir(d);
}
void fcache_rawdump(int fd, int num)
{
int cnt, remaining;
char *start;
FBLOCK *fp;
if((num < 0) || (num > FC_LAST))
return;
fp = fcache[num].fileblock;
while (fp != NULL) {
start = fp->data;
remaining = fp->hdr.nchars;
while (remaining > 0) {
cnt = WRITE(fd, start, remaining);
if(cnt < 0)
return;
remaining -= cnt;
start += cnt;
}
fp = fp->hdr.nxt;
}
return;
}
void fcache_dumpbase(DESC * d, FCACHE fc[], int num)
{
FBLOCK *fp;
fp = fc[num].fileblock;
while (fp != NULL) {
queue_write(d, fp->data, fp->hdr.nchars);
fp = fp->hdr.nxt;
}
}
void fcache_dump(DESC * d, int num)
{
if((num < 0) || (num > FC_LAST))
return;
fcache_dumpbase(d, fcache, num);
}
void fcache_dump_conn(DESC * d, int num)
{
fcache_dumpbase(d, fcache_conn, num);
}
void fcache_send(dbref player, int num)
{
DESC *d;
DESC_ITER_PLAYER(player, d) {
fcache_dump(d, num);
}
}
void fcache_load(dbref player)
{
FCACHE *fp;
char *buff, *bufc, *sbuf;
int i;
buff = bufc = alloc_lbuf("fcache_load.lbuf");
sbuf = alloc_sbuf("fcache_load.sbuf");
for(fp = fcache; fp->filename; fp++) {
i = fcache_read(&fp->fileblock, fp->filename);
if((player != NOTHING) && !Quiet(player)) {
sprintf(sbuf, "%d", i);
if(fp == fcache)
safe_str((char *) "File sizes: ", buff, &bufc);
else
safe_str((char *) " ", buff, &bufc);
safe_str((char *) fp->desc, buff, &bufc);
safe_str((char *) "...", buff, &bufc);
safe_str(sbuf, buff, &bufc);
}
}
*bufc = '\0';
if(*mudconf.conn_dir)
fcache_read_dir(mudconf.conn_dir, fcache_conn, &fcache_conn_c,
MAX_CONN);
if((player != NOTHING) && !Quiet(player)) {
notify(player, buff);
}
free_lbuf(buff);
free_sbuf(sbuf);
}
void fcache_init(void)
{
FCACHE *fp;
for(fp = fcache; fp->filename; fp++) {
fp->fileblock = NULL;
}
fcache_load(NOTHING);
}