/* Reset.server (c) 1997 Paweî Marciniak <pmarciniak@lodz.home.pl>*/
/* Wersja finaîowa Poniedziaîek 13-Kwi-98    16:17:45 */

#include <stdio.h>
#include <string.h>
#include <exec/execbase.h>
#include <exec/semaphores.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <devices/keyboard.h>
#include <exec/interrupts.h>

#include <stdlib.h>

#include "ResetServer_globals.h"
#include "ResetServer.h"

#include	"ResetServer_rev.h"
static	UBYTE	verstr[]={ VERSTAG };

char __stdiowin[]="CON:10/10/600/240/Reset.server/CLOSE/WAIT/AUTO";

extern struct ExecBase *SysBase;

struct List PortList;

struct MsgPort *serverport;
struct MsgPort *ioport;
struct IOStdReq *ioreq;
struct SignalSemaphore sem;

ULONG sig=0L;
ULONG sigmsg=0L;


/* Tytaj zaczynajâ sië wszystkie poûyteczne funkcje */

void __asm ResetFunction( register __a1 struct List * );
struct Interrupt intserver = { {0, 0, 0, 0, 0 }, &PortList, (void (*)())ResetFunction };

void AddHandler( void )
{
  ioreq->io_Command=KBD_ADDRESETHANDLER;
  ioreq->io_Data=&intserver;
  DoIO ((struct IORequest *)ioreq);
}

void HandlerDone( void )
{
  Delay(50);
  ioreq->io_Command=KBD_RESETHANDLERDONE;
  ioreq->io_Data=&intserver;
  ioreq->io_Length = sizeof(struct Interrupt);
  DoIO ((struct IORequest *)ioreq);
}


/* Funkcje Reset.server */
void SendWarning( struct List *portlist )
{
  struct RWNode *node;
  struct RWMessage *WarnMsg;

  ObtainSemaphore( &sem );
  if( IsListEmpty( &PortList ) )
    HandlerDone();
  else
  {
	  for( node=(struct RWNode *)portlist->lh_Head; node->rwn_Node.ln_Succ; node=(struct RWNode *)node->rwn_Node.ln_Succ )
  	{
    	if(node->rwn_MsgPort)
  	  {
			  WarnMsg=(struct RWMessage *)AllocVec( sizeof(struct RWMessage), MEMF_PUBLIC|MEMF_CLEAR );
  			WarnMsg->rwm_Message.mn_ReplyPort=serverport;
 	 			WarnMsg->rwm_MsgType=RWM_RESETWARNING;
  	    PutMsg( node->rwn_MsgPort, (struct Message *)WarnMsg);
    	}
  	}
  }
  ReleaseSemaphore( &sem );
}

void __asm ResetFunction( register __a1 struct List *PortL )
{
	SendWarning( PortL );
}

/* Funkcja dodaje msgport do listy portlist */
int RW_AddPort( struct List *portlist, struct RWMessage *rwmsg )
{
  struct RWNode *node;

  if( node=(struct RWNode *)AllocVec( sizeof(struct RWNode), MEMF_PUBLIC|MEMF_CLEAR ) )
  {
    node->rwn_MsgPort = rwmsg->rwm_MsgPort;
    node->rwn_ProgName = rwmsg->rwm_ProgName;
    node->rwn_Node.ln_Name = rwmsg->rwm_ProgName;
    ObtainSemaphore( &sem );
    AddTail( portlist, (struct Node *)node );
    ReleaseSemaphore( &sem );
    return( TRUE );
  }
  return( FALSE );
}

/* Funkcja usuwa msgport z listy portlist */
void RW_RemPort( struct List *portlist, struct RWMessage *rwmsg )
{
  struct RWNode *node;

  ObtainSemaphore( &sem );
  for( node=(struct RWNode *)portlist->lh_Head; node->rwn_Node.ln_Succ; node=(struct RWNode *)node->rwn_Node.ln_Succ )
  {
    if(node->rwn_MsgPort==rwmsg->rwm_MsgPort)
    {
      Remove( (struct Node *)node );
      FreeVec( node );
      break;
    }
  }
  ReleaseSemaphore( &sem );
}

/* Koniec funkcji Reset.server */


/* Funkcja otwiera wszystkie biblioteki */

LONG OpenLibraries( void )
{
  if ( !(DosBase = (struct DosLibrary *) OpenLibrary((UBYTE *) "dos.library", 37 )))
    return( FALSE );
  if ( !(IntuitionBase = (struct IntuitionBase *) OpenLibrary((UBYTE *) "intuition.library", 37 )))
    return( FALSE );
  return( TRUE );
}


/* Funkcja zamyka wszystkie biblioteki */

void CloseLibraries( void )
{
  if (IntuitionBase)  CloseLibrary( (struct Library *) IntuitionBase );
  if (DosBase)        CloseLibrary( (struct Library *) DOSBase );
}


void ShutDown( void )
{
  if (serverport)
    DeletePort (serverport);
  CloseLibraries();
}

/* Gîówna funkcja */

int main( int argc, char *argv[] )
{
  BOOL running=TRUE;
  WORD error;
  struct RWMessage *msg;

  if(!(OpenLibraries()))
  {
    ShutDown();
    return( FALSE );
  }

  NewList( &PortList );
  InitSemaphore( &sem );

  Forbid();
  if (FindPort( RESETSERVERNAME ))
  {
    Permit();
    printf("Program is already running\n");
    return( FALSE );
  }
  if (!(serverport=CreatePort( RESETSERVERNAME, 5L )))
  {
    Permit();
    printf("Not free mem for port\n");
    return( FALSE );
  }
  Permit();
  sigmsg = 1L << serverport->mp_SigBit;

	if (!(ioport=CreatePort(NULL, 0L)))
	{
		printf("No memory for I/O port\n");
		return(20);
	}

	if (!(ioreq=CreateStdIO(ioport)))
	{
		printf("No memory for IORequest\n");
		return(20);
	}

	if(error=OpenDevice("keyboard.device", 0, (struct IORequest *)ioreq, 0L ))
	{
    printf("Couldn't open keyboard.device\n");
    return(20);
  }

  AddHandler();	
  printf("%s copyright 1993-1998 Paweî Marciniak\nResetServer is starting...\n",VERS);
  
  do
  {
    sig=Wait( sigmsg );

    while( msg=(struct RWMessage *)GetMsg( serverport ))
    {
      switch( msg->rwm_Message.mn_Node.ln_Type )
      {
        case  NT_REPLYMSG:
          switch( msg->rwm_MsgType )
          {
	        	case RWM_RESETWARNING:
              FreeVec( msg );
            break;
          }
        break;

        case  NT_MESSAGE:
          switch( msg->rwm_MsgType )
          {
            case  RWM_ADDPORT:
              RW_AddPort( &PortList, msg );
            break;

            case  RWM_REMPORT:
              RW_RemPort( &PortList, msg );
            break;

            case  RWM_DONE:
              RW_RemPort( &PortList, msg );
              if( IsListEmpty( &PortList ) )
								HandlerDone();
            break;
          }
        ReplyMsg((struct Message *)msg);
        break;
        
        default:
        break;

      }
    } /* while reset serverport */
  } while ( running );

  printf("End\n");
  ShutDown();
  return( TRUE );
}
