//================================================================================
// PROGRAM: ULC (Updater / Last Callers)
// VERSION: v1.2
//COMPILER: Lattice C v5.10b
//    DATE: Oct 25, 1992
//================================================================================

//**********************
//*****  Includes  *****
//**********************

#include <proto/all.h>
#include <stdio.h>
#include <time.h>

#include <string.h>
#include <skeleton/commas.h>
#include <tempest/headers.h>
#include <tempest/Skel-Current.h>
#include <tempest/Skel-Data.h>

void OutPut(int,int);
void CurrentDay(int,int);
void NewDay(void);



//*********************
//*****  Structs  *****
//*********************

struct LastCallers
{
 char   Name[32],Location[32];
 BYTE   NodeLastOn;
 USHORT UL,DL,CallsToday,NewUser,Send,Slot_Number;
 long   DB,UB,TDB,TUB,Time_Last_On,Time_Last;
};

char *mon[]={ "Jan","Feb","Mar","Apr","May","Jun",
              "Jul","Aug","Sep","Oct","Nov","Dec" };

struct Current Current;
struct SKEL SKEL;

struct User    User;
struct Today   Today;
struct LastCallers Last[15];

//*********************
//*****  Globals  *****
//*********************

char DateString[15],OUTPATH[255],shit1[255],Outname[255];
int  Day,Test=0,TodayUFiles,TodayDFiles,TodayNewUsers,stat,
     TotalUsers,TodayCalls,TodayMessages,TodayBusy,TodayNewUsers;
long TotalCalls,TotalMessages,TotalDL,TotalUL,TodayULKB,TodayDLKB,
     TotalULKB,TotalDLKB;

//******************
//*****  Main  *****
//******************

void main(int argc,char *argv[])
{
 register int i=1,j=2,m=2,x=0,y,RANK=12,NODES;
 int HOLDER,Day,Month,Year,stat,fd,UserDay;
 char namen[80],string[255],string1[50],RMonth[50];

 struct tm *zt;
 time_t just;
 time(&just);
 zt   = localtime(&just);
 Day  = zt->tm_mday;
 Month= zt->tm_mon + 1;
 Year = zt->tm_year;
 strcpy(RMonth,mon[Month-1]);
 sprintf(DateString,"%2d%2d%d",Day,Month,Year);
 NODES = argc - 2;

//***********************
//*****  Interface  *****
//***********************

 sprintf(shit1,"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"");
 if(argc!=4)
  {
   puts("\n[m[1m    _______ _________");
   puts("   / ___/ [4m/[m[1m/ / ___/ /    [[32mSKEL-ULC v2.0[m[1m] - [3mUpdater/Last Callers[m");
   puts("[1m  [4m/[m[1m__  /   _/ ___/ [4m/[m[1m__");
   puts("[1m [4m/[m[1m____[4m/[m[1m_/\\_[4m)[m[1m____[4m/[m[1m____/   For Tempest BBS - [Programmer: Michael Bockert]");
   puts(shit1);
   puts("[m   USAGE: SKEL-ULC [#Nodes] [OutFile] [SetupDir Path]");
   puts(" EXAMPLE: SKEL-ULC 5 RAM:Test TEMPEST:");
   puts(" [#Nodes] Number of Nodes\n");
   puts("[OutFile] Path of Last Callers Output File\n");
   puts("  [Setup] Path to Setup Directory");
   exit(0);
  }
 NODES=atoi(argv[1]);
 strcpy(OUTPATH,argv[2]);

//************************************
//*****  Load Skel-Current.Data  *****
//************************************

  fd=Open("S:SKEL-Current.Data",MODE_OLDFILE);
  if(fd==0)
     Test = 1;
  else
   {
    stat=Read(fd,(char *)&Current, sizeof(struct Current));
    if(stat!=sizeof(struct Current))
     {
      Close(fd);
      puts("\nWrong Current.Data in S:, Delete It\n");
      exit(0);
     }
   }
  Close(fd);

//*************************************
//*****  Load Runtime.Data Files  *****
//*************************************

 do
  {
   sprintf(namen,"%sSetup/Runtime-%d.data",argv[3],i);
   fd=Open(namen,MODE_OLDFILE);
   if(fd==0)
    {
     puts("\nA Runtime.Data file was not found!\n");
     exit(0);
    }
   Read(fd,(char *)&Today, sizeof(struct Today));
   Close(fd);
   TodayBusy     += Today.Busy;
   TodayNewUsers += Today.New;
   TotalCalls    += Today.Total;
   i++;
  }
 while(i<NODES+1);

//**************************************
//*****  Load Skel-Data.Data  **********
//**************************************

 sprintf(Outname,"%sSetup/Skel-Data.Data",argv[3]);
 fd=Open(Outname,MODE_OLDFILE);
 if(fd!=0)
  {
   Read(fd,(char *)&SKEL, sizeof(struct SKEL));
   Close(fd);
  }

//********************************
//*****  Load Accounts.Data  *****
//********************************

 sprintf(string,"%sAccounts.data",argv[3]);
 fd=Open(string,MODE_OLDFILE);
 Read(fd,(char *)&User, sizeof(struct User));
 do
  {
   if(User.Slot_Number != 0)
    {
     if(Test == 1)
      {
       TotalMessages += User.Total_Posts;
       TotalUL   += User.Total_ULFiles;
       TotalDL   += User.Total_DLFiles;
       TotalULKB += ((User.Total_ULBytes + 1L) / 1024L);
       TotalDLKB += ((User.Total_DLBytes + 1L) / 1024L);
      }
     TotalUsers ++;
     strcpy(string,ctime(&User.Time_Last_Connect));
     strmid(string,string1,9,2);
     UserDay   = atoi(string1);
     strmid(string,string1,5,3);
     if( (strcmp(string1,RMonth)==0) && (UserDay == Day) )
      {
       TodayCalls    += User.Period_Calls;
       TodayMessages += User.Period_Posts;
       TodayUFiles   += User.Period_ULFiles;
       TodayULKB     += ((User.Period_ULBytes + 1L) / 1024L);
       TodayDFiles   += User.Period_DLFiles;
       TodayDLKB     += ((User.Period_DLBytes + 1L) / 1024L);
      }
     if(User.Slot_Number < 2)
        goto DONE;
    }
   x=0;
   do
    {
     if(User.Time_Last_Connect >= Last[x].Time_Last)
      {
       HOLDER = x;
       y=0;
       do
        {
         y++;
         CopyMem((char *)&Last[RANK-(y+1)],(char *)&Last[RANK-y],sizeof(struct LastCallers));
         x++;
        }
       while(x+1<RANK);
       x=HOLDER;
       strcpy(Last[x].Name,User.Name);
       strcpy(Last[x].Location,User.City);
       Last[x].UL           = User.Period_ULFiles;
       Last[x].DL           = User.Period_DLFiles;
       Last[x].TDB          = User.Total_DLBytes;
       Last[x].TUB          = User.Total_ULBytes;
       Last[x].CallsToday   = User.Period_Calls;
       if(User.Status==2) Last[x].NewUser=1;
       else               Last[x].NewUser=0;
       Last[x].Send         = User.Period_Posts;
       Last[x].Time_Last_On = User.Time_Last_Logoff;
       Last[x].Time_Last    = User.Time_Last_Connect;
       Last[x].NodeLastOn   = User.NodeLastOn;
       Last[x].Slot_Number  = User.Status;
       goto DONE;
      }
     x++;
    }
   while(x<RANK);

   DONE:
   stat=Read(fd,(char *)&User, sizeof(struct User));
  }
 while(stat > 0);
 Close(fd);
 OutPut(NODES,RANK);

//**************************
//*****  Updater Part  *****
//**************************

 if(Test == 1)
  {
   CurrentDay(NODES,Day);
   NewDay();
   puts("\nRemember! Some stats are creaetd after midnight tonight!\n");
  }
 else
  {
   if(Day == Current.Day)
    {
     CurrentDay(NODES,Day);
    }
   else
    {
     NewDay();
     CurrentDay(NODES,Day);
    }
  }
 puts("\nSKEL-ULC Done!\n");
 exit(0);
}

//********************
//*****  Output  *****
//********************

void OutPut(int NODES,int RANK)
{
 register int x=0,Connected;
 char  time[180],Connected1[40],Ratio2[40],ampm[15],node[25],
       Activity2[80],string[255];
 float Ratio;
 FILE *out2;
 out2=fopen(OUTPATH,"w");
 if(out2==NULL)
  {
   puts("Error writing output file!\n");
   exit(0);
  }

 fprintf(out2,"\f~+[33m[[31mSKEL-ULC v2.0[33m] [36mLast Callers for [33m[ [31m%d[33m] [36mNode(s)     By Michael Bockert [33m[[31m12-28-93[33m]\n",
                       NODES);
 fprintf(out2,"[34m%s\"\"\"\"\"\"\"\n",shit1);
 fprintf(out2," [32mConnect Min Ratio CT  Acts Node Alias/Handle         Location/Group\n");
 fprintf(out2,"[34m========-===-=====-==-=====-====-====================-=========================\n");
 do
  {
   strcpy(string,ctime(&Last[x].Time_Last));
   strmid(string,time,12,5);
//***************************
//*****  Convert AM/PM  *****
//***************************
   strcpy(ampm," pm");
   if((time[0] == '1') && (time[1] != '0') && (time[1] != '1'))
    {
     time[0] = ' ';
     if(time[1] == '2') time[0] = '1';
     else if(time[1] == '3') time[1] = '1';
       else if(time[1] == '4') time[1] = '2';
         else if(time[1] == '5') time[1] = '3';
           else if(time[1] == '6') time[1] = '4';
             else if(time[1] == '7') time[1] = '5';
               else if(time[1] == '8') time[1] = '6';
                 else if(time[1] == '9') time[1] = '7';
    }
   else
    {
     if(time[0] == '2')
      {
       if(time[1] == '0') { time[0] = ' '; time[1] = '8'; }
       else if(time[1] == '1') { time[0] = ' '; time[1] = '9'; }
         else if(time[1] == '2') { time[0] = '1'; time[1] = '0'; }
           else if(time[1] == '3') { time[0] = '1'; time[1] = '1'; }
      }
     else
      {
       ampm[1]='a';
       if((time[0] == '0') && (time[1] == '0')) { time[0] = '1'; time[1] = '2'; }
       else
         if(time[0] != '1') time[0] = ' ';
      }
    }
   Connected = ((Last[x].Time_Last_On - Last[x].Time_Last)/60)+1;
   sprintf(Connected1,"%d",Connected);
//*****************************
//*****  Figure Activity  *****
//*****************************
   if(Last[x].NewUser > 0)
    {
     strcpy(Activity2,"=New=");
     strcpy(Ratio2,"[35m -.--");
     goto PRINT;
    }
   else
    {
     if(Last[x].Slot_Number== 0)
      {
       strcpy(Activity2,"=DEL=");
       strcpy(Ratio2,"[35m -.--");
       goto PRINT;
      }
     else
      {
       strcpy(Activity2,"-[34m-[32m-[34m-[32m-");
       if(Last[x].UL > 0)   Activity2[0]  = 'U';
       if(Last[x].DL > 0)   Activity2[12] = 'D';
       if(Last[x].Send > 0) Activity2[24] = 'P';
      }
    }
   if(Connected < 0)
      strcpy(Connected1,"n/a");
//**************************
//*****  Figure Ratio  *****
//**************************
   Ratio = (float) (Last[x].TDB+1) / (Last[x].TUB+1);
   if((Ratio>10.00) || (Last[x].TDB < 1000000L) && (Last[x].TUB < 1000000L))
      strcpy(Ratio2,"[35m -.--");
   else
    {
     if(Ratio>3.00)
        strcpy(Ratio2,"[34mLEECH");
     else
      {
       if( (Ratio < 0.16) && (Ratio >= 0.00) && (Last[x].TUB >= 5000000L) )
           strcpy(Ratio2,"[33mELITE");
       else
           sprintf(Ratio2,"%4.2f",Ratio);
      }
    }
   if(Last[x].NodeLastOn<0) Last[x].NodeLastOn=0;
   if(Last[x].NodeLastOn>99) Last[x].NodeLastOn=0;
   if(Last[x].NodeLastOn<10) sprintf(node,"0%d",Last[x].NodeLastOn);
   else                      sprintf(node,"%d" ,Last[x].NodeLastOn);

   PRINT:

   fprintf(out2,"[33m%s[35m%s [32m%3s [36m%5s [35m%2d [32m%s  [33m%2s  [36m%-20.20s [31m%-25.25s\n",
      time,ampm,Connected1,Ratio2,Last[x].CallsToday,Activity2,node,Last[x].Name,Last[x].Location);
   x++;
  }
 while(x<RANK);
 fprintf(out2,"\n[33m[[31mTODAY[33m]   [32mMins Busy [33m[[0m%4d[33m]   [32mTotal Calls [33m[[0m%7.7s[33m]   [[31mY-DAY[33m]   [32mMins Busy [33m[[0m%4d[33m]\n",
                                     TodayBusy,commas(SKEL.TotalCalls,buff),SKEL.HBusy[1]);
 fprintf(out2,"[32mCalls [33m[[0m%3d[33m] [32mMessages [33m[[0m%3d[33m]    [32mTotal Msgs [33m[[0m%7s[33m]   [32mCalls [33m[[0m%3d[33m] [32mMessages [33m[[0m%3d[33m]\n",
               TodayCalls,TodayMessages,commas(SKEL.TotalMessages,buff),SKEL.HCalls[1],SKEL.HMessages[1]);
 fprintf(out2,"[32mUL's  [33m[[0m%3d[33m] / [[0m%7s[33m] [32mkb   [32mTotal Users     [33m[[0m%3d[33m]   [32mUL's  [33m[[0m%3d[33m] / [",
                      TodayUFiles,commas(TodayULKB,buff),TotalUsers,SKEL.HUL[1]);
 fprintf(out2,"[0m%7.7s[33m] [32mkb\n",commas(SKEL.HULKB[1],buff));
 fprintf(out2,"[32mDL's  [33m[[0m%3d[33m] / [[0m%7s[33m] [32mkb     New Users      [33m[[0m%2d[33m]   [32mDL's  [33m[[0m%3d[33m] / [",
               TodayDFiles,commas(TodayDLKB,buff),TodayNewUsers,SKEL.HDL[1]);
 fprintf(out2,"[0m%7s[33m] [32mkb\n",commas(SKEL.HDLKB[1],buff));
 fprintf(out2,"[34m%s\"\"\"\"\"\"\"[0m~r\n",shit1);
 fclose(out2);
}

//**************************
//**************************
//*****  Current Day!  *****
//**************************
//**************************

void CurrentDay(int NODES,int Day)
{
 register int fd;

 Current.Calls      = TodayCalls;
 Current.Messages   = TodayMessages;
 Current.Busy       = TodayBusy;
 Current.NewUsers   = TodayNewUsers;
 Current.UL         = TodayUFiles;
 Current.ULKB       = TodayULKB;
 Current.DL         = TodayDFiles;
 Current.DLKB       = TodayDLKB;
 Current.Users      = TotalUsers;
 Current.Nodes      = NODES;
 Current.Day        = Day;
 strcpy(Current.Date,DateString);

//*************************************
//*****  Write Skel-Current.Data  *****
//*************************************

 fd=Open("S:Skel-Current.Data",MODE_NEWFILE);
 if(fd==0)
  {
   puts("Error writing S:Skel-Current.Data\n");
   exit(0);
  }
 Write(fd,(char *)&Current, sizeof(struct Current));
 Close(fd);
}

//**********************
//**********************
//*****  New Day!  *****
//**********************
//**********************

void NewDay()
{
 register int i,j,fd;

 if(Test != 1)
  {
//******************************
//*****  Get History Data  *****
//******************************
   i = 29;
   j = 30;
   do
    {
     SKEL.HCalls[j]     = SKEL.HCalls[i];
     SKEL.HMessages[j]  = SKEL.HMessages[i];
     SKEL.HBusy[j]      = SKEL.HBusy[i];
     SKEL.HNewUsers[j]  = SKEL.HNewUsers[i];
     SKEL.HUL[j]        = SKEL.HUL[i];
     SKEL.HULKB[j]      = SKEL.HULKB[i];
     SKEL.HDL[j]        = SKEL.HDL[i];
     SKEL.HDLKB[j]      = SKEL.HDLKB[i];
     strcpy(SKEL.HDate[j],SKEL.HDate[i]);
     i--;
     j--;
    }
   while(i > 0);

//**********************************
//*****  Get Yesterday's Data  *****
//**********************************

   SKEL.HCalls[1]     = Current.Calls;
   SKEL.HMessages[1]  = Current.Messages;
   SKEL.HBusy[1]      = Current.Busy;
   SKEL.HNewUsers[1]  = Current.NewUsers;
   SKEL.HUL[1]        = Current.UL;
   SKEL.HULKB[1]      = Current.ULKB;
   SKEL.HDL[1]        = Current.DL;
   SKEL.HDLKB[1]      = Current.DLKB;
   strcpy(SKEL.HDate[1],Current.Date);

//*****************************
//*****  Get New Records  *****
//*****************************

   if(SKEL.HCalls[1] > SKEL.RCalls)
    {
     SKEL.RCalls = SKEL.HCalls[1];
     strcpy(SKEL.RDates[1],SKEL.HDate[1]);
    }
   if(SKEL.HMessages[1] > SKEL.RMessages)
    {
     SKEL.RMessages = SKEL.HMessages[1];
     strcpy(SKEL.RDates[2],SKEL.HDate[1]);
    }
   if(SKEL.HBusy[1] > SKEL.RBusy)
    {
     SKEL.RBusy = SKEL.HBusy[1];
     strcpy(SKEL.RDates[3],SKEL.HDate[1]);
    }
   if(SKEL.HNewUsers[1] > SKEL.RNewUsers)
    {
     SKEL.RNewUsers = SKEL.HNewUsers[1];
     strcpy(SKEL.RDates[4],SKEL.HDate[1]);
    }
   if(SKEL.HUL[1] > SKEL.RUL)
    {
     SKEL.RUL = SKEL.HUL[1];
     strcpy(SKEL.RDates[5],SKEL.HDate[1]);
    }
   if(SKEL.HULKB[1] > SKEL.RULKB)
    {
     SKEL.RULKB = SKEL.HULKB[1];
     strcpy(SKEL.RDates[6],SKEL.HDate[1]);
    }
   if(SKEL.HDL[1] > SKEL.RDL)
    {
     SKEL.RDL = SKEL.HDL[1];
     strcpy(SKEL.RDates[7],SKEL.HDate[1]);
    }
   if(SKEL.HDLKB[1] > SKEL.RDLKB)
    {
     SKEL.RDLKB = SKEL.HDLKB[1];
     strcpy(SKEL.RDates[8],SKEL.HDate[1]);
    }
//*****************************
//*****  Get Totals Data  *****
//*****************************
   SKEL.TotalCalls    += Current.Calls;
   SKEL.TotalMessages += Current.Messages;
   SKEL.TotalUL       += Current.UL;
   SKEL.TotalDL       += Current.DL;
   SKEL.TotalULKB     += Current.ULKB;
   SKEL.TotalDLKB     += Current.DLKB;
  }
 else
  {
   SKEL.TotalCalls     = TotalCalls;
   SKEL.TotalMessages  = TotalMessages;
   SKEL.TotalUL        = TotalUL;
   SKEL.TotalDL        = TotalDL;
   SKEL.TotalULKB      = TotalULKB;
   SKEL.TotalDLKB      = TotalDLKB;
  }
 SKEL.TotalUsers       = TotalUsers;

//**********************************
//*****  Write Skel-Data.Data  *****
//**********************************

 fd=Open(Outname,MODE_NEWFILE);
 if(fd==0)
  {
   puts("Error writing Skel-Data.Data!\n");
   exit(0);
  }
 Write(fd,(char *)&SKEL, sizeof(struct SKEL));
 Close(fd);
}
