/*
  ConfTop V1.0 for DayDream BBS
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <proto/dddoor.h>
#include <libraries/dddoor.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <daydream.h>
#include <exec/memory.h>
#include <dos.h>
#include <dos/datetime.h>
#include <dos/dostags.h>

long __stack=30000;

struct ConfTopData {
	ULONG   ULBytes;
	UWORD	ULFiles;
	ULONG	FirstC;
};

struct ConfTopDates {
	ULONG   ctd_Start;
	ULONG   ctd_LastWS;
	ULONG	ctd_CurrWS;
};

void AddData(char *, int, ULONG, ULONG);
char * ExamineCfg( char *, char *);
int get_file_size (char *);
void GenTop(char *file, ULONG, ULONG, ULONG);
char * StyleNum(char *bufferi, ULONG num);
void CpyToLAINA(char *src, char *dest);
void CpyToEOL(char *src, char *dest);
void CpyToHIPSU(char *src, char *dest);

char * CfgMem =0;
struct	Library	*DDBase;
struct	DIFace	*d;
struct	DDPointers *Pointers;
int ConfigSize=0;
int maxlines=15;

char Header[2000];
char Line[500];
char Tail[2000];

void CloseMe(void);

struct FileInfoBlock *FBlock = NULL;

struct ConfTopDates ctdates;

char BUFFER[2048];
char BUFFER2[2048];

struct DayDream_User *UserBase = 0;
int UBSize=0;

#define enddate(a) ((6-(a-1)%7)+a)

int main(int argc, char *argv[])
{
	BPTR CfgHandle;
	char cmdline[512];
	int i;
	int goon=1;
	BPTR ULHandle;
	int ULSize;
	struct DateStamp stamp;
	char *p;

	DateStamp(&stamp);

	DDBase=(struct Library *)OpenLibrary("dreamdoor.library",1);
	if(DDBase==NULL) {
		PutStr("Needs DreamDoor.library V1.00+ to run\n");
		exit(10);
	}
	d=InitDoor(argv[1]);		/* Establish link with DD */

	if(d==NULL) {
		PutStr("Hey Asswipe, this program requires DayDream BBS!\n");
		CloseLibrary(DDBase);
	        exit(10);
        }

	Pointers = AllocMem(sizeof(struct DDPointers),MEMF_PUBLIC|MEMF_CLEAR);
	InquirePointers(d,Pointers);
	strcpy(cmdline,Pointers->dp_DoorParams);

	atexit(CloseMe);

	if (Pointers->dp_CurrConf->CONF_FILEAREAS==0) {
		SendString(d,"[37mNo files in this conference!\n\n");
		exit(0);
	}

	if (!(CfgHandle=Open("ENV:DREAMUTILS",MODE_OLDFILE))) {
		SendString(d,"[37mCan't open ENV:DREAMUTILS!\n\n");
		exit(0);
	}

	i=Read(CfgHandle,BUFFER,300);
	Close(CfgHandle);
	BUFFER[i]=0;
	strcat(BUFFER,"DD-ConfTop.CFG");

	FBlock=AllocDosObject(DOS_FIB,0);

	if (!(CfgHandle=Lock(BUFFER,ACCESS_READ))) {
		SendString(d,"[37mCan't open configfile!\n\n");
		exit(0);
	}
	
	Examine(CfgHandle,FBlock);
	ConfigSize = FBlock->fib_Size;

	UnLock(CfgHandle);

	if (!(CfgMem=AllocMem(ConfigSize+2,MEMF_CLEAR))) {
		SendString(d,"[37mCan't allocate memory for configfile!\n\n");
		exit(0);
	}

	CfgHandle=Open(BUFFER,MODE_OLDFILE);
	Read(CfgHandle,CfgMem,ConfigSize);
	Close(CfgHandle);

	if (p=ExamineCfg(CfgMem,"HEADER \"")) CpyToLAINA(p,Header);
		else strcpy(Header,"\n[44;33m No | Name                  | Organization             | Upload bytes | Files[0m\n\n");

	if (p=ExamineCfg(CfgMem,"LINE \"")) CpyToLAINA(p,Line);
		else strcpy(Line,"[0m %02ld.  [33m%-23.23s [32m%-25.25s [36m%15.15s [35m%5.5s\n");

	if (p=ExamineCfg(CfgMem,"TAIL \"")) CpyToLAINA(p,Tail);
		else strcpy(Tail,"\n[44;33m UP: %15.15s kbytes / %7.7s files | DD-ConfTop v1.0   Hydra/insane [0m\n[44;33m Start Date : %s                                 End Date : %s [0m\n\n");

	if (p=ExamineCfg(CfgMem,"MAXLINES ")) { 
		CpyToEOL(p,BUFFER);
		maxlines=atoi(BUFFER);
	}

	sprintf(BUFFER,"%sData/DD-ConfTopDates.DAT",Pointers->dp_CurrConf->CONF_PATH);
	if (ULHandle=Open(BUFFER,MODE_OLDFILE)) {
		Read(ULHandle,&ctdates,sizeof(struct ConfTopDates));
		Close(ULHandle);
	} else {
		ctdates.ctd_Start=stamp.ds_Days;
		ctdates.ctd_CurrWS=stamp.ds_Days;
	}

	sprintf(BUFFER,"%sData/DD-ConfTopAll.DAT",Pointers->dp_CurrConf->CONF_PATH);

	if (argc==2) {

		if (!(ULHandle=Lock(cmdline,ACCESS_READ))) {
			SendString(d,"[37mCan't open uploaded file!\n\n");
			exit(0);
		}
	
		Examine(ULHandle,FBlock);
		ULSize = FBlock->fib_Size;
		UnLock(ULHandle);
	
		AddData(BUFFER,Pointers->dp_CurrUser->user_account_id,ULSize,Pointers->dp_CurrUser->user_firstcall);

		if (enddate(ctdates.ctd_CurrWS) < stamp.ds_Days) {

			UBSize=get_file_size("DayDream:Data/UserBase.DAT");

			if (UserBase=AllocMem(UBSize,0)) {
				ULHandle=Open("DayDream:Data/UserBase.DAT",MODE_OLDFILE);
				Read(ULHandle,UserBase,UBSize);
		  		Close(ULHandle);

				sprintf(BUFFER,"%sData/DD-ConfTopThisWeek.DAT",Pointers->dp_CurrConf->CONF_PATH);
				GenTop(BUFFER,ctdates.ctd_CurrWS,enddate(ctdates.ctd_CurrWS),1);
				sprintf(BUFFER,"%sData/DD-ConfTopLastWeek.DAT",Pointers->dp_CurrConf->CONF_PATH);
				sprintf(BUFFER2,"%sData/DD-ConfTopThisWeek.DAT",Pointers->dp_CurrConf->CONF_PATH);
				DeleteFile(BUFFER);
				Rename(BUFFER2,BUFFER);
				ctdates.ctd_LastWS=ctdates.ctd_CurrWS;
				ctdates.ctd_CurrWS=stamp.ds_Days;
			}
		}
		sprintf(BUFFER,"%sData/DD-ConfTopThisWeek.DAT",Pointers->dp_CurrConf->CONF_PATH);
		AddData(BUFFER,Pointers->dp_CurrUser->user_account_id,ULSize,Pointers->dp_CurrUser->user_firstcall);

	} else {
		UBSize=get_file_size("DayDream:Data/UserBase.DAT");

		UserBase=AllocMem(UBSize,0);
		ULHandle=Open("DayDream:Data/UserBase.DAT",MODE_OLDFILE);
		Read(ULHandle,UserBase,UBSize);
  		Close(ULHandle);

		if (!(stricmp("last",argv[2]))) {
			sprintf(BUFFER,"%sData/DD-ConfTopLastWeek.DAT",Pointers->dp_CurrConf->CONF_PATH);
			GenTop(BUFFER,ctdates.ctd_LastWS,enddate(ctdates.ctd_LastWS),0);
		}

		if (!(stricmp("this",argv[2]))) {
			sprintf(BUFFER,"%sData/DD-ConfTopThisWeek.DAT",Pointers->dp_CurrConf->CONF_PATH);
			GenTop(BUFFER,ctdates.ctd_CurrWS,enddate(ctdates.ctd_CurrWS),0);
		}

		if (!(stricmp("all",argv[2]))) {
			GenTop(BUFFER,ctdates.ctd_Start,stamp.ds_Days,0);
		}
	}
	sprintf(BUFFER,"%sData/DD-ConfTopDates.DAT",Pointers->dp_CurrConf->CONF_PATH);
	if (ULHandle=Open(BUFFER,MODE_NEWFILE)) {
		Write(ULHandle,&ctdates,sizeof(struct ConfTopDates));
		Close(ULHandle);
	}

}

int get_file_size (char * fileh)
{
	BPTR filelock;
	struct FileInfoBlock FBlock;

	if (filelock=Lock(fileh,ACCESS_READ)) {
		Examine(filelock,&FBlock);
		UnLock(filelock);
		return FBlock.fib_Size;
  	}
	else return 0;
}

void GenTop(char *file, ULONG startd, ULONG endd, ULONG mode)
{
	struct ConfTopData *ctd;
	int users;
	int dbsize;
	BPTR dbhandle;
	int userstogo;
	struct ConfTopData *currbest;
	struct ConfTopData *curr;
	int dohowmany;
	int etsi;
	struct DayDream_User *TheUser;
	int bestnum;
	int currnum;
	char ubbuf[40];
	char ufbuf[40];
	ULONG totk=0;
	ULONG totf=0;
	BPTR  msghandle;
	struct DateTime startdt;
	char  startds[30];
	char  endds[30];
	char  buff[200];
	char  MsgCom[300];
	char  *p;
	ULONG usersinconf=0;
	ULONG conf;

	if (mode) {
		sprintf(buff,"MSGCOM%ld '",Pointers->dp_CurrConf->CONF_NUMBER);
		if (p=ExamineCfg(CfgMem,buff)) CpyToHIPSU(p,MsgCom);
			else return;

		sprintf(buff,"T:msg.%ld",Pointers->dp_CurrUser->user_account_id);
		if (!(msghandle=Open(buff,MODE_NEWFILE))) return;
	}

	conf=Pointers->dp_CurrConf->CONF_NUMBER-1;

	startdt.dat_Stamp.ds_Days=startd;
	startdt.dat_Stamp.ds_Minute=0;
	startdt.dat_Stamp.ds_Tick=0;
	startdt.dat_Format=FORMAT_DOS;
	startdt.dat_Flags=0;
	startdt.dat_StrDay=0;
	startdt.dat_StrDate=startds;
	startdt.dat_StrTime=0;

	DateToStr(&startdt);

	startdt.dat_Stamp.ds_Days=endd;
	startdt.dat_Stamp.ds_Minute=0;
	startdt.dat_Stamp.ds_Tick=0;
	startdt.dat_Format=FORMAT_DOS;
	startdt.dat_Flags=0;
	startdt.dat_StrDay=0;
	startdt.dat_StrDate=endds;
	startdt.dat_StrTime=0;

	DateToStr(&startdt);

	dbsize=get_file_size(file);
	if (!(ctd=AllocMem(dbsize,0))) return;

	dbhandle=Open(file,MODE_OLDFILE);
	Read(dbhandle,ctd,dbsize);
	Close(dbhandle);

	users=dbsize/sizeof(struct ConfTopData);

	curr=ctd;

	if (ExamineCfg(CfgMem,"NOOPERATOR")) ctd->ULBytes=0;

	currnum=0;
	for (etsi=UBSize/300; etsi; etsi --)
	{
		TheUser=UserBase + currnum;

		if (conf<32) { 
			if (TheUser->user_conferenceacc1&(1L<<conf)) usersinconf++;
	        } else {
			if (TheUser->user_conferenceacc2&(1L<<conf-32)) usersinconf++;
	        }
		currnum++;
	}

	for (etsi=users; etsi; etsi --)
	{
		totk=totk+(curr->ULBytes/1024);
		totf=totf+curr->ULFiles;
		curr=curr+1;
	}		

	sprintf(BUFFER2,Header,Pointers->dp_CurrConf->CONF_NAME,usersinconf);
	if (mode) FPuts(msghandle,BUFFER2); else SendString(d,BUFFER2);

	for (dohowmany=1;dohowmany < maxlines+1; dohowmany ++)
	{
		curr=ctd;
		currbest=0;
		bestnum=currnum=0;
		for (etsi=users; etsi; etsi --)
		{
			if (curr->ULBytes) {
				if (currbest) { 
					if (curr->ULBytes > currbest -> ULBytes) {
						bestnum=currnum;
						currbest=curr;
					}
				} else {
					currbest=curr;
					bestnum=currnum;
				}
			}
			curr=curr+1;
			currnum++;
		}		
		if (currbest) {
			TheUser=UserBase + bestnum;
			sprintf(BUFFER2,Line,dohowmany,TheUser->user_handle,TheUser->user_organization,StyleNum(ubbuf,currbest->ULBytes),StyleNum(ufbuf,currbest->ULFiles));
			if (mode) FPuts(msghandle,BUFFER2); else SendString(d,BUFFER2);
			currbest->ULBytes=0;
		} else dohowmany=600;
	}	

	sprintf(BUFFER2,Tail,StyleNum(ubbuf,totk),StyleNum(ufbuf,totf),startds,endds);
	if (mode) FPuts(msghandle,BUFFER2); else SendString(d,BUFFER2);

	if (mode) {
		Close(msghandle);

		sprintf(BUFFER2,MsgCom,buff);
		SystemTags(BUFFER2,SYS_Input,0,SYS_Output,0,TAG_DONE);
		DeleteFile(buff);
	}
	FreeMem(ctd,dbsize);
}

char * StyleNum(char *bufferi, ULONG num)
{
	char tempbuf[60];
	char *tp;
	char *p;
	int  buflen;
	int  silmacount;

	sprintf(tempbuf,"%lu",num);
	tp=&tempbuf[50];
	buflen=strlen(tempbuf);
	p=&tempbuf[buflen-1];
	tp[1]=0;
	silmacount=3;

	while (p!=tempbuf)
	{
		if (!silmacount) {
			*tp='.';
			tp--;			
			silmacount=3;
		}
		*tp=*p;
		*tp--; *p--;
		silmacount--;
	}
	if (!silmacount) {
		*tp='.';
		tp--;			
	}
	*tp=*p;

	strcpy(bufferi,tp);
	return(bufferi);
}

void AddData(char *file, int user, ULONG bytes, ULONG call)
{
	int dbsize;
	BPTR dbhandle;
	int clearsize;
	APTR nullmem;
	struct ConfTopData ctd;

	dbsize=get_file_size(file);
	if (!(dbhandle=Open(file,MODE_READWRITE))) return;

	if (user*sizeof(struct ConfTopData) > dbsize)
	{
		nullmem=AllocMem(user*sizeof(struct ConfTopData) - dbsize,MEMF_CLEAR);
		Seek(dbhandle,0,OFFSET_END);
		Write(dbhandle,nullmem,user*sizeof(struct ConfTopData) - dbsize);
		FreeMem(nullmem,user*sizeof(struct ConfTopData) - dbsize);
 	}
	Seek(dbhandle,user*sizeof(struct ConfTopData),OFFSET_BEGINNING);
	Read(dbhandle,&ctd,sizeof(struct ConfTopData));
	Seek(dbhandle,user*sizeof(struct ConfTopData),OFFSET_BEGINNING);
	if (call==ctd.FirstC) {
		ctd.ULBytes=ctd.ULBytes+bytes;
		ctd.ULFiles++;
	} else {
		ctd.ULBytes=bytes;
		ctd.ULFiles=1;
		ctd.FirstC=call;
	}
	Write(dbhandle,&ctd,sizeof(struct ConfTopData));
	Close(dbhandle);
}

void CpyToEOL(char *src, char *dest)
{
int i=0;

	while (src[i]!=10) {
		dest[i]=src[i];
		i++;
	}
	dest[i]=0;
}

void CpyToLAINA(char *src, char *dest)
{
int i=0;

	while (src[i]!=34) {
		dest[i]=src[i];
		i++;
	}
	dest[i]=0;
}

void CpyToHIPSU(char *src, char *dest)
{
	int i=0;

	while (src[i]!=39) {
		dest[i]=src[i];
		i++;
	}
	dest[i]=0;
}

void CloseMe(void)
{
	if (UBSize) FreeMem(UserBase,UBSize);
	if (CfgMem) FreeMem(CfgMem,ConfigSize+2);
	if (FBlock) FreeDosObject(DOS_FIB,FBlock);
        FreeMem(Pointers,sizeof(struct DDPointers));
	CloseDoor(d);
	CloseLibrary(DDBase);
}

