/*
** vn news reader.
**
** stat.c - stat and log file collection
**
** see copyright disclaimer / history in vn.c source file
*/
#include <stdio.h>
#include <sys/types.h>
#ifdef SYSV
#include <fcntl.h>
#endif

#ifndef	MINIX
#ifndef	MSDOS
#ifndef	amiga
/* Minix doesn't have sys/file.h for some reason */
#include <sys/file.h>
#endif
#endif
#endif

#include <sys/stat.h>
#include <pwd.h>
#include "config.h"
#include "node.h"

extern NODE *hashfind();
extern char *strtok();
extern int Ncount;
extern NODE **Newsorder;

#ifdef VNLOGFILE
static char Start[80];
#endif

stat_start()
{
#ifdef VNLOGFILE
	char *ctime();
	long now;

	time(&now);
	strcpy(Start,ctime(&now));
#endif
}

/*
** flag = 0, "NO NEWS" type session.
**      = 1, regular session.
**	= -1, aborted session
**
** CAUTION: routine CALLED from within printex() - do NOT
** call printex().  Simply do message to stderr on fail.
*/
stat_end(flag)
int flag;
{
	NODE *nd;
	char *nl,*index();
	char *how;
	struct passwd *ptr, *getpwuid();
	struct stat buf;
	long now;
	char bufr[81];
	char name[60];
	FILE *fp;
	int fd;
	long chk, rd, pg;
	int i;

#ifdef VNLOGFILE
	if (stat(VNLOGFILE,&buf) == 0 && (fp = fopen(VNLOGFILE,"a")) != NULL)
	{
		time(&now);
		strcpy(bufr,ctime(&now));
		if ((nl = index(bufr,'\n')) != NULL)
			*nl = '\0';
		if ((nl = index(Start,'\n')) != NULL)
			*nl = '\0';
		if (flag == 0)
			how = "NO NEWS";
		else
		{
			if (flag > 0)
				how = "OK";
			else
				how = "ABORTED";
		}
		ptr = getpwuid (getuid());
		fprintf(fp, "%s\t%s - %s %s\n", ptr->pw_name, Start, bufr, how);
		fclose (fp);
	}
#endif

#ifdef VNSTATFILE
	/*
	** Stat file is done with a fixed record size, and maintaining the
	** existing record order exactly so that concurrent users will do
	** the least damage.  If two users actually read & update a single
	** record simultaneously, we should just lose one user's counts.
	** Short of implementing a locking scheme, we probably won't do
	** much better.  Disadvantages are that deleted newsgroups never
	** get cleaned out, order is set by the first user whose
	** statistics are collected, it will break if anyone modifies it,
	** and the file is a bit larger than it needs to be.
	**
	** record format:
	**
	** CCCCCC PPPPPP RRRRRR newsgroup name ....  \n
	** ^      ^      ^      ^                    ^
	** 0      7      14     21              char 79
	**
	** CCCCCC - count of sessions searching group
	** PPPPPP - count of sessions actually finding pages for group
	** RRRRRR - count of sessions actually accessing articles in group
	*/
	if ((fd = open(VNSTATFILE,O_RDWR)) > 0)
	{
		bufr[80] = '\0';

		/*
		** read a record, find the newsgroup, update counts.
		** If changed, seek back & overwrite.  By using fixed
		** length records, we should only lose something on
		** concurrent writes of the same record, and by writing
		** the ENTIRE record, we keep it consistent
		*/
		while ((i = read(fd,bufr,80)) == 80 && bufr[79] == '\n')
		{
			chk = atoi(bufr);
			pg = atoi(bufr+7);
			rd = atoi(bufr+14);
			strcpy(name,bufr+21);
			nl = strtok(name," \n");
			if (nl == NULL || (nd = hashfind(nl)) == NULL)
				continue;
			nd->flags |= FLG_STAT;
			if ((nd->flags & (FLG_SEARCH|FLG_ACC|FLG_PAGE)) == 0)
				continue;
			if ((nd->flags & FLG_SEARCH) != 0)
				++chk;
			if ((nd->flags & FLG_PAGE) != 0)
				++pg;
			if ((nd->flags & FLG_ACC) != 0)
				++rd;
			if (chk > 999999L)
				chk = 999999L;
			if (pg > 999999L)
				pg = 999999L;
			if (rd > 999999L)
				rd = 999999L;
			sprintf(bufr,"%6ld",chk);
			bufr[6] = ' ';
			sprintf(bufr+7,"%6ld",pg);
			bufr[13] = ' ';
			sprintf(bufr+14,"%6ld",rd);
			bufr[20] = ' ';
			lseek(fd,-80L,1);
			write(fd,bufr,80);
		}

		/* format screwed up ? */
		if (i != 0)
		{
			lseek(fd,(long) -i,1);
			fprintf(stderr,"bad data in %s\n",VNSTATFILE);
		}

		/* may have aborted during vns_news() */
		if (Newsorder == NULL)
			Ncount = 0;

		/* now append any groups not in file yet */
		for (i = 0; i < Ncount; ++i)
		{
			nd = Newsorder[i];
			if ((nd->flags & FLG_STAT) != 0)
				continue;
			chk = rd = pg = 0;
			if ((nd->flags & FLG_SEARCH) != 0)
				chk = 1;
			if ((nd->flags & FLG_PAGE) != 0)
				pg = 1;
			if ((nd->flags & FLG_ACC) != 0)
				rd = 1;
			sprintf(bufr,"%6ld %6ld %6ld %-58s\n",
					chk, pg, rd, nd->nd_name);
			write(fd,bufr,80);
		}
		close(fd);
	}
#endif
}
