/********************************************************************
 *                                                                  *
 * EazyLog C Version (c) 1994 by Thomas Patschinski                 *
 *                                                                  *
 ********************************************************************/

#include <exec/types.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <dos/datetime.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <error.h>
#include <own/pools.h>

#define DEF_days_ago		5
#define DEF_ports		(1L<<0)
#define DEF_top_files		10
#define DEF_top_boards		5
#define DEF_top_area_stat	99
#define DEF_top_user_stat	99
#define DEF_buffer_size		4096

#define outgoing		"Outgoing"
#define config_file		"PROGDIR:EazyLog.Config"
#define max_line_length		256

#define start_date		1       /* von 1 an */
#define start_time		10      /*  "  " "  */
#define start_port		21      /*  "  " "  */
#define start_type		25      /*  "  " "  */
#define start_user		29      /* von 0 an */

#define raw_version		"1.7"
#define raw_date		"14.8.94"

#define TEMPL_MAXIMUM		8
#define TEMPL_questionmark	0
#define TEMPL_config		1
#define TEMPL_log		2
#define TEMPL_buffer		3
#define TEMPL_files		4
#define TEMPL_boards		5
#define TEMPL_area_stat		6
#define TEMPL_user_stat		7

static char *version_dos		= "\0$VER: EazyLog "raw_version" ("raw_date")";
static char *version			= "EazyLog V" raw_version " © 1994 by Thomas Patschinski Compiled: "__DATE__" "__TIME__"";

static char *template			= "?/S,C=Config/K,L=Log/K,Buffer/K/N,F=Files/S,B=Boards/S,AreaStat/K,U=UserStat/K";

static char *DEF_log_name		= "mb:EazyBBS.TransferLog";
static char *DEF_header_name_files	= "";
static char *DEF_header_name_boards	= "";
static char *DEF_header_name_stat_area	= "";
static char *DEF_header_name_user_stat	= "";
static char *DEF_file_intro_1st		= "\\9\\1";
static char *DEF_file_intro_next	= "\\7";
static char *DEF_board_intro_1st	= "\\9\\1";
static char *DEF_board_intro_next	= "\\7";
static char *DEF_area_stat_intro_1st	= "\\9\\1";
static char *DEF_area_stat_intro_next	= "\\7";
static char *DEF_forbidden_text		= "\n\\1Sorry you are not allowed to use this Userprogramm.\n";

static char *CFG_days_ago		= "DAYSAGO";
static char *CFG_ports			= "PORTS";
static char *CFG_hidden_area		= "HIDDENAREA";
static char *CFG_hidden_board		= "HIDDENBOARD";
static char *CFG_log_name		= "LOGNAME";
static char *CFG_top_files		= "TOPFILES";
static char *CFG_top_boards		= "TOPBOARDS";
static char *CFG_top_area_stat		= "TOPAREASTAT";
static char *CFG_top_user_stat		= "TOPUSERSTAT";
static char *CFG_file_intro_1st		= "FILEINTRO1ST";
static char *CFG_file_intro_next	= "FILEINTRONEXT";
static char *CFG_board_intro_1st	= "BOARDINTRO1ST";
static char *CFG_board_intro_next	= "BOARDINTRONEXT";
static char *CFG_area_stat_intro_1st	= "AREASTATINTRO1ST";
static char *CFG_area_stat_intro_next	= "AREASTATINTRONEXT";
static char *CFG_header_top_files	= "FILEHEADER";
static char *CFG_header_top_boards	= "BOARDHEADER";
static char *CFG_header_area_stat	= "AREASTATHEADER";
static char *CFG_header_user_stat	= "USERSTATHEADER";
static char *CFG_footer_top_files	= "FILEFOOTER";
static char *CFG_footer_top_boards	= "BOARDFOOTER";
static char *CFG_show_file_header	= "SHOWFILEHEADER";
static char *CFG_show_file_footer	= "SHOWFILEFOOTER";
static char *CFG_show_board_header	= "SHOWBOARDHEADER";
static char *CFG_show_board_footer	= "SHOWBOARDFOOTER";
static char *CFG_show_area_stat_header	= "SHOWAREASTATHEADER";
static char *CFG_show_user_stat_header	= "SHOWUSERSTATHEADER";
static char *CFG_allowed_user		= "ALLOWEDUSER";
static char *CFG_forbidden_user		= "FORBIDDENUSER";
static char *CFG_forbidden_text		= "FORBIDDENTEXT";
static char *CFG_sort_user_stat		= "SORTUSERSTAT";

static char *CFG_ja			= "JA";
static char *CFG_yes			= "YES";
static char *CFG_nein			= "NEIN";
static char *CFG_no			= "NO";


#define HT_Files		0
#define HT_Boards		1
#define HT_AreaStat		2
#define HT_UserStat		3

/* Komplette Zeilen Info */

#define LF_Unbekannt		0
#define LF_Upl			1
#define LF_Dwn			2
#define LF_Msg			3
#define LF_Txt			4
#define LF_Bin			5

struct LineFormat {
   struct Node		node;
   struct DateStamp	Datum;
   int			PortNr;
   int			Action;
   int			Laenge;
   int			Dauer;
   int			Cps;
   char			User[16];
   char			AnUser[128];
   char			Name1[64];
   char			Name2[64];
};

/* Uni Top Liste (für FindNextRankItem) */

struct UniInfo {
   struct Node		node;
   int			Anzahl;
};

/* Top Board - List Daten */

struct BoardInfo {
   struct Node		node;
   int			Anzahl;
   struct LineFormat	*Data;
};

/* Top File - List Daten */

struct DownloadInfo {
   struct Node		node;
   int			Anzahl;
   struct LineFormat	*Uploader;
   struct LineFormat	*FirstDown;
};

/* UniStat Liste */

struct UniStatInfo {
   struct Node		node;
   int			Anzahl;
};

/* Area Stat - List Daten */

struct AreaStatInfo {
   struct Node		node;
   int			Anzahl;
   int			GesLaenge;
   char			User[16];
};

/* User Stat - List Daten */

struct UserStatInfo {
   struct Node		node;
   int			GesLaenge;
   int			dummy;
   char			File[64];
   struct DateStamp	Datum;
};

/* Hidden Board/Area Allowed/Forbidden User Daten */

struct HiddenData {
   struct Node		node;
   char			String[32];
};

/* Config Daten */

struct Config {
   int			DaysAgo;
   int			Ports;
   short		TopFiles;
   short		TopBoards;
   short		TopAreaStat;
   short		TopUserStat;
   BOOL			ShowFileHeader;
   BOOL			ShowFileFooter;
   BOOL			ShowBoardHeader;
   BOOL			ShowBoardFooter;
   BOOL			ShowAreaStatHeader;
   BOOL			ShowUserStatHeader;
   BOOL			SortUserStat;
   struct List		HiddenAreas;
   struct List		HiddenBoards;
   struct List		*AllowedUser;
   struct List		*ForbiddenUser;
   char			LogName[64];
   char			HeaderTopFiles[64];
   char			HeaderTopBoards[64];
   char			HeaderAreaStat[64];
   char			HeaderUserStat[64];
   char			FooterTopFiles[64];
   char			FooterTopBoards[64];
   char			FileIntro1st[16];
   char			FileIntroNext[16];
   char			BoardIntro1st[16];
   char			BoardIntroNext[16];
   char			OutLogName[64];
   char			ForbiddenText[256];
   char			AreaStatIntro1st[16];
   char			AreaStatIntroNext[16];
};

/* Prototypes */

static void Cleanup(void);
static BOOL InitAll(void);
static void AktDate(char *DateStr, char *TimeStr);
static void WriteLogFile(char *LogName, char *ConfigName, int File, int Board, char *Area, char *UserStat,BOOL Access);
static int  ReadWord(char *Buffer,char *Word,int Start);
static __stdargs char *ReadConfigFile(char *CfgName, int BuffSize);
static BOOL InList(char *Pfad, struct List *List);
static struct DownloadInfo *FileInList(char *File);
static struct BoardInfo *BoardInList(char *Board1, char *Board2);
static struct AreaStatInfo *UserInList(char *User, struct List *Liste);
static void CodeDate(char *Datum, char *Time, struct DateStamp *Date);
static void DecodeDate(char *Datum, char *Time, struct DateStamp *DecodeDate);
static char *CopyPart(char *Zeile,char *Buffer,char EndZeichen1,char EndZeichen2);
static struct LineFormat *Decode1Line(char *Zeile);
static BOOL ScanLogFile(char *Name, int BuffSize);
static void WriteDefFilesHeader(char *DateStr, char *TimeStr);
static void WriteDefBoardsHeader(char *DateStr, char *TimeStr);
static void WriteDefAreaStatHeader(char *DateStr, char *TimeStr);
static void WriteHeader(char *HeaderName, int WhichHeader, char *StatName);
static void WriteDefFooter(int Anzahl);
static void WriteFooter(char *FooterName, int GesRanks, int ShownRanks, int Gesamt, int Shown);
static APTR GetNextRankItem(int Nummer, struct List *Liste);
static void MakeTopFileListe(int *Anzahl1, int *Anzahl2);
static void SortTopFiles(void);
static void ShowTopFiles(int *Anzahl1, int *Anzahl2);
static void MakeTopBoardListe(int *Anzahl1, int *Anzahl2);
static void SortTopBoards(void);
static void ShowTopBoards(int *Anzahl1, int *Anzahl2);
static void MakeAreaStatListe(char * AreaName);
static void SortUniStat(struct List *Liste);
static void ShowAreaStat(void);
static void MakeUserStatListe(char *UserName);
static void ShowUserStat(void);
static void WriteInt(int Zahl, int Stellen);
static void WriteIntTausend(int Zahl, int Stellen);
static BOOL CheckAllowed(void);

/* Globale Variablen */

static struct List		LineList;
static struct List		TopFiles;
static struct List		TopBoards;
static struct List		TempListe;
static struct List		AreaUpListe;
static struct List		AreaDownListe;
static struct List		UserUpListe;
static struct List		UserDownListe;
static struct Config		Cfg;
static struct RDArgs		*rda;
static LONG			ResArray[TEMPL_MAXIMUM];
static char			*CharPtr;
static int			Count1,Count2,Count3,Count4;
static int			VBuffer=DEF_buffer_size;
static void			*PoolHeader=NULL;
static char			*CName;

#ifdef __SASC
__regargs int _CXBRK(void) { return(0); }      /* Disable Lattice CTRL/C handling *
__regargs int __chkabort(void) { return(0); }  /* really */
#endif

int main(void)
{
   if (rda=ReadArgs(template,&ResArray[0],NULL)) {
      if (ResArray[TEMPL_questionmark]) {
         puts(version); puts(template);
      }
      else {

         if (InitAll()) {

            if (ResArray[TEMPL_buffer])
               VBuffer=* (int *) ResArray[TEMPL_buffer];

            /*******************/
            /* Config einlesen */
            /*******************/

            if (ResArray[TEMPL_config]) {
               CName=ReadConfigFile( (char *) ResArray[TEMPL_config],VBuffer);
            }
            else {
               CName=ReadConfigFile(config_file,VBuffer);
            }

            if (ResArray[TEMPL_log])
               WriteLogFile( (char *) ResArray[TEMPL_log], CName,ResArray[TEMPL_files],
                             ResArray[TEMPL_boards],(char *) ResArray[TEMPL_area_stat],
                             (char *) ResArray[TEMPL_user_stat],CheckAllowed());

            if (CheckAllowed()) {

               /********************/
               /* Logfiles Scannen */
               /********************/

               if ((ResArray[TEMPL_files]) || (ResArray[TEMPL_boards]) ||
                   (ResArray[TEMPL_area_stat]) || (ResArray[TEMPL_user_stat])) {
                  if (ScanLogFile(&Cfg.LogName,VBuffer)) {

                     if (ResArray[TEMPL_area_stat]) {

                        /*************/
                        /* Area Stat */
                        /*************/

                        MakeAreaStatListe( (char *) ResArray[TEMPL_area_stat]);
                        SortUniStat(&AreaUpListe);
                        SortUniStat(&AreaDownListe);
                        if (Cfg.ShowAreaStatHeader)
                           WriteHeader(&Cfg.HeaderAreaStat,HT_AreaStat,(char *) ResArray[TEMPL_area_stat]);
                        ShowAreaStat();

                     }

                     if (ResArray[TEMPL_user_stat]) {

                        /*************/
                        /* User Stat */
                        /*************/

                        MakeUserStatListe( (char *) ResArray[TEMPL_user_stat]);
                        if (Cfg.ShowUserStatHeader)
                           WriteHeader(&Cfg.HeaderUserStat,HT_UserStat,(char *) ResArray[TEMPL_user_stat]);
                        if (Cfg.SortUserStat) {
                           SortUniStat(&UserUpListe);
                           SortUniStat(&UserDownListe);
                        }
                        ShowUserStat();

                     }

                     if (ResArray[TEMPL_files]) {

                        /*************/
                        /* Top Files */
                        /*************/

                        MakeTopFileListe(&Count3,&Count4);
                        SortTopFiles();
                        if (Cfg.ShowFileHeader)
                           WriteHeader(&Cfg.HeaderTopFiles,HT_Files,NULL);
                        ShowTopFiles(&Count1,&Count2);
                        if (Cfg.ShowFileFooter)
                           WriteFooter(&Cfg.FooterTopFiles,Count1,Count2,Count3,Count4);
                     }

                     if (ResArray[TEMPL_boards]) {

                        /**************/
                        /* Top Boards */
                        /**************/

                        MakeTopBoardListe(&Count3,&Count4);
                        SortTopBoards();
                        if (Cfg.ShowBoardHeader)
                           WriteHeader(&Cfg.HeaderTopBoards,HT_Boards,NULL);
                        ShowTopBoards(&Count1,&Count2);
                        if (Cfg.ShowBoardFooter)
                           WriteFooter(&Cfg.FooterTopBoards,Count1,Count2,Count3,Count4);
                     }
                  }
                  else {
                     printf("Can't open %s\n",&Cfg.LogName);
                  }
               }
            }
            else {
               printf(&Cfg.ForbiddenText);
            }
         }
      }
      FreeArgs(rda);     
   }
   else {
      puts(version); puts(template);
   }
   Cleanup();
   return 0;
}

/* Tool Proceduren */

static void Cleanup(void)
{
   DeletePool(PoolHeader);
}

static BOOL InitAll(void)
{
   /* Pool erstellen */

   if (!(PoolHeader=CreatePool(MEMF_PUBLIC|MEMF_CLEAR,32768,16384)))
      return FALSE;

   NewList(&Cfg.HiddenAreas);
   NewList(&Cfg.HiddenBoards);
   NewList(&LineList);
   NewList(&TopFiles);
   NewList(&TopBoards);
   NewList(&AreaUpListe);
   NewList(&AreaDownListe);
   NewList(&UserUpListe);
   NewList(&UserDownListe);

   return TRUE;
}

static void AktDate(char *DateStr, char *TimeStr)
{
   struct DateStamp	date;
   struct DateTime	DatumStr;

   DateStamp(&date);

   DatumStr.dat_Stamp	= date;
   DatumStr.dat_Format	= FORMAT_CDN;
   DatumStr.dat_Flags	= 0;
   DatumStr.dat_StrDay	= NULL;
   DatumStr.dat_StrDate	= DateStr;
   DatumStr.dat_StrTime	= TimeStr;

   DateToStr(&DatumStr);
}

static void WriteLogFile(char *LogName, char *ConfigName, int File, int Board, char *Area, char *UserStat,BOOL Access)
{
   BPTR			F;
   char			User[16];
   char			Date[16],Time[16];

   if (F = Open(LogName,MODE_READWRITE)) {
      if (GetVar("EazyUsername",&User,15,0)==-1)
         strcpy(&User,"<local>");

      Seek(F,0,OFFSET_END);

      AktDate(&Date,&Time);
      FPuts(F,&Date);
      FPutC(F,' ');
      FPuts(F,&Time);
      FPuts(F,", ");
      FPuts(F,&User);
      FPuts(F,", ");
      if (File)
         FPuts(F,"Files, ");
      if (Board)
         FPuts(F,"Boards, ");
      if (Area) {
         FPuts(F,Area);
         FPuts(F,", ");
      }
      if (UserStat)
         FPuts(F,"UserStat, ");
      if (ConfigName) {
         FPuts(F,ConfigName);
      }
      else {
         FPuts(F,"<Interne Config>");
      }
      if (!Access)
         FPuts(F,", *NO ACCESS* ");
      FPutC(F,'\n');
        
      Close(F);
   }

}

static int ReadWord(char *Buffer,char *Word,int Start)
{
   int		i;
   BOOL		Flag=FALSE;

   Buffer += Start;
   i=Start;

   while ((*Buffer==' ') || (*Buffer=='\t') || (*Buffer==',')) {
      Buffer++;
      i++;
   }

   while (*Buffer!='\012') {
      if ( !Flag && ((*Buffer==' ') || (*Buffer==',') || (*Buffer=='\t')) ) break;

      if (*Buffer=='\"') {
         Flag = !Flag;
      }
      else {
         if ( Flag && (*Buffer=='\\') ) {
            Buffer++;
            if ((*Buffer=='n') || (*Buffer=='N') ) {
               *Word='\n';
            }
            else {
               *Word=*Buffer;
            }
            Word++;
         }
         else {
            *Word=*Buffer;
            Word++;
         }
      }
      Buffer++;
      i++;
   }
   *Word='\0';
   if (*Buffer=='\012') return -1;
   return i;

}

static __stdargs char *ReadConfigFile(char *CfgName, int BuffSize)
{
   volatile char	*RetCfg=NULL;
   BPTR			F;
   char			Buffer[max_line_length];
   char			Word[64];
   int			Pos,Wert;
   struct HiddenData	*Data;

   Cfg.AllowedUser		= NULL;
   Cfg.ForbiddenUser		= NULL;
   Cfg.ShowFileHeader		= TRUE;
   Cfg.ShowFileFooter		= FALSE;
   Cfg.ShowBoardHeader		= TRUE;
   Cfg.ShowBoardFooter		= FALSE;
   Cfg.ShowAreaStatHeader	= TRUE;
   Cfg.ShowUserStatHeader	= TRUE;
   Cfg.SortUserStat		= TRUE;
   Cfg.DaysAgo			= DEF_days_ago;
   Cfg.Ports			= DEF_ports;
   Cfg.TopFiles			= DEF_top_files;
   Cfg.TopBoards		= DEF_top_boards;
   Cfg.TopAreaStat		= DEF_top_area_stat;
   Cfg.TopUserStat		= DEF_top_user_stat;
   strcpy(&Cfg.OutLogName,"");
   strcpy(&Cfg.FileIntro1st,DEF_file_intro_1st);
   strcpy(&Cfg.FileIntroNext,DEF_file_intro_next);
   strcpy(&Cfg.BoardIntro1st,DEF_board_intro_1st);
   strcpy(&Cfg.BoardIntroNext,DEF_board_intro_next);
   strcpy(&Cfg.HeaderTopFiles,DEF_header_name_files);
   strcpy(&Cfg.HeaderTopBoards,DEF_header_name_boards);
   strcpy(&Cfg.HeaderAreaStat,DEF_header_name_stat_area);
   strcpy(&Cfg.HeaderUserStat,DEF_header_name_user_stat);
   strcpy(&Cfg.AreaStatIntro1st,DEF_area_stat_intro_1st);
   strcpy(&Cfg.AreaStatIntroNext,DEF_area_stat_intro_next);
   strcpy(&Cfg.LogName,DEF_log_name);
   strcpy(&Cfg.ForbiddenText,DEF_forbidden_text);

   if (F=Open(CfgName,MODE_OLDFILE)) {
      RetCfg=CfgName;
      SetVBuf(F,NULL,0,BuffSize);

      while (FGets(F,&Buffer,max_line_length-1)) {
         errno=0;
         Pos=ReadWord(&Buffer,&Word,0);

         if (Pos!=-1) {
            if (Word[0]!='#') {
               if (!stricmp(&Word,CFG_days_ago)) {
                  ReadWord(&Buffer,&Word,Pos);
                  Wert=strtol(&Word,NULL,10);
                  if ( (errno!=ERANGE) && (Wert>0) )
                     Cfg.DaysAgo=Wert;
               }

               if (!stricmp(&Word,CFG_ports)) {
                  Cfg.Ports=0;
                  do {
                     Pos=ReadWord(&Buffer,&Word,Pos);
                     Wert=strtol(&Word,NULL,10);
                     if ( (errno!=ERANGE) && (Wert>0) )
                        Cfg.Ports |= Wert;
                  } while (Pos!=-1);
               }

               if (!stricmp(&Word,CFG_top_files)) {
                  ReadWord(&Buffer,&Word,Pos);
                  Wert=strtol(&Word,NULL,10);
                  if ( (errno!=ERANGE) && (Wert>0) )
                     Cfg.TopFiles=Wert;
               }

               if (!stricmp(&Word,CFG_top_boards)) {
                  ReadWord(&Buffer,&Word,Pos);
                  Wert=strtol(&Word,NULL,10);
                  if ( (errno!=ERANGE) && (Wert>0) )
                     Cfg.TopBoards=Wert;
               }

               if (!stricmp(&Word,CFG_top_area_stat)) {
                  ReadWord(&Buffer,&Word,Pos);
                  Wert=strtol(&Word,NULL,10);
                  if ( (errno!=ERANGE) && (Wert>0) )
                     Cfg.TopAreaStat=Wert;
               }

               if (!stricmp(&Word,CFG_top_user_stat)) {
                  ReadWord(&Buffer,&Word,Pos);
                  Wert=strtol(&Word,NULL,10);
                  if ( (errno!=ERANGE) && (Wert>0) )
                     Cfg.TopUserStat=Wert;
               }

               if (!stricmp(&Word,CFG_log_name)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.LogName,&Word);
               }

               if (!stricmp(&Word,CFG_file_intro_1st)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.FileIntro1st,&Word);
               }

               if (!stricmp(&Word,CFG_file_intro_next)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.FileIntroNext,&Word);
               }

               if (!stricmp(&Word,CFG_board_intro_1st)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.BoardIntro1st,&Word);
               }

               if (!stricmp(&Word,CFG_board_intro_next)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.BoardIntroNext,&Word);
               }

               if (!stricmp(&Word,CFG_area_stat_intro_1st)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.AreaStatIntro1st,&Word);
               }

               if (!stricmp(&Word,CFG_area_stat_intro_next)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word))
                     strcpy(&Cfg.AreaStatIntroNext,&Word);
               }

               if (!stricmp(&Word,CFG_header_top_files)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.HeaderTopFiles,&Word);
               }

               if (!stricmp(&Word,CFG_header_top_boards)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.HeaderTopBoards,&Word);
               }

               if (!stricmp(&Word,CFG_header_area_stat)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.HeaderAreaStat,&Word);
               }

               if (!stricmp(&Word,CFG_header_user_stat)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.HeaderUserStat,&Word);
               }

               if (!stricmp(&Word,CFG_footer_top_files)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.FooterTopFiles,&Word);
               }

               if (!stricmp(&Word,CFG_footer_top_boards)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.FooterTopBoards,&Word);
               }

               if (!stricmp(&Word,CFG_show_file_header)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_nein))
                     Cfg.ShowFileHeader=FALSE;
                  if (!stricmp(&Word,CFG_no))
                     Cfg.ShowFileHeader=FALSE;
               }

               if (!stricmp(&Word,CFG_show_file_footer)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_ja))
                     Cfg.ShowFileFooter=TRUE;
                  if (!stricmp(&Word,CFG_yes))
                     Cfg.ShowFileFooter=TRUE;
               }

               if (!stricmp(&Word,CFG_show_board_header)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_nein))
                     Cfg.ShowBoardHeader=FALSE;
                  if (!stricmp(&Word,CFG_no))
                     Cfg.ShowBoardHeader=FALSE;
               }

               if (!stricmp(&Word,CFG_show_board_footer)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_ja))
                     Cfg.ShowBoardFooter=TRUE;
                  if (!stricmp(&Word,CFG_yes))
                     Cfg.ShowBoardFooter=TRUE;
               }

               if (!stricmp(&Word,CFG_show_area_stat_header)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_nein))
                     Cfg.ShowAreaStatHeader=FALSE;
                  if (!stricmp(&Word,CFG_no))
                     Cfg.ShowAreaStatHeader=FALSE;
               }

               if (!stricmp(&Word,CFG_show_user_stat_header)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_nein))
                     Cfg.ShowUserStatHeader=FALSE;
                  if (!stricmp(&Word,CFG_no))
                     Cfg.ShowUserStatHeader=FALSE;
               }

               if (!stricmp(&Word,CFG_sort_user_stat)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!stricmp(&Word,CFG_nein))
                     Cfg.SortUserStat=FALSE;
                  if (!stricmp(&Word,CFG_no))
                     Cfg.SortUserStat=FALSE;
               }

               if (!stricmp(&Word,CFG_hidden_area)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (Data=AllocPooled(PoolHeader,sizeof(struct HiddenData))) {
                     strcpy(&Data->String,&Word);
                     strupr(&Data->String);
                     AddTail(&Cfg.HiddenAreas,Data);
                  }
               }

               if (!stricmp(&Word,CFG_hidden_board)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (Data=AllocPooled(PoolHeader,sizeof(struct HiddenData))) {
                     strcpy(&Data->String,&Word);
                     strupr(&Data->String);
                     AddTail(&Cfg.HiddenBoards,Data);
                  }
               }

               if (!stricmp(&Word,CFG_allowed_user)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!Cfg.AllowedUser) {
                     if (Cfg.AllowedUser=AllocPooled(PoolHeader,sizeof(struct List)))
                        NewList(Cfg.AllowedUser);
                  }
                  if (Cfg.AllowedUser && (Data=AllocPooled(PoolHeader,sizeof(struct HiddenData))) ) {
                     strcpy(&Data->String,&Word);
                     strupr(&Data->String);
                     AddTail(Cfg.AllowedUser,Data);
                  }
               }

               if (!stricmp(&Word,CFG_forbidden_user)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (!Cfg.ForbiddenUser) {
                     if (Cfg.ForbiddenUser=AllocPooled(PoolHeader,sizeof(struct List)))
                        NewList(Cfg.ForbiddenUser);
                  }
                  if (Cfg.ForbiddenUser && (Data=AllocPooled(PoolHeader,sizeof(struct HiddenData))) ) {
                     strcpy(&Data->String,&Word);
                     strupr(&Data->String);
                     AddTail(Cfg.ForbiddenUser,Data);
                  }
               }

               if (!stricmp(&Word,CFG_forbidden_text)) {
                  ReadWord(&Buffer,&Word,Pos);
                  if (strlen(&Word)>2)
                     strcpy(&Cfg.ForbiddenText,&Word);
               }

            }
         }

      }
      Close(F);
   }
   return RetCfg;
}

static __inline BOOL InList(char *Pfad, struct List *List)
{
   struct HiddenData	*TempData;

   TempData = (struct HiddenData*) List->lh_Head;

   while (TempData->node.ln_Succ) {
      if (!stricmp(Pfad,&TempData->String))
         return TRUE;
      TempData = (struct HiddenData *) TempData->node.ln_Succ;
   }
   return FALSE;
}

static struct DownloadInfo *FileInList(char *File)
{
   struct DownloadInfo	*TempDown;

   TempDown = (struct DownloadInfo*) TopFiles.lh_Head;
   while (TempDown->node.ln_Succ) {
      if (!strcmp(&TempDown->FirstDown->Name2,File))
         return TempDown;
      TempDown = (struct DownloadInfo*) TempDown->node.ln_Succ;
   }
   return NULL;
}

static struct AreaStatInfo *UserInList(char *User, struct List *Liste)
{
   struct AreaStatInfo	*TempAreaStat;

   TempAreaStat = (struct AreaStatInfo*) Liste->lh_Head;
   while (TempAreaStat->node.ln_Succ) {
      if (!strcmp(&TempAreaStat->User,User))
         return TempAreaStat;
      TempAreaStat = (struct AreaStatInfo*) TempAreaStat->node.ln_Succ;
   }
   return NULL;
}

static struct BoardInfo *BoardInList(char *Board1, char *Board2)
{
   struct BoardInfo	*TempBoard;

   TempBoard = (struct BoardInfo*) TopBoards.lh_Head;
   while (TempBoard->node.ln_Succ) {
      if ( (!strcmp(&TempBoard->Data->Name1,Board1)) && (!strcmp(&TempBoard->Data->Name2,Board2)) )
         return TempBoard;
      TempBoard = (struct BoardInfo*) TempBoard->node.ln_Succ;
   }
   return NULL;
}

static void CodeDate(char *Datum, char *Time, struct DateStamp *CodeDate)
{
   struct DateTime	DT;

   DT.dat_Format  = FORMAT_CDN;
   DT.dat_Flags   = 0;
   DT.dat_StrDay  = NULL;
   DT.dat_StrDate = Datum;
   DT.dat_StrTime = Time;
   if (StrToDate(&DT)) {
        *CodeDate=DT.dat_Stamp;
   }
   else {
      memset(CodeDate,0,sizeof(struct DateStamp));
   }
}

static void DecodeDate(char *Datum, char *Time, struct DateStamp *DecodeDate)
{
   struct DateTime	DT;

   DT.dat_Format  = FORMAT_CDN;
   DT.dat_Flags   = 0;
   DT.dat_StrDay  = NULL;
   DT.dat_StrDate = Datum;
   DT.dat_StrTime = Time;
   DT.dat_Stamp   = *DecodeDate;

   if (!DateToStr(&DT)) {
      strcpy(Datum,""); strcpy(Time,"");
   }
}

static __inline char *CopyPart(char *Zeile,char *Buffer,char EndZeichen1,char EndZeichen2)
{
   while (*Zeile!=EndZeichen1 && *Zeile!=EndZeichen2 && *Zeile!=0) {
      *Buffer=*Zeile;
      Buffer++;
      Zeile++;
   }
   *Buffer=0;
   return Zeile;
}

static struct LineFormat *Decode1Line(char *Zeile)
{
   int			i,i2;
   char			DateStr[10];
   char			TimeStr[10];
   char			TempStr[128];
   struct LineFormat	*L;
   BOOL			DriveFlag = FALSE;

   if (!(L = AllocPooled(PoolHeader,sizeof(struct LineFormat))))
      return NULL;

   Zeile=CopyPart(Zeile,&DateStr,' ',' ');
   Zeile++;

   Zeile=CopyPart(Zeile,&TimeStr,',',',');
   Zeile += 3;

   CodeDate(&DateStr,&TimeStr,&L->Datum);

   Zeile=CopyPart(Zeile,&TempStr,' ',',');
   if (*Zeile==' ') {
      Zeile += 3;
   }
   else {
      Zeile += 2;
   }

   L->PortNr=strtol(&TempStr,NULL,10);
   if (!(Cfg.Ports & L->PortNr)) {
      FreePooled(PoolHeader,L,sizeof(struct LineFormat));
      return NULL;
   }

   Zeile=CopyPart(Zeile,&TempStr,':',',');
   Zeile += 2;

   L->Action=LF_Unbekannt;
   if (!strcmp(&TempStr,"Upl")) L->Action=LF_Upl;
   if (!strcmp(&TempStr,"Dwn")) L->Action=LF_Dwn;
   if (!strcmp(&TempStr,"Msg")) L->Action=LF_Msg;
   if (!strcmp(&TempStr,"Txt")) L->Action=LF_Txt;
   if (!strcmp(&TempStr,"Bin")) L->Action=LF_Bin;

   Zeile=CopyPart(Zeile,&L->User,',',',');
   Zeile += 2;

   Zeile=CopyPart(Zeile,&TempStr,' ',' ');
   L->Laenge=strtol(&TempStr,NULL,10);
   Zeile += 8;

   if ((L->Action==LF_Upl) || (L->Action==LF_Dwn)) {

      Zeile=CopyPart(Zeile,&TempStr,' ',',');
      if (!strcmp(&TempStr,"<local>")) {
         L->Cps=-1;
         Zeile += 2;
      }
      else {
         L->Cps=strtol(&TempStr,NULL,10);
         Zeile += 6;
      }

      i = 0;
      while (*Zeile!='\012') {
         if (*Zeile==':') DriveFlag=TRUE;
         L->Name1[i]=*Zeile++;
         i++;
      }
      L->Name1[i]=0;

      if (DriveFlag) {

         while ((i>=0) && (L->Name1[i]!='/') && (L->Name1[i]!=':')) {
            i--;
            Zeile--;
         }

         if (L->Name1[i]==':')
            i++;

         L->Name1[i]=0;

         strcpy(&TempStr,&L->Name1);
         i2=0;
         while (TempStr[i2]!=':')
            i2++;
         i2+=2;

         strmid(&TempStr,&L->Name1,i2,strlen(&TempStr)-1);

         if ( (InList(&L->Name1,&Cfg.HiddenAreas)) || (strstr(&L->Name1,outgoing)) ) {
            FreePooled(PoolHeader,L,sizeof(struct LineFormat));
            return NULL;
         }

         Zeile++;

         CopyPart(Zeile,&L->Name2,'\012','\012');

      }
      else {
         strcpy(&L->Name2,&L->Name1);
         L->Name1[0]=0;
      }
   }
   else {
      Zeile=CopyPart(Zeile,&TempStr,' ',' ');
      L->Dauer=strtol(&TempStr,NULL,10);
      Zeile += 7;

      if (L->Action==LF_Msg) {
         Zeile=CopyPart(Zeile,&L->Name1,'\012','\012');

         if (InList(&L->Name1,&Cfg.HiddenBoards)) {
            FreePooled(PoolHeader,L,sizeof(struct LineFormat));
            return NULL;
         }

         i=strlen(&L->Name1);

         while ( (i>=0) && (L->Name1[i]!='/') ) {
            i--;
            Zeile--;
         }
         L->Name1[i]=0;

         Zeile++;
         CopyPart(Zeile,&L->Name2,'\012','\012');
      }
      else {
         CopyPart(Zeile,&L->AnUser,'\012','\012');
      }
   }
   return L;
}

static BOOL ScanLogFile(char *Name, int BuffSize)
{
   BPTR			F;
   char			*LineBuffer[max_line_length];
   struct LineFormat	*Line;
   int			MaxLength;

   if (DOSBase->dl_lib.lib_Version>=39) {
      MaxLength=max_line_length;
   }
   else {
      MaxLength=max_line_length-1;
   }

   if (!(F=Open(Name,MODE_OLDFILE)))
      return FALSE;

   SetVBuf(F,NULL,0,BuffSize);

   while (FGets(F,&LineBuffer,MaxLength)) {
      if (Line=Decode1Line(&LineBuffer))
         AddTail(&LineList,Line);
           
   }
   Close(F);
   return TRUE;
}

static void WriteDefFilesHeader(char *DateStr, char *TimeStr)
{
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   puts("\\6\\1|      \\0\\6\\2\\1EazyLog\\0\\6\\1       |     Version "raw_version"       |  (c) 1994 by Thomas Patschinski |");
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   printf("\\6\\1      Top Files                                \\7Generated on %s at %s\n",DateStr,TimeStr);
   puts("\\6\\1--------------------------------------------------------------------------------");
   puts("\\9\\1 Rang    Filename                 gezogen    File Area            Uploader      ");
   puts("\\9\\1================================================================================\n");
}

static void WriteDefBoardsHeader(char *DateStr, char *TimeStr)
{
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   puts("\\6\\1|      \\0\\6\\2\\1EazyLog\\0\\6\\1       |     Version "raw_version"       |  (c) 1994 by Thomas Patschinski |");
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   printf("\\6\\1      Top Boards                               \\7Generated on %s at %s\n",DateStr,TimeStr);
   puts("\\6\\1--------------------------------------------------------------------------------");
   puts("\\9\\1     Rang        Boardname             wie oft beschrieben                      ");
   puts("\\9\\1================================================================================\n");
}

static void WriteDefAreaStatHeader(char *DateStr, char *TimeStr)
{
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   puts("\\6\\1|      \\0\\6\\2\\1EazyLog\\0\\6\\1       |     Version "raw_version"       |  (c) 1994 by Thomas Patschinski |");
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   printf("\\6\\1      Area Stat                                \\7Generated on %s at %s\n",DateStr,TimeStr);
   puts("\\6\\1--------------------------------------------------------------------------------");
   puts("\\9\\1  Rang  Uploader        Anz.    GesLänge     Downloader      Anz.    GesLänge   ");
   puts("\\9\\1================================================================================\n");
}

static void WriteDefUserStatHeader(char *DateStr, char *TimeStr)
{
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   puts("\\6\\1|      \\0\\6\\2\\1EazyLog\\0\\6\\1       |     Version "raw_version"       |  (c) 1994 by Thomas Patschinski |");
   puts("\\6\\1+--------------------+-----------------------+---------------------------------+");
   printf("\\6\\1      User Stat                                \\7Generated on %s at %s\n",DateStr,TimeStr);
   puts("\\6\\1--------------------------------------------------------------------------------");
   puts("\\9\\1  Rang     Filename                               Länge     Datum               ");
   puts("\\9\\1================================================================================\n");
}

static void WriteHeader(char *HeaderName, int WhichHeader, char *StatName)
{
   BPTR		F;
   char		DateStr[16];
   char		TimeStr[16];
   char		Buffer[max_line_length];
   int		i,j,MaxLength;

   if (DOSBase->dl_lib.lib_Version>=39) {
      MaxLength=max_line_length;
   }
   else {
      MaxLength=max_line_length-1;
   }

   AktDate(&DateStr,&TimeStr);

   if(F=Open(HeaderName,MODE_OLDFILE)) {
      while (FGets(F,&Buffer,MaxLength)) {
         i=0;
         while (Buffer[i]!=0) {
            if (Buffer[i]=='%') {
               i++;
               switch (Buffer[i]) {
                  case '%': putchar('%');
                            break;
                  case 'v':
                  case 'V': printf(raw_version);
                            break;
                  case 'd':
                  case 'D': printf("%s at %s",DateStr,TimeStr);
                            break;
                  case 'a':
                  case 'A': WriteInt(Cfg.DaysAgo,3);
                            break;
                  case 's':
                  case 'S': if (StatName) {
                               printf(StatName);
                               for (j=strlen(StatName);j<31;j++)
                                  putchar(' ');
                            }
                            break;
                  case 'u':
                  case 'U': if (StatName) {
                               printf(StatName);
                               for (j=strlen(StatName);j<15;j++)
                                  putchar(' ');
                            }
                            break;
                  default:  putchar(Buffer[i]);
               }
            }
            else {
               putchar(Buffer[i]);
            }
            i++;
         }
      }
      Close(F);
   }
   else {
      switch (WhichHeader) {
         case HT_Files:    WriteDefFilesHeader(&DateStr,&TimeStr);
                           break;
         case HT_Boards:   WriteDefBoardsHeader(&DateStr,&TimeStr);
                           break;
         case HT_AreaStat: WriteDefAreaStatHeader(&DateStr,&TimeStr);
                           break;
         case HT_UserStat: WriteDefUserStatHeader(&DateStr,&TimeStr);
      }
   }
}

static void WriteDefFooter(int Anzahl)
{
   printf("\nAnzahl der nicht angezeigten Plätze:%d\n",Anzahl);
}

static void WriteFooter(char *FooterName, int GesRanks, int ShownRanks, int Gesamt, int Shown)
{
   BPTR		F;
   char		Buffer[max_line_length];
   int		i,MaxLength;

   if (DOSBase->dl_lib.lib_Version>=39) {
      MaxLength=max_line_length;
   }
   else {
      MaxLength=max_line_length-1;
   }

   if (F=Open(FooterName,MODE_OLDFILE)) {
      while (FGets(F,&Buffer,MaxLength)) {
         i=0;
         while (Buffer[i]!=0) {
            if (Buffer[i]=='%') {
               i++;
               switch (Buffer[i]) {
                  case '%': putchar('%');
                            break;
                  case '1': WriteInt(Gesamt,3);
                            break;
                  case '2': WriteInt(Shown,3);
                            break;
                  case '3': WriteInt(GesRanks,3);
                            break;
                  case '4': WriteInt(ShownRanks,3);
                            break;
                  case '5': WriteInt(GesRanks-ShownRanks,3);
                            break;
                  default:  putchar(Buffer[i]);
               }
            }
            else {
               putchar(Buffer[i]);
            }
            i++;
         }
      }
      Close(F);
   }
   else {
      WriteDefFooter(GesRanks-ShownRanks);
   }
}

static APTR GetNextRankItem(int Nummer, struct List *Liste)
{
   struct UniInfo	*TopNode,*PrevTopNode=NULL;

   TopNode = (struct UniInfo*) Liste->lh_Head;
   while (TopNode->node.ln_Succ) {
      if (TopNode->Anzahl>=Nummer)
         PrevTopNode=TopNode;
      if (TopNode->Anzahl<Nummer)
         return PrevTopNode;
      TopNode = (struct UniInfo*) TopNode->node.ln_Succ;
   }
   return PrevTopNode;
}

static void MakeTopFileListe(int *Anzahl1, int *Anzahl2)
{
   struct LineFormat	*LineNode;
   struct DownloadInfo	*TopNode;
   struct DateStamp	AktDate;

   *Anzahl1=*Anzahl2=0;
   DateStamp(&AktDate);

   /* Zuerst alle Downs in die Liste eintragen */

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Dwn) {
         *Anzahl1=*Anzahl1+1;
         if (LineNode->Datum.ds_Days>=AktDate.ds_Days-Cfg.DaysAgo) {
            *Anzahl2=*Anzahl2+1;
            if (TopNode=FileInList(&LineNode->Name2)) {
               TopNode->Anzahl++;
            }
            else {
               if (TopNode=AllocPooled(PoolHeader,sizeof(struct DownloadInfo))) {
                  TopNode->Anzahl    = 1;
                  TopNode->FirstDown = LineNode;
                  TopNode->Uploader  = NULL;
                  AddTail(&TopFiles,TopNode);
               }
            }
         }
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }

   /* Jetzt die Uploader nachtragen (Falls noch in der Liste) */

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Upl) {
         if (TopNode=FileInList(LineNode->Name2))
            TopNode->Uploader=LineNode;
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }
}

static void SortTopFiles(void)
{
   struct DownloadInfo	*TopNode,*PrevTopNode;

   NewList(&TempListe);

   while (TopNode = (struct DownloadInfo*) RemTail(&TopFiles)) {
      if (PrevTopNode=GetNextRankItem(TopNode->Anzahl,&TempListe)) {
         Insert(&TempListe,TopNode,PrevTopNode);
      }
      else {
         AddHead(&TempListe,TopNode);
      }
   }
   TopFiles=TempListe;
}

static void ShowTopFiles(int *Anzahl1, int *Anzahl2)
{
   struct DownloadInfo	*TopNode;
   int			Rang=1;
   int			i;

   *Anzahl1=*Anzahl2=0;

   TopNode = (struct DownloadInfo*) TopFiles.lh_Head;
   while (TopNode->node.ln_Succ) {
      if (Rang==1)
         printf(&Cfg.FileIntro1st);
      if (Rang>1 && Rang<=Cfg.TopFiles)
         printf(&Cfg.FileIntroNext);
      if (Rang<=Cfg.TopFiles) {
         *Anzahl2=*Anzahl2+1;
         WriteInt(Rang,3); printf("   ");
         printf(TopNode->FirstDown->Name2);
         for (i=strlen(&TopNode->FirstDown->Name2);i<=30;i++)
            putchar(' ');

         WriteInt(TopNode->Anzahl,3);
         if (strlen(TopNode->FirstDown->Name1)==0)
            strcpy(&TopNode->FirstDown->Name1,"CD-Rom");
         printf("   %s",&TopNode->FirstDown->Name1);
         for (i=strlen(&TopNode->FirstDown->Name1);i<=23;i++)
            putchar(' ');

         if (TopNode->Uploader) {
            printf(&TopNode->Uploader->User);
            for (i=strlen(&TopNode->Uploader->User);i<=12;i++)
               putchar(' ');
         }
         else {
            printf("            ");
         }
         putchar('\n');
      }
      if (Rang==1)
         putchar('\n');
      Rang++;
      *Anzahl1=*Anzahl1+1;
      TopNode=(struct DownloadInfo*)TopNode->node.ln_Succ;
   }        
}

static void MakeTopBoardListe(int *Anzahl1, int *Anzahl2)
{
   struct LineFormat	*LineNode;
   struct BoardInfo	*BoardNode;
   struct DateStamp	AktDate;

   *Anzahl1=*Anzahl2=0;
   DateStamp(&AktDate);

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Msg) {
         *Anzahl1=*Anzahl1+1;
         if (LineNode->Datum.ds_Days>=AktDate.ds_Days-Cfg.DaysAgo) {
            *Anzahl2=*Anzahl2+1;
            if (BoardNode=BoardInList(&LineNode->Name1,&LineNode->Name2)) {
               BoardNode->Anzahl++;
            }
            else {
               if (BoardNode=AllocPooled(PoolHeader,sizeof(struct BoardInfo))) {
                  BoardNode->Anzahl = 1;
                  BoardNode->Data   = LineNode;
                  AddTail(&TopBoards,BoardNode);
               }
            }
         }
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }
}

static void SortTopBoards(void)
{
   struct BoardInfo	*BoardNode,*PrevBoardNode;

   NewList(&TempListe);

   while (BoardNode = (struct BoardInfo*) RemTail(&TopBoards)) {
      if (PrevBoardNode=GetNextRankItem(BoardNode->Anzahl,&TempListe)) {
         Insert(&TempListe,BoardNode,PrevBoardNode);
      }
      else {
         AddHead(&TempListe,BoardNode);
      }
   }
   TopBoards=TempListe;
}

static void ShowTopBoards(int *Anzahl1, int *Anzahl2)
{
   struct BoardInfo	*BoardNode;
   int			i,Rang=1;

   *Anzahl1=*Anzahl2=0;

   BoardNode = (struct BoardInfo*) TopBoards.lh_Head;
   while (BoardNode->node.ln_Succ) {
      if (Rang==1)
         printf(&Cfg.BoardIntro1st);
      if (Rang>1 && Rang<=Cfg.TopBoards)
         printf(&Cfg.BoardIntroNext);
      if (Rang<=Cfg.TopBoards) {
         *Anzahl2=*Anzahl2+1;
         printf("    ");
         WriteInt(Rang,3);
         printf("     ");
         printf(&BoardNode->Data->Name1);
         putchar('/');
         printf(&BoardNode->Data->Name2);

         for (i=strlen(&BoardNode->Data->Name1)+strlen(&BoardNode->Data->Name2);i<=35;i++)
            putchar(' ');

         WriteInt(BoardNode->Anzahl,3);
         printf("                            \n");
      }
      if (Rang==1)
         putchar('\n');
      Rang++;
      *Anzahl1=*Anzahl1+1;
      BoardNode = (struct BoardInfo*) BoardNode->node.ln_Succ;
   }
}

static void MakeAreaStatListe(char *AreaName)
{
   struct LineFormat	*LineNode;
   struct AreaStatInfo	*AreaNode;
   struct DateStamp	AktDate;

   DateStamp(&AktDate);

   /* AreaStat Down Liste erstellen */

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Dwn) {
         if ( (LineNode->Laenge) && (LineNode->Datum.ds_Days>=AktDate.ds_Days-Cfg.DaysAgo) ) {
            if (!stricmp(&LineNode->Name1,AreaName)) {
               if (AreaNode=UserInList(&LineNode->User,&AreaDownListe)) {
                  AreaNode->Anzahl++;
                  AreaNode->GesLaenge += LineNode->Laenge;
               }
               else {
                  if (AreaNode=AllocPooled(PoolHeader,sizeof(struct AreaStatInfo))) {
                     AreaNode->Anzahl    = 1;
                     AreaNode->GesLaenge = LineNode->Laenge;
                     strcpy(&AreaNode->User,&LineNode->User);
                     AddTail(&AreaDownListe,AreaNode);
                  }
               }
            }
         }
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }

   /* AreaStat Up Liste erstellen */

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Upl) {
         if ( (LineNode->Laenge) && (LineNode->Datum.ds_Days>=AktDate.ds_Days-Cfg.DaysAgo) ) {
            if (!stricmp(&LineNode->Name1,AreaName)) {
               if (AreaNode=UserInList(&LineNode->User,&AreaUpListe)) {
                  AreaNode->Anzahl++;
                  AreaNode->GesLaenge += LineNode->Laenge;
               }
               else {
                  if (AreaNode=AllocPooled(PoolHeader,sizeof(struct AreaStatInfo))) {
                     AreaNode->Anzahl    = 1;
                     AreaNode->GesLaenge = LineNode->Laenge;
                     strcpy(&AreaNode->User,&LineNode->User);
                     AddTail(&AreaUpListe,AreaNode);
                  }
               }
            }
         }
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }
}

static void SortUniStat(struct List *Liste)
{
   struct UniStatInfo	*Node,*PrevNode;

   NewList(&TempListe);

   while (Node = (struct UniStatInfo*) RemTail(Liste)) {
      if (PrevNode=GetNextRankItem(Node->Anzahl,&TempListe)) {
         Insert(&TempListe,Node,PrevNode);
      }
      else {
         AddHead(&TempListe,Node);
      }
   }
   *Liste=TempListe;
}

static void ShowAreaStat(void)
{
   struct AreaStatInfo	*AreaUpNode,*AreaDownNode;
   int			i,Rang=1;

   AreaUpNode   = (struct AreaStatInfo*) AreaUpListe.lh_Head;
   AreaDownNode = (struct AreaStatInfo*) AreaDownListe.lh_Head;
   while ( (AreaUpNode->node.ln_Succ) || (AreaDownNode->node.ln_Succ) ) {
      if (Rang==1)
         printf(&Cfg.AreaStatIntro1st);
      if (Rang>1 && Rang<=Cfg.TopAreaStat)
         printf(&Cfg.AreaStatIntroNext);
      if (Rang<=Cfg.TopAreaStat) {
         printf("  ");
         WriteInt(Rang,3);
         printf("   ");
         if (AreaUpNode->node.ln_Succ) {
            printf(&AreaUpNode->User);

            for (i=strlen(&AreaUpNode->User);i<15;i++)
               putchar(' ');

            printf("  ");
            WriteInt(AreaUpNode->Anzahl,2);
            printf("  ");
            WriteIntTausend(AreaUpNode->GesLaenge,12);
            printf("  ");

         }
         else {
            printf("                                   ");
         }

         if (AreaDownNode->node.ln_Succ) {
            printf("  ");
            printf(&AreaDownNode->User);

            for (i=strlen(&AreaDownNode->User);i<15;i++)
               putchar(' ');

            printf("  ");
            WriteInt(AreaDownNode->Anzahl,2);
            printf("  ");
            WriteIntTausend(AreaDownNode->GesLaenge,12);

         }
         else {
            printf("                                   ");
         }
         printf("       \n");
      }
      if (Rang==1)
         putchar('\n');
      Rang++;

      if (AreaUpNode->node.ln_Succ)
         AreaUpNode   = (struct AreaStatInfo*) AreaUpNode->node.ln_Succ;

      if (AreaDownNode->node.ln_Succ)
         AreaDownNode = (struct AreaStatInfo*) AreaDownNode->node.ln_Succ;
   }

}

static void MakeUserStatListe(char *UserName)
{
   struct LineFormat	*LineNode;
   struct UserStatInfo	*UserNode;
   struct DateStamp	AktDate;
   char			*TempString[64];

   DateStamp(&AktDate);

   /* UserStat Down Liste erstellen */

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Dwn) {
         if ( (LineNode->Laenge) && (LineNode->Datum.ds_Days>=AktDate.ds_Days-Cfg.DaysAgo) ) {
            if (!stricmp(&LineNode->User,UserName)) {
               strcpy(&TempString,&LineNode->Name1);
               strcat(&TempString,":");
               strcat(&TempString,&LineNode->Name2);
               if (!UserInList(&TempString,&UserDownListe)) {
                  if (UserNode=AllocPooled(PoolHeader,sizeof(struct UserStatInfo))) {
                     UserNode->GesLaenge = LineNode->Laenge;
                     UserNode->Datum     = LineNode->Datum;
                     strcpy(&UserNode->File,&TempString);
                     AddTail(&UserDownListe,UserNode);
                  }
               }
            }
         }
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }

   /* UserStat Up Liste erstellen */

   LineNode = (struct LineFormat*) LineList.lh_Head;
   while (LineNode->node.ln_Succ) {
      if (LineNode->Action==LF_Upl) {
         if ( (LineNode->Laenge) && (LineNode->Datum.ds_Days>=AktDate.ds_Days-Cfg.DaysAgo) ) {
            if (!stricmp(&LineNode->User,UserName)) {
               strcpy(&TempString,&LineNode->Name1);
               strcat(&TempString,":");
               strcat(&TempString,&LineNode->Name2);
               if (!UserInList(&TempString,&UserUpListe)) {
                  if (UserNode=AllocPooled(PoolHeader,sizeof(struct UserStatInfo))) {
                     UserNode->GesLaenge = LineNode->Laenge;
                     UserNode->Datum     = LineNode->Datum;
                     strcpy(&UserNode->File,&TempString);
                     AddTail(&UserUpListe,UserNode);
                  }
               }
            }
         }
      }
      LineNode = (struct LineFormat*) LineNode->node.ln_Succ;
   }
}

static void ShowUserStat(void)
{
   struct UserStatInfo	*UserUpNode,*UserDownNode;
   int			i,GesamtLaenge=0,Rang=1;
   char			Date[16],Time[16];

   printf("Uploads:\n");
   UserUpNode   = (struct UserStatInfo*) UserUpListe.lh_Head;
   while (UserUpNode->node.ln_Succ) {
      if (Rang<=Cfg.TopUserStat) {
         printf(" ");
         WriteInt(Rang,3);
         printf(" ");
         printf(&UserUpNode->File);

         for (i=strlen(&UserUpNode->File);i<40;i++)
            putchar(' ');

         printf(" ");
         WriteIntTausend(UserUpNode->GesLaenge,12);

         GesamtLaenge += UserUpNode->GesLaenge;

         DecodeDate(&Date,&Time,&UserUpNode->Datum);
         printf("   %s %s\n",&Date,&Time);
      }
      Rang++;

      UserUpNode = (struct UserStatInfo*) UserUpNode->node.ln_Succ;

   }

   if (GesamtLaenge>0) {
      printf("                                             --------------\n");
      printf("                                              ");
      WriteIntTausend(GesamtLaenge,12);
      printf("\n");
   }

   Rang=1;
   GesamtLaenge=0;

   printf("------------------------------------------------------------------------------\nDownloads:\n");

   UserDownNode   = (struct UserStatInfo*) UserDownListe.lh_Head;
   while (UserDownNode->node.ln_Succ) {
      if (Rang<=Cfg.TopUserStat) {
         printf(" ");
         WriteInt(Rang,3);
         printf(" ");
         printf(&UserDownNode->File);

         for (i=strlen(&UserDownNode->File);i<40;i++)
            putchar(' ');

         printf(" ");
         WriteIntTausend(UserDownNode->GesLaenge,12);

         GesamtLaenge += UserDownNode->GesLaenge;

         DecodeDate(&Date,&Time,&UserDownNode->Datum);
         printf("   %s %s\n",&Date,&Time);
      }
      Rang++;

      UserDownNode = (struct UserStatInfo*) UserDownNode->node.ln_Succ;

   }

   if (GesamtLaenge>0) {
      printf("                                             --------------\n");
      printf("                                              ");
      WriteIntTausend(GesamtLaenge,12);
      printf("\n");
   }

}

static void WriteInt(int Zahl, int Stellen)
{
   char		TempString[16];
   int		Laenge,i;

   Laenge=stci_d(&TempString,Zahl);
   if (Laenge<Stellen) {
      for (i=Laenge;i<Stellen;i++)
         putchar(' ');

   }
   printf(&TempString);
}

static void WriteIntTausend(int Zahl, int Stellen)
{
   char		TempString[32],ResultString[32];
   int		Laenge,i,t;
   char		*S;

   S=&TempString[0];

   Laenge=stci_d(&TempString,Zahl);

   while (*S!=0)
      S++;

   i=1;

   do {
      S--;
      if ( (i==4) || (i==8) || (i==12) || (i==15) ) {
         ResultString[i-1]='.';
         i++;
         Laenge++;
      }
      ResultString[i-1]=*S;
      i++;
   } while (S!=&TempString[0]);
 
   if (Laenge<Stellen) {
      Laenge=Stellen-Laenge;
      for (t=0;t<Laenge;t++) {
         ResultString[i-1]=' ';
         i++;
      }
   }

   ResultString[i-1]=0;
   strrev(&ResultString);
   printf(&ResultString);
}

static BOOL CheckAllowed(void)
{
   struct HiddenData	*UserNode;
   BOOL			ReturnCode=FALSE;
   char			User[15];

   if (GetVar("EazyUsername",&User,15,0)==-1)
      return TRUE;

   if (!Cfg.AllowedUser) {
      ReturnCode=TRUE;
   }
   else {
      UserNode = (struct HiddenData*) Cfg.AllowedUser->lh_Head;
      while (UserNode->node.ln_Succ) {
         if (!stricmp(&UserNode->String,&User))
            ReturnCode=TRUE;
         if (!strcmp(&UserNode->String,"*"))
            ReturnCode=TRUE;
         UserNode = (struct HiddenData*) UserNode->node.ln_Succ;
      }
   }

   if (Cfg.ForbiddenUser) {
      UserNode = (struct HiddenData*) Cfg.ForbiddenUser->lh_Head;
      while (UserNode->node.ln_Succ) {
         if (!stricmp(&UserNode->String,&User))
            ReturnCode=FALSE;
         UserNode = (struct HiddenData*) UserNode->node.ln_Succ;
      }
   }
   return ReturnCode;
}
