/*
* $Revision: 1.1 $ *
*
* History file routines.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include "cmbbs.h"
#include "innbbsconf.h"
#include "his.h"
#include "dbz.h"
#include "externs.h"
#define STATIC static
/* STATIC char HIShistpath[] = _PATH_HISTORY; */
STATIC FILE *HISwritefp;
STATIC int HISreadfd;
STATIC int HISdirty;
STATIC int HISincore = XINDEX_DBZINCORE;
STATIC char *LogName = "xindexchan";
#ifndef EXPIREDAYS
#define EXPIREDAYS 4
#endif
#ifndef DEFAULT_HIST_SIZE
#define DEFAULT_HIST_SIZE 100000
#endif
void
hisincore(flag)
int flag;
{
HISincore = flag;
}
void
makedbz(histpath, entry)
char *histpath;
long entry;
{
long size;
size = dbzsize(entry);
dbzfresh(histpath, size, '\t', 0, 1);
dbmclose();
}
void HISsetup();
void HISclose();
void
mkhistory(srchist)
char *srchist;
{
FILE *hismaint;
char maintbuff[256];
char *ptr;
hismaint = fopen(srchist, "r");
if (hismaint == NULL) {
return;
} {
char newhistpath[1024];
char newhistdirpath[1024];
char newhistpagpath[1024];
sprintf(newhistpath, "%s.n", srchist);
sprintf(newhistdirpath, "%s.n.dir", srchist);
sprintf(newhistpagpath, "%s.n.pag", srchist);
if (!dashf(newhistdirpath) || !dashf(newhistpagpath)) {
makedbz(newhistpath, DEFAULT_HIST_SIZE);
}
myHISsetup(newhistpath);
while (fgets(maintbuff, sizeof(maintbuff), hismaint) != NULL) {
datum key;
ptr = (char *)strchr(maintbuff, '\t');
if (ptr != NULL) {
*ptr = '\0';
ptr++;
}
key.dptr = maintbuff;
key.dsize = strlen(maintbuff);
myHISwrite(&key, ptr);
}
(void)HISclose();
/*
* rename(newhistpath, srchist); rename(newhistdirpath,
* fileglue("%s.dir", srchist)); rename(newhistpagpath,
* fileglue("%s.pag", srchist));
*/
}
fclose(hismaint);
}
time_t
gethisinfo(void)
{
FILE *hismaint;
time_t lasthist;
char maintbuff[4096];
char *ptr;
hismaint = fopen(HISTORY, "r");
if (hismaint == NULL) {
return 0;
}
fgets(maintbuff, sizeof(maintbuff), hismaint);
fclose(hismaint);
ptr = (char *)strchr(maintbuff, '\t');
if (ptr != NULL) {
ptr++;
lasthist = atol(ptr);
return lasthist;
}
return 0;
}
void
HISmaint(void)
{
FILE *hismaint;
time_t lasthist, now;
char maintbuff[4096];
char *ptr;
if (!dashf(HISTORY)) {
makedbz(HISTORY, DEFAULT_HIST_SIZE);
}
hismaint = fopen(HISTORY, "r");
if (hismaint == NULL) {
return;
}
fgets(maintbuff, sizeof(maintbuff), hismaint);
ptr = (char *)strchr(maintbuff, '\t');
if (ptr != NULL) {
ptr++;
lasthist = atol(ptr);
time(&now);
if (lasthist + 86400 * Expiredays * 2 < now) {
char newhistpath[1024];
char newhistdirpath[1024];
char newhistpagpath[1024];
(void)HISclose();
sprintf(newhistpath, "%s.n", HISTORY);
sprintf(newhistdirpath, "%s.n.dir", HISTORY);
sprintf(newhistpagpath, "%s.n.pag", HISTORY);
if (!dashf(newhistdirpath)) {
makedbz(newhistpath, DEFAULT_HIST_SIZE);
}
myHISsetup(newhistpath);
while (fgets(maintbuff, sizeof(maintbuff), hismaint) != NULL) {
datum key;
ptr = (char *)strchr(maintbuff, '\t');
if (ptr != NULL) {
*ptr = '\0';
ptr++;
lasthist = atol(ptr);
} else {
continue;
}
if (lasthist + 99600 * Expiredays < now)
continue;
key.dptr = maintbuff;
key.dsize = strlen(maintbuff);
myHISwrite(&key, ptr);
}
(void)HISclose();
rename(HISTORY, (char *)fileglue("%s.o", HISTORY));
rename(newhistpath, HISTORY);
rename(newhistdirpath, (char *)fileglue("%s.dir", HISTORY));
rename(newhistpagpath, (char *)fileglue("%s.pag", HISTORY));
(void)HISsetup();
}
}
fclose(hismaint);
}
/*
* * Set up the history files.
*/
void
HISsetup(void)
{
myHISsetup(HISTORY);
}
int
myHISsetup(histpath)
char *histpath;
{
if (HISwritefp == NULL) {
/* Open the history file for appending formatted I/O. */
if ((HISwritefp = fopen(histpath, "a")) == NULL) {
syslog(LOG_CRIT, "%s cant fopen %s %m", LogName, histpath);
exit(1);
}
CloseOnExec((int)fileno(HISwritefp), TRUE);
/* Open the history file for reading. */
if ((HISreadfd = open(histpath, O_RDONLY)) < 0) {
syslog(LOG_CRIT, "%s cant open %s %m", LogName, histpath);
exit(1);
}
CloseOnExec(HISreadfd, TRUE);
/* Open the DBZ file. */
/* (void)dbzincore(HISincore); */
(void)dbzincore(HISincore);
(void)dbzwritethrough(1);
if (dbminit(histpath) < 0) {
syslog(LOG_CRIT, "%s cant dbminit %s %m", histpath, LogName);
exit(1);
}
}
return 0;
}
/*
* * Synchronize the in-core history file (flush it).
*/
void
HISsync()
{
if (HISdirty) {
if (dbzsync()) {
syslog(LOG_CRIT, "%s cant dbzsync %m", LogName);
exit(1);
}
HISdirty = 0;
}
}
/*
* * Close the history files.
*/
void
HISclose(void)
{
if (HISwritefp != NULL) {
/*
* Since dbmclose calls dbzsync we could replace this line with
* "HISdirty = 0;". Oh well, it keeps the abstraction clean.
*/
HISsync();
if (dbmclose() < 0)
syslog(LOG_ERR, "%s cant dbmclose %m", LogName);
if (fclose(HISwritefp) == EOF)
syslog(LOG_ERR, "%s cant fclose history %m", LogName);
HISwritefp = NULL;
if (close(HISreadfd) < 0)
syslog(LOG_ERR, "%s cant close history %m", LogName);
HISreadfd = -1;
}
}
/*
* * Get the list of files under which a Message-ID is stored.
*/
char *
HISfilesfor(key, output)
datum *key;
datum *output;
{
char *dest;
datum val;
long offset;
register char *p;
register int i;
int Used;
/* Get the seek value into the history file. */
val = dbzfetch(*key);
if (val.dptr == NULL || val.dsize != sizeof offset) {
/* printf("fail here val.dptr %d\n",val.dptr); */
return NULL;
}
/* Get space. */
if (output->dptr == NULL) {
printf("fail here output->dptr null\n");
return NULL;
}
/* Copy the value to an aligned spot. */
for (p = val.dptr, dest = (char *)&offset, i = sizeof offset; --i >= 0;)
*dest++ = *p++;
if (lseek(HISreadfd, offset, SEEK_SET) == -1) {
printf("fail here lseek %ld\n", offset);
return NULL;
}
/* Read the text until \n or EOF. */
for (output->dsize = 0, Used = 0;;) {
i = read(HISreadfd,
&output->dptr[output->dsize], LEN - 1);
if (i <= 0) {
printf("fail here i %d\n", i);
return NULL;
}
Used += i;
output->dptr[Used] = '\0';
if ((p = (char *)strchr(output->dptr, '\n')) != NULL) {
*p = '\0';
break;
}
}
/* Move past the first two fields -- Message-ID and date info. */
if ((p = (char *)strchr(output->dptr, HIS_FIELDSEP)) == NULL) {
printf("fail here no HIS_FILE\n");
return NULL;
}
return p + 1;
/*
* if ((p = (char*)strchr(p + 1, HIS_FIELDSEP)) == NULL) return NULL;
*/
/* Translate newsgroup separators to slashes, return the fieldstart. */
}
void
IOError(error)
char *error;
{
fprintf(stderr, "%s\n", error);
}
/* BOOL */
int
myHISwrite(key, remain)
datum *key;
char *remain;
{
long offset;
datum val;
int i;
val = dbzfetch(*key);
if (val.dptr != NULL) {
return FALSE;
}
flock(fileno(HISwritefp), LOCK_EX);
offset = ftell(HISwritefp);
i = fprintf(HISwritefp, "%s%c%s",
key->dptr, HIS_FIELDSEP, remain);
if (i == EOF || fflush(HISwritefp) == EOF) {
/* The history line is now an orphan... */
IOError("history");
syslog(LOG_ERR, "%s cant write history %m", LogName);
flock(fileno(HISwritefp), LOCK_UN);
return FALSE;
}
/* Set up the database values and write them. */
val.dptr = (char *)&offset;
val.dsize = sizeof offset;
if (dbzstore(*key, val) < 0) {
IOError("my history database");
syslog(LOG_ERR, "%s cant dbzstore %m", LogName);
flock(fileno(HISwritefp), LOCK_UN);
return FALSE;
}
if (++HISdirty >= ICD_SYNC_COUNT)
HISsync();
flock(fileno(HISwritefp), LOCK_UN);
return TRUE;
}
/*
* * Write a history entry.
*/
BOOL
HISwrite(key, date, paths)
datum *key;
long date;
char *paths;
{
long offset;
datum val;
int i;
flock(fileno(HISwritefp), LOCK_EX);
offset = ftell(HISwritefp);
i = fprintf(HISwritefp, "%s%c%ld%c%s\n",
key->dptr, HIS_FIELDSEP, (long)date, HIS_FIELDSEP,
paths);
if (i == EOF || fflush(HISwritefp) == EOF) {
/* The history line is now an orphan... */
IOError("history");
syslog(LOG_ERR, "%s cant write history %m", LogName);
flock(fileno(HISwritefp), LOCK_UN);
return FALSE;
}
/* Set up the database values and write them. */
val.dptr = (char *)&offset;
val.dsize = sizeof offset;
if (dbzstore(*key, val) < 0) {
IOError("history database");
syslog(LOG_ERR, "%s cant dbzstore %m", LogName);
flock(fileno(HISwritefp), LOCK_UN);
return FALSE;
}
if (++HISdirty >= ICD_SYNC_COUNT)
HISsync();
flock(fileno(HISwritefp), LOCK_UN);
return TRUE;
}