From ae31e19f92e717919ac8e3db9039eb38d2b89aae Mon Sep 17 00:00:00 2001 From: in2 Date: Thu, 7 Mar 2002 15:13:44 +0000 Subject: Initial revision git-svn-id: http://opensvn.csie.org/pttbbs/pttbbs/trunk/pttbbs@1 63ad8ddf-47c3-0310-b6dd-a9e9d9715204 --- innbbsd/his.c | 474 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 innbbsd/his.c (limited to 'innbbsd/his.c') diff --git a/innbbsd/his.c b/innbbsd/his.c new file mode 100644 index 00000000..7fe48dc3 --- /dev/null +++ b/innbbsd/his.c @@ -0,0 +1,474 @@ +/* $Revision: 1.1 $ +** +** History file routines. +*/ +#include "innbbsconf.h" +#include "bbslib.h" +#include "his.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 + +hisincore(flag) +int flag; +{ + HISincore = flag; +} + +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 ; + time_t lasthist, now; + 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 (!isfile(newhistdirpath) || !isfile(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() +{ + FILE *hismaint ; + time_t lasthist, now; + 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() +{ + FILE *hismaint ; + time_t lasthist, now; + char maintbuff[4096]; + char *ptr; + + if (!isfile(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 (!isfile(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() +{ + 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); + } + } +} + + +/* +** 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() +{ + 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; + } +} + + +#ifdef HISset +/* +** File in the DBZ datum for a Message-ID, making sure not to copy any +** illegal characters. +*/ +STATIC void +HISsetkey(p, keyp) + register char *p; + datum *keyp; +{ + static BUFFER MessageID; + register char *dest; + register int i; + + /* Get space to hold the ID. */ + i = strlen(p); + if (MessageID.Data == NULL) { + MessageID.Data = NEW(char, i + 1); + MessageID.Size = i; + } + else if (MessageID.Size < i) { + RENEW(MessageID.Data, char, i + 1); + MessageID.Size = i; + } + + for (keyp->dptr = dest = MessageID.Data; *p; p++) + if (*p == HIS_FIELDSEP || *p == '\n') + *dest++ = HIS_BADCHAR; + else + *dest++ = *p; + *dest = '\0'; + + keyp->dsize = dest - MessageID.Data + 1; +} + +#endif +/* +** 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 %d\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. */ +} + +/* +** Have we already seen an article? +*/ +#ifdef HISh +BOOL +HIShavearticle(MessageID) + char *MessageID; +{ + datum key; + datum val; + + HISsetkey(MessageID, &key); + val = dbzfetch(key); + return val.dptr != NULL; +} +#endif + + +/* +** Turn a history filename entry from slashes to dots. It's a pity +** we have to do this. +*/ +STATIC void +HISslashify(p) + register char *p; +{ + register char *last; + + for (last = NULL; *p; p++) { + if (*p == '/') { + *p = '.'; + last = p; + } + else if (*p == ' ' && last != NULL) + *last = '/'; + } + if (last) + *last = '/'; +} + + +IOError(error) +char *error; +{ + fprintf(stderr,"%s\n",error); +} + +/*BOOL*/ +myHISwrite(key, remain) + datum *key; + char *remain; +{ + static char NOPATHS[] = ""; + 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; + char *paths; + long date; +{ + static char NOPATHS[] = ""; + 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; +} -- cgit v1.2.3