summaryrefslogtreecommitdiffstats
path: root/innbbsd/his.c
diff options
context:
space:
mode:
Diffstat (limited to 'innbbsd/his.c')
-rw-r--r--innbbsd/his.c474
1 files changed, 474 insertions, 0 deletions
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;
+}