
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>

#ifdef __SASC
int CXBRK(void) { return(0); }
int _CXBRK(void) { return(0); }
void chkabort(void) {}
#endif

#include <HBBS/ANSI_Codes.h>
#include <HBBS/Defines.h>
#include <HBBS/types.h>
#include <HBBS/structures.h>
#include <HBBS/hbbscommon_protos.h>
#include <HBBS/hbbscommon_pragmas.h>
#include <HBBS/Hbbsnode_protos.h>
#include <HBBS/Hbbsnode_pragmas.h>

/* hbbs variables */
struct Library *HBBSCommonBase=NULL;
struct BBSGlobalData *BBSGlobal=NULL;
char outstr[1024];


/* lastcaller variables */

struct CallerNode
{
  struct Node node; // ->ln_Name contains the handle..
  char Group[LEN_GROUP];
  V_BIGNUM NodeNum;
  char OnTime[LEN_TIMESTR];
  char OffTime[LEN_TIMESTR];
  char Date[LEN_DATESTR];
  char Actions[LEN_ACTIONS];
  char Speed[MAX_CPSBAUD_LEN+1];

};

struct List *CallerList;



static VOID cleanup(ULONG num)
{
  if (HBBSCommonBase)
  {
    HBBS_CleanUpCommon();
    CloseLibrary (HBBSCommonBase);
  }

  if (num) printf("Door Error = %d\n",num);

  exit(0);
}

static VOID init(char *name)
{
  if(!(HBBSCommonBase = OpenLibrary("HBBSCommon.library",0)))
  {
    cleanup(1);
  }

  if (!(HBBS_InitCommon()))
  {
    cleanup(2);
  }

  SetProgramName(name);
}

void DisplayHelp( void )
{
  puts("LastCallers - Witten by Hydra/LSD\n\n"
       "Usage:\n\n"
       "LastCallers <outputfile> <#users> [ALLNODES|<nodenum>] [ConfigFile=<ConfigFile>]\n\n"
       "e.g.\n\n"
       "LastCallers HBBS:Nodes/Node1/Screens/Special/LastCallers.TXT 20 ConfigFile=Progdir:LastCallers.CFG\n\n");
}

#define bufferlen 1024

void AddCallersToList( LONG NodeNum,LONG Users)
{
  // read callers log and add upto <Users> nodes to the list..

  struct CallerNode *Caller;

  BPTR FH;
  struct NodeData *nd;
  LONG UsersAdded=0,from,to;
  UBYTE buffer[bufferlen];
  char *strptr;
  UBYTE tmpstr[1024];

  char LastActions[LEN_ACTIONS]="";
  char OffTime[LEN_TIMESTR]="";

  nd=(struct NodeData*)GetNode(BBSGlobal->NodeList,NodeNum);

  if (FH=Open(nd->NodeSettings.CallersLogFile,MODE_OLDFILE))
  {
    if (Seek(FH,0,OFFSET_END)!=-1)
    {
      while (UsersAdded<Users && FGetsR(FH,buffer,bufferlen))
      {
        stripcr(buffer);
        if (buffer[0])
        {
          if (strstr(buffer,"User logged in"))
          {
            // ooh, we got some details!
            if (strptr=strstr(buffer,"Handle: "))
            {
              from=(strptr-buffer)+8;
              if (strptr=strstr(buffer,"Group: "))
              {
                to=strptr-buffer-2;
                strftcpy(tmpstr,buffer,from,to);

                if (Caller=(struct CallerNode *)HBBS_CreateNode(tmpstr,sizeof(struct CallerNode)))
                {
                  from=to+7;
                  if (strptr=strstr(buffer,"Speed: "))
                  {
                    to=strptr-buffer-2;
                    strftcpy(Caller->Group,buffer,from,to);

                    strfcpy(Caller->Speed,buffer,to+7);

                    strcpy(Caller->Actions,LastActions);
                    strcpy(Caller->OffTime,OffTime);
                    strNcpy(Caller->Date,buffer,11);

                    AddTail(CallerList,(struct Node*)Caller);
                  }
                  else
                  {
                    HBBS_FreeNode((struct Node*)Caller,FALSE);
                  }
                }
              }
            }
          }
          if (strptr=strstr(buffer,"Actions:"))
          {
            strcpy(LastActions,strptr+9); // +9 to skip the actions: string itself..
            strftcpy(OffTime,buffer,12,19); //copy the time
          }
        }
      }
    }
    else
    {
      printf("error seeking into callers log for node %ld\n",NodeNum);
    }
  }

}

void SaveList(LONG Users,char *filename)
{

  // sort the list and save the first <Users> nodes into <filename>

  struct CallerNode *Caller;
  LONG Callers,loop;
  char tmpstr[1024];

  Callers=HBBS_NodesInList(CallerList);

  for (loop=0;loop<Callers;loop++)
  {
    Caller=(struct CallerNode *)GetNode(CallerList,loop);

    strNcpy(tmpstr,Caller->OnTime,5);
    printf("%ld %ld %-6s %-25s %30s %s\n",loop,Caller->NodeNum,Caller->Speed,Caller->node.ln_Name,Caller->Group,tmpstr);
  }
}

int main(int argc,char *argv[])
{
  LONG loop,Users;

  init("LastCallers");

  if (BBSGlobal=HBBS_GimmeBBS())
  {
    if (argc>=2)
    {
      if (argv[1][0]=='?')
      {
        DisplayHelp();
      }
      else
      {
        if (argc>=4)
        {
          if (CallerList=HBBS_CreateList())
          {
            if (sscanf(argv[2],"%ld",&Users) && Users)
            {
              if (stricmp(argv[3],"ALLNODES")==0)
              {
                for (loop=0;loop<BBSGlobal->BBSNodes;loop++)
                {
                  AddCallersToList(loop,Users);
                }
              }
              else
              {
                if (sscanf(argv[3],"%ld",&loop) && loop>=0 && loop<BBSGlobal->BBSNodes)
                {
                  AddCallersToList(loop,Users);
                }
                else printf("invalid parameter %s\n",argv[3]);
              }

              if (HBBS_NodesInList(CallerList))
              {
                SaveList(Users,argv[1]);
              }
              else
              {
                puts("cannot find and info in the caller logs! (or out of mem!)");
              }

            }
            else printf("invalid parameter %s\n",argv[2]);

            FreeStrList(CallerList);
          }
        }
        else
        {
          puts("Not enough arguments! (you should shout louder at your mum!)");
          DisplayHelp();
        }
      }
    }
    else
    {
      DisplayHelp();
    }
  }
  else
  {
    puts("Control must be running!! This util requires access to runtime data!");
  }
  cleanup(0);
}
