/*
    $Header: Welmat:src/RCS/logproc.c,v 1.8 93/01/23 16:08:40 rwm Exp Locker: rwm $

    Log process routines for Welmat.

    Copyright (C) 1988,1989,1990 Michael Richardson
    Copyright (C) 1992 Russell McOrmond

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <exec/types.h>
#include <proto/all.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <clib/rexxsyslib_protos.h>
#include <pragmas/rexxsyslib_pragmas.h>
#include "listmacros.h"
#include "logproc.h"

struct Library *RexxSysBase;

char *copyParam(args,buffer,len)
char *args,*buffer;
long len;
{
  while(*args==' ') args++; /* scip any blanks */
  if (len) len--; /* always leave room for null termination */
  while(len && *args && (*args!=' ')) {
    *buffer++=tolower(*args);
    args++;
    len--;
  }
  *buffer='\0';
  while(*args==' ') args++; /* scip any trailing blanks */
  return(args);
}

struct logHandle *OpenLogHandle(log,name,file,flags)
struct LogProc *log;
char *name,*file,*flags;
{
  struct logHandleW *myHandleW;
  struct logHandleF *myHandleF;
  char *temp;
  long size=0;

  temp=flags;
  while (*temp) {
    switch (tolower(*temp)) {
      case 'f':
        size=1;
        break;

      case 'w':
        size=0;
        break;
    }
    temp++;
  }

  if(size) {
    size=sizeof(struct logHandleF)+strlen(file);
    if(myHandleF=AllocMem(size,MEMF_CLEAR)) {
      (myHandleF->lh.length)=size;
      strncpy(myHandleF->lh.name,name,LPNAMELEN);
      myHandleF->lh.lplh.ln_Name=myHandleF->lh.name;
      strcpy(myHandleF->filename,file);
      NewList(&myHandleF->logs);
      NewList(&myHandleF->freelogs);
      for (size=0; size<NUMLOGS; size++) {
        AddTail(&myHandleF->freelogs,&myHandleF->logentries[size]);
      }      

#ifdef LOGDEBUG
      SPrintF(log->scratch,"OpenHand: %lx,%s\n",myHandleF,myHandleF->lh.name);
      PutStr(log->scratch);
#endif

      AddTail(&log->logHandles,myHandleF);
      return((struct logHandle *)myHandleF);
    }
  } else if(myHandleW=AllocMem(sizeof(struct logHandleW),MEMF_CLEAR)) {
    if((myHandleW->myFile)=Open(file,MODE_NEWFILE)) {
      myHandleW->lh.length=0;
      strncpy(myHandleW->lh.name,name,LPNAMELEN);
      myHandleW->lh.lplh.ln_Name=myHandleW->lh.name;

#ifdef LOGDEBUG
      SPrintF(log->scratch,"OpenHand: %lx,%s\n",myHandleW,myHandleW->lh.name);
      PutStr(log->scratch);
#endif

      AddTail(&log->logHandles,myHandleW);
      return((struct logHandle *)myHandleW);
    }
    FreeMem(myHandleW,sizeof(struct logHandleW));
  }
  return(NULL);
}

void FlushLogF(handle)
struct logHandleF *handle;
{
  BPTR logfile;
  struct LogEntry *entry;

  logfile=Open(handle->filename,MODE_READWRITE);
  if(logfile) (void) Seek(logfile,0,OFFSET_END);

  FOREACH_LIST_SAFE(&handle->logs,entry)
    if(logfile) {
      FPuts(logfile,entry->buf);
      FPutC(logfile,'\n');
    }
    Remove(entry);
    AddTail(&handle->freelogs,entry);
  END_LIST_SAFE;

  if(logfile) Close(logfile);
}

void CloseLogHandle(log,handle)
struct LogProc *log;
struct logHandle *handle;
 /* 
  * The 'handle' is eithor NULL for 'all' or a log handle for which all 
  * lpSesNode structures should be removed, and the log handle closed.
  */
{
  struct lpSesNode *tempn;
  struct logSession *temps;

  FOREACH_LIST_SAFE(&log->logSessions,temps)
    FOREACH_LIST_SAFE(&temps->logSesNodes,tempn)
      if(!handle || ((tempn->handle)==handle)) {

#ifdef LOGDEBUG
        SPrintF(log->scratch,"Remove-Node: %lx, %s\n",tempn,tempn->lpsn.ln_Name);
        PutStr(log->scratch);
#endif

        Remove(tempn);
        FreeMem(tempn,sizeof(struct lpSesNode));
      }
    END_LIST_SAFE;
    if((temps->logSesNodes.lh_Head->ln_Succ)==NULL) {
      /* If the list is empty, nuke it */
#ifdef LOGDEBUG
      SPrintF(log->scratch,"Remove-Ses: %lx, %s\n",temps,temps->name);
      PutStr(log->scratch);
#endif
      Remove(temps);
      FreeMem(temps,sizeof(struct logSession));
    }
  END_LIST_SAFE;
  if (handle) {
    Remove(handle);

#ifdef LOGDEBUG
    PutStr("Closing:");
    PutStr(handle->name);
    PutStr("\n");
#endif

    if (handle->length) {
      FlushLogF((struct logHandleF *)handle);

#ifdef LOGDEBUG
      SPrintF(log->scratch,"Remove-HandF: %lx\n",handle);
      PutStr(log->scratch);
#endif

      FreeMem(handle,handle->length);
    } else {
      Close(((struct logHandleW *)handle)->myFile);

#ifdef LOGDEBUG
      SPrintF(log->scratch,"Remove-Hand: %lx\n",handle);
      PutStr(log->scratch);
#endif

      FreeMem(handle,sizeof(struct logHandleW));
    }
  }
}

void logRexxMsg(aMsg,log)
struct RexxMsg *aMsg;
struct LogProc *log;
{
  char *temp;

#ifdef LOGDEBUG
  SPrintF(log->scratch,"%lx,%lx, REXX:%s\n",aMsg->rm_TaskBlock,aMsg->rm_LibBase,
            ARG0(aMsg));
  PutStr(log->scratch);
#endif

  temp=copyParam(ARG0(aMsg),log->scratch,SCRATCHLEN);

  if(!stricmp(log->scratch,"abort")) {
    log->aborting=TRUE;
    aMsg->rm_Result1=100;
  } else if(!stricmp(log->scratch,"putlog")) {
    struct logSession *temps;
    struct lpSesNode  *tempn;

    temp=copyParam(temp,log->session,LPNAMELEN);

    if(temps=(struct logSession *)FindName(&log->logSessions,log->session)) {
      FOREACH_LIST_UNSAFE(&temps->logSesNodes,tempn)
        if (tempn->handle->length) {
          struct LogEntry *entry;
          struct logHandleF *handle;

          handle=(struct LogHandleF *)(tempn->handle);
          if ((entry=(struct LogEntry *)RemHead(&handle->freelogs))==NULL) {
            FlushLogF(handle);
            entry=(struct LogEntry *)RemHead(&handle->freelogs);
	  }
          if (entry) {
            strncpy(entry->buf,temp,MAXLOGENTRY-1);
            entry->buf[MAXLOGENTRY-1]='\0';
            AddTail(&handle->logs,entry);
	  }
	} else {
          FPuts(((struct logHandleW *)(tempn->handle))->myFile,temp);
          FPutC(((struct logHandleW *)(tempn->handle))->myFile,'\n');
	}
      END_LIST_UNSAFE;
      aMsg->rm_Result1=0;
    } else
      aMsg->rm_Result1=1;
  } else if(!stricmp(log->scratch,"openlog")) {
    struct logHandle *temph;

    temp=copyParam(temp,log->session,LPNAMELEN);
    temp=copyParam(temp,log->scratch,SCRATCHLEN);
#ifdef LOGDEBUG
    PutStr(temp);
    PutStr("\n");
#endif
    temph=OpenLogHandle(log,log->session,temp,log->scratch);
    aMsg->rm_Result1=(temph) ? 0 : 1;
  } else if(!stricmp(log->scratch,"closelog")) {
    struct logHandle *temph;

    aMsg->rm_Result1=0;
#ifdef LOGDEBUG
    PutStr("ClosLog:");
#endif
    while(strlen(temp)) {
      temp=copyParam(temp,log->session,LPNAMELEN);
#ifdef LOGDEBUG
      PutStr(log->session);
      PutStr("\n");
#endif
      if(temph=(struct logHandle *)FindName(&log->logHandles,log->session)) {
        CloseLogHandle(log,temph);
      } else 
        aMsg->rm_Result1=1;
    }
  } else if(!stricmp(log->scratch,"flushlog")) {
    struct logSession *temps;
    struct lpSesNode *tempn;

    aMsg->rm_Result1=0;
#ifdef LOGDEBUG
    PutStr("FlushLog:");
#endif
    while(strlen(temp)) {
      temp=copyParam(temp,log->session,LPNAMELEN);
#ifdef LOGDEBUG
      PutStr(log->session);
      PutStr("\n");
#endif
      if(temps=(struct logSession *)FindName(&log->logSessions,log->session)) {
        FOREACH_LIST_UNSAFE(&temps->logSesNodes,tempn)
          if(tempn->handle->length)
            FlushLogF((struct logHandleF *)tempn->handle);
        END_LIST_UNSAFE;
      } else 
        aMsg->rm_Result1=1;
    }
  } else if(!stricmp(log->scratch,"addlogses")) {
    struct logHandle *temph;
    struct logSession *newtemps;
    struct logSession *temps;
    struct lpSesNode  *tempn;

    temp=copyParam(temp,log->session,LPNAMELEN);
    if((temps=(struct logSession *)FindName(&log->logSessions,log->session))
       || (newtemps=AllocMem(sizeof(struct logSession),MEMF_CLEAR))) {
      if (!temps) {
#ifdef LOGDEBUG
        PutStr("Making new logsession\n");
#endif
        strncpy(newtemps->name,log->session,LPNAMELEN);
        newtemps->lpls.ln_Name=newtemps->name;
        NewList(&newtemps->logSesNodes);
        AddTail(&log->logSessions,newtemps);
        temps=newtemps;
      }
      aMsg->rm_Result1=0;
      while(strlen(temp)) {
        temp=copyParam(temp,log->scratch,LPNAMELEN);
#ifdef LOGDEBUG
        PutStr(log->scratch);
        PutStr("\n");
#endif
        if(temph=(struct logHandle *)FindName(&log->logHandles,log->scratch)) {
          if(tempn=AllocMem(sizeof(struct lpSesNode),MEMF_CLEAR)) {
#ifdef LOGDEBUG
            PutStr("Added...\n");
#endif
            tempn->lpsn.ln_Name=temph->name;
            tempn->handle=temph;
            AddTail(&temps->logSesNodes,tempn);
	  }
        } else
          aMsg->rm_Result1=1; /* one or more could not be found */
      }
    }
  } else if(!stricmp(log->scratch,"remlogses")) {
    struct logSession *temps;
    struct lpSesNode  *tempn;

    temp=copyParam(temp,log->session,LPNAMELEN);
    if(temps=(struct logSession *)FindName(&log->logSessions,log->session)) {
      aMsg->rm_Result1=0;
      while(strlen(temp)) {
        temp=copyParam(temp,log->scratch,LPNAMELEN);
#ifdef LOGDEBUG
        PutStr(log->scratch);
        PutStr("\n");
#endif
        if(tempn=(struct lpSesNode *)FindName(&temps->logSesNodes,log->scratch)) {
#ifdef LOGDEBUG
          PutStr("Removed...\n");
#endif
          Remove(tempn);
          FreeMem(tempn,sizeof(struct lpSesNode));
	}
      }
    } else
     aMsg->rm_Result1=1; /* couldn't find session */
  } else {
    aMsg->rm_Result1=99;
  }
  aMsg->rm_Result2=NULL;
  ReplyMsg(aMsg);
}

main(int argc,char **argv)
{
  struct LogProc *log;
  BOOL didforbid;
  struct Process *me;
  struct Message *aMsg;
  struct MsgPort *thisPort;
#ifdef LOGDEBUG
  BPTR oldfile,newfile;

  newfile=Open("raw:580/0/150/100/Debug",MODE_NEWFILE);
  if (newfile) oldfile=SelectOutput(newfile);

  PutStr("DEBUG Log Ready\n");
#endif

  Forbid();

  if(!FindPort("WELMATLOG") && (thisPort=CreatePort("WELMATLOG",0)) && 
      (RexxSysBase = OpenLibrary("rexxsyslib.library", 0L)) && 
      (log=AllocMem(sizeof(struct LogProc),MEMF_CLEAR))) {
    me=(struct Process *)FindTask(NULL);

    Permit();

#ifdef LOGDEBUG
    PutStr("Log Port Opened...");
#endif

    log->PublicPort=thisPort;
    me->pr_WindowPtr=(APTR)-1;   /* kill requestors */

#ifdef LOGDEBUG
    SPrintF(log->scratch,"Log:%lx(%ld)\n",log,sizeof(struct LogProc));
    PutStr(log->scratch);

    SPrintF(log->scratch,"LogHandleF(%ld) LogHandle(%ld)\n",sizeof(struct logHandleF)
                   ,sizeof(struct logHandle));
    PutStr(log->scratch);

    SPrintF(log->scratch,"LogSession(%ld)\n",sizeof(struct logSession));
    PutStr(log->scratch);
#endif

    NewList(&log->logHandles);
    NewList(&log->logSessions);
    didforbid=(log->aborting)=FALSE;

#ifdef LOGDEBUG
    PutStr("Ready\n");
#endif

    while(!didforbid /* (log->aborting) */) {
      WaitPort(log->PublicPort);
      while(aMsg=GetMsg(log->PublicPort)) {
        if(IsRexxMsg((struct RexxMsg *)aMsg)) {
          if(log->aborting) {

#ifdef LOGDEBUG
            PutStr("Aborting....\n");
#endif
            ((struct RexxMsg *)aMsg)->rm_Result1=100;
            ((struct RexxMsg *)aMsg)->rm_Result2=NULL;
            ReplyMsg(aMsg);
            if (!didforbid) {
              Forbid();
              didforbid=TRUE;
            }
          } else {
            logRexxMsg((struct RexxMsg *)aMsg,log);
          }
        } else {

#ifdef LOGDEBUG
          PutStr("Wasn't a REXX message? Bad...Bad..!!\n");
#endif
          ReplyMsg(aMsg); /* Let's hope this is legal */
        }
      }
    }
    DeletePort(log->PublicPort);
    Permit();
    CloseLogHandle(log,NULL); /* clear out all log sessions */
    {
      struct logHandle *temph;
      FOREACH_LIST_SAFE(&log->logHandles,temph)
        CloseLogHandle(log,temph);
      END_LIST_SAFE;
    }
    FreeMem(log,sizeof(struct LogProc));
  } else
   Permit();

#ifdef LOGDEBUG
  if (newfile) {
     newfile=SelectOutput(oldfile);
     Close(newfile);
  }
#endif
  return;
}
