/*****************************************************************************
 *                                                                           *
 *  Copyright (c) 1993, 1994, 1995, Elan Feingold (feingold@zko.dec.com)     *
 *                                                                           *
 *     PERMISSION TO USE, COPY, MODIFY, AND TO DISTRIBUTE THIS SOFTWARE      *
 *     AND ITS DOCUMENTATION FOR ANY PURPOSE IS HEREBY GRANTED WITHOUT       *
 *     FEE, PROVIDED THAT THE ABOVE COPYRIGHT NOTICE APPEAR IN ALL           *
 *     COPIES AND MODIFIED COPIES AND THAT BOTH THAT COPYRIGHT NOTICE AND    *
 *     THIS PERMISSION NOTICE APPEAR IN SUPPORTING DOCUMENTATION.  THERE     *
 *     IS NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR      *
 *     ANY PURPOSE.  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS       *
 *     OR IMPLIED WARRANTY.                                                  *
 *                                                                           *
 *****************************************************************************/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include "riskgame.h"
#include "types.h"
#include "network.h"
#include "debug.h"

/* Useful macro */
#define ReturnIfError(foo) if ((foo) <= 0) return (-1);
  
/* Local prototypes */
Int32 _NET_SendCString(Int32 iSocket, CString strCString);
Int32 _NET_SendLong(Int32 iSocket, Int32 iLong);
Int32 _NET_RecvCString(Int32 iSocket, CString *pstrCString);
Int32 _NET_SocketRead(Int32 iSocket, void *ptr, Int32 iNumBytes);
Int32 _NET_SocketWrite(Int32 iSocket, void *ptr, Int32 iNumBytes);
Int32 _NET_RecvLong(Int32 iSocket, Int32 *piLong);


/************************************************************************ 
 *  FUNCTION: NET_SendSyncMessage
 *  HISTORY: 
 *     03.03.94  ESF  Created.
 *     08.03.94  ESF  Fixed to return error message. 
 *  PURPOSE: 
 *  NOTES: 
 *     This procedure assumes that there is no other async. I/O on the
 *    sockets.  You must remove all callbacks you added with XtAddInput,
 *    for example, before calling it.
 ************************************************************************/
Int32 NET_SendSyncMessage(Int32 iSocket, Int32 iSendMessType, void *pvMessage, 
		        Int32 iReturnMessType,
			void (*CBK_MessageReceived)(Int32, void *))
{
  Int32     iMessType;
  void   *pvMess;

  /* Send the message */
  ReturnIfError(NET_SendMessage(iSocket, iSendMessType, pvMessage));

  /* Loop, until we receive the desired message, dispatching all others
   * to the specified callback, which is assumed to be an X type callback,
   * with three pointers passed to it.
   */
  
  for (;;)
    {
      /* This will block when there is no input */
      ReturnIfError(NET_RecvMessage(iSocket, &iMessType, &pvMess));
      
      /* If we received the message we were looking for, 
       * then dispatch it and return finally.
       */
      
      CBK_MessageReceived(iMessType, pvMess);
      NET_DeleteMessage(iMessType, pvMess);

      if (iMessType == iReturnMessType)
	return (1);
    }

  /* For the compiler */
  return (1);
}


/************************************************************************ 
 *  FUNCTION: NET_SendMessage
 *  HISTORY: 
 *     01.24.94  ESF  Created 
 *     01.28.94  ESF  Added strFrom in MSG_MESSAGEPACKET.
 *     03.04.94  ESF  Changed MSG_UPDATE mesage.
 *     03.05.94  ESF  Added MSG_ENTERSTATE for fault tolerance.
 *     03.28.94  ESF  Added MSG_DEADPLAYER & MSG_ENDOFGAME.
 *     03.28.94  ESF  Changed MSG_REQUESTCARDS to ...CARD.
 *     03.29.94  ESF  Changed MSG_UPDATECARDS to MSG_EXCHANGECARDS.
 *     03.29.94  ESF  Changed uiReply to be an Int32.
 *     04.11.94  ESF  Added a player parameter to MSG_CARDPACKET.
 *     04.11.94  ESF  Added a killer paramter to MSG_DEADPLAYER.
 *     05.03.94  ESF  Added MSG_OBJ*UPDATE msgs.
 *     05.03.94  ESF  Removed MSG_REGISTERPLAYER and MSG_UPDATEARMIES.
 *     05.05.94  ESF  Added MSG_OBJ* msgs.
 *     05.12.94  ESF  Removed MSG_OBJ* msgs and added GAME messages.
 *     05.12.94  ESF  Added MSG_DEREGISTERCLIENT.
 *     05.12.94  ESF  Added MSG_DELETEMSGDST.
 *     05.13.94  ESF  Added MSG_STARTREGISTRATION.
 *     05.15.94  ESF  Added MSG_[FREE|ALLOC]PLAYER
 *     05.15.94  ESF  Removed MSG_DEADPLAYER.
 *     05.17.94  ESF  Added MSG_NETMESSAGE.
 *     07.27.94  ESF  Removed MSG_STARTREGISTRATION.
 *     07.31.94  ESF  Added MSG_NETPOPUP.
 *     08.03.94  ESF  Fixed to return error message. 
 *     08.28.94  ESF  Added MSG_POPUPREGISTERBOX.
 *     09.31.94  ESF  Changed MSG_ENDOFGAME to take a string parameter.
 *     10.29.94  ESF  Added MSG_DICEROLL.
 *     10.30.94  ESF  Added MSG_PLACENOTIFY.
 *     10.30.94  ESF  Added MSG_ATTACKNOTIFY.
 *     10.30.94  ESF  Added MSG_MOVENOTIFY.
 *     01.17.95  ESF  Removed MSG_DELETEMSGDST.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 NET_SendMessage(Int32 iSocket, Int32 iMessType, void *pvMessage)
{
  Int32 i;

  /* Send the message ID */
  ReturnIfError(_NET_SendLong(iSocket, (Int32)iMessType));

  switch(iMessType)
    {
    case MSG_REGISTERCLIENT:  
      {
	MsgRegisterClient *pmsgMess = (MsgRegisterClient *)pvMessage;
	
	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strClientAddress));
      }
      break;

    case MSG_EXCHANGECARDS:
      {
	MsgExchangeCards *pmsgMess = (MsgExchangeCards *)pvMessage;
	
	for(i=0; i!=3; i++)
	  ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->piCards[i]));
      }
      break;

    case MSG_CARDPACKET:
      {
	MsgCardPacket *pmsgMess = (MsgCardPacket *)pvMessage;

	ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->iPlayer));
	ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->cdCard));
      }
      break;
      
    case MSG_REPLYPACKET:
      {
	MsgReplyPacket *pmsgMess = (MsgReplyPacket *)pvMessage;

	ReturnIfError(_NET_SendLong(iSocket, (Int32)pmsgMess->iReply));
      }
      break;

    case MSG_SENDMESSAGE:
      {
	MsgSendMessage *pmsgMess = (MsgSendMessage *)pvMessage;

	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strMessage));
	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strDestination));
      } 
      break;

    case MSG_MESSAGEPACKET:
      {
	MsgMessagePacket *pmsgMess = (MsgMessagePacket *)pvMessage;

	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strMessage));
	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strFrom));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iTo));
      }
      break;

    case MSG_TURNNOTIFY:
      {
	MsgTurnNotify *pmsgMess = (MsgTurnNotify *)pvMessage;
	
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iClient));
      }
      break;
      
    case MSG_CLIENTIDENT:
      {
	MsgClientIdent *pmsgMess = (MsgClientIdent *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iClientID));
      }
      break;

    case MSG_REQUESTCARD:
      {
	MsgRequestCard *pmsgMess = (MsgRequestCard *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer));
      }
      break;

    case MSG_ENTERSTATE:
      {
	MsgEnterState *pmsgMess = (MsgEnterState *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iState));
      }
      break;

    case MSG_OBJSTRUPDATE:
      {
	MsgObjStrUpdate *pmsgMess = (MsgObjStrUpdate *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iField));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex1));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex2));
	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strNewValue));
      }
      break;

    case MSG_OBJINTUPDATE:
      {
	MsgObjIntUpdate *pmsgMess = (MsgObjIntUpdate *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iField));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex1));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iIndex2));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iNewValue));
      }
      break;

    case MSG_FREEPLAYER:
      {
	MsgFreePlayer *pmsgMess = (MsgFreePlayer *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iPlayer));
      }
      break;

    /* These happen to be identical, so we can lump them. */  
    case MSG_NETMESSAGE:
    case MSG_NETPOPUP:
      {
	MsgNetMessage *pmsgMess = (MsgNetMessage *)pvMessage;
	ReturnIfError(_NET_SendCString(iSocket, pmsgMess->strMessage));
      }
      break;

    case MSG_ENDOFGAME:
      {
	MsgEndOfGame *pmsgMess = (MsgEndOfGame *)pvMessage;
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iWinner));
      }
      break;

    case MSG_DICEROLL:
      {
	MsgDiceRoll *pmsgMess = (MsgDiceRoll *)pvMessage;

	for (i=0; i!=3; i++)
	  ReturnIfError(_NET_SendLong(iSocket, pmsgMess->pAttackDice[i]));

	for (i=0; i!=3; i++)
	  ReturnIfError(_NET_SendLong(iSocket, pmsgMess->pDefendDice[i]));

	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iDefendingPlayer));
      }
      break;

    case MSG_PLACENOTIFY:
      {
	MsgPlaceNotify *pmsgMess = (MsgPlaceNotify *)pvMessage;

	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iCountry));
      }
      break;

    case MSG_ATTACKNOTIFY:
      {
	MsgAttackNotify *pmsgMess = (MsgAttackNotify *)pvMessage;

	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iSrcCountry));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iDstCountry));
      }
      break;

    case MSG_MOVENOTIFY:
      {
	MsgMoveNotify *pmsgMess = (MsgMoveNotify *)pvMessage;
	
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iSrcCountry));
	ReturnIfError(_NET_SendLong(iSocket, pmsgMess->iDstCountry));
      }
      break;

    case MSG_EXIT:
    case MSG_STARTGAME:
    case MSG_ENDTURN:
    case MSG_GAMENEWPLAYERS:
    case MSG_GAMEMOREPLAYERS:
    case MSG_SAMEPLAYERS:
    case MSG_DEREGISTERCLIENT:
    case MSG_ALLOCPLAYER:
    case MSG_POPUPREGISTERBOX:
      /* No parameters */
      break;

    default:
      printf("NETWORK: Illegal message!\n");
    }

  return (1);
}


/************************************************************************ 
 *  FUNCTION: NET_RecvMessage
 *  HISTORY: 
 *     01.24.94  ESF  Created.
 *     01.27.94  ESF  Fixed bug in MSG_MESSAGEPACKET case.
 *     01.28.94  ESF  Added strFrom in MSG_MESSAGEPACKET.
 *     03.04.94  ESF  Changed _UPDATE mesage.
 *     03.05.94  ESF  Added _ENTERSTATE for fault tolerance.
 *     03.28.94  ESF  Added MSG_DEADPLAYER & MSG_ENDOFGAME.
 *     03.28.94  ESF  Changed MSG_REQUESTCARDS to ...CARD.
 *     03.29.94  ESF  Changed MSG_UPDATECARDS to MSG_EXCHANGECARDS.
 *     03.29.94  ESF  Changed uiReply to be an Int32.
 *     04.11.94  ESF  Added a player parameter to MSG_CARDPACKET.
 *     04.11.94  ESF  Added a killer paramter to MSG_DEADPLAYER.
 *     05.03.94  ESF  Added MSG_OBJ*UPDATE msgs.
 *     05.03.94  ESF  Removed MSG_REGISTERPLAYER and MSG_UPDATEARMIES.
 *     05.05.94  ESF  Added MSG_OBJ* msgs.
 *     05.12.94  ESF  Removed MSG_OBJ* msgs and added GAME messages.
 *     05.12.94  ESF  Added MSG_DEREGISTERCLIENT.
 *     05.12.94  ESF  Added MSG_DELETEMSGDST.
 *     05.13.94  ESF  Added MSG_STARTREGISTRATION.
 *     05.15.94  ESF  Added MSG_[FREE|ALLOC]PLAYER
 *     05.15.94  ESF  Removed MSG_DEADPLAYER.
 *     05.17.94  ESF  Added MSG_NETMESSAGE.
 *     07.27.94  ESF  Removed MSG_STARTREGISTRATION.
 *     07.31.94  ESF  Added MSG_NETPOPUP.
 *     08.03.94  ESF  Fixed to return error message. 
 *     08.28.94  ESF  Added MSG_POPUPREGISTERBOX.
 *     09.31.94  ESF  Changed MSG_ENDOFGAME to take a string parameter.
 *     10.29.94  ESF  Added MSG_DICEROLL.
 *     10.30.94  ESF  Added MSG_PLACENOTIFY.
 *     10.30.94  ESF  Added MSG_ATTACKNOTIFY.
 *     10.30.94  ESF  Added MSG_MOVENOTIFY.
 *     01.17.95  ESF  Removed MSG_DELETEMSGDST.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 NET_RecvMessage(Int32 iSocket, Int32 *piMessType, void **ppvMessage)
{
  Int32 i;

  /* Get the message ID */
  ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)piMessType));

  switch(*piMessType)
    {
    case MSG_REGISTERCLIENT:  
      {
	MsgRegisterClient *pmsgMess = 
	  (MsgRegisterClient *)MEM_Alloc(sizeof(MsgRegisterClient));
	
	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strClientAddress));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_EXCHANGECARDS:
      {
	MsgExchangeCards *pmsgMess = 
	  (MsgExchangeCards *)MEM_Alloc(sizeof(MsgExchangeCards));
	
	for(i=0; i!=3; i++)
	  ReturnIfError(_NET_RecvLong(iSocket, 
				      (Int32 *)&pmsgMess->piCards[i]));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_CARDPACKET:
      {
	MsgCardPacket *pmsgMess = 
	  (MsgCardPacket *)MEM_Alloc(sizeof(MsgCardPacket));

	ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->iPlayer));
	ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->cdCard));

	*ppvMessage = (void *)pmsgMess;
      }
      break;
      
    case MSG_REPLYPACKET:
      {
	MsgReplyPacket *pmsgMess = 
	  (MsgReplyPacket *)MEM_Alloc(sizeof(MsgReplyPacket));

	ReturnIfError(_NET_RecvLong(iSocket, (Int32 *)&pmsgMess->iReply));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_SENDMESSAGE:
      {
	MsgSendMessage *pmsgMess = 
	  (MsgSendMessage *)MEM_Alloc(sizeof(MsgSendMessage));

	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strMessage));
	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strDestination));

	*ppvMessage = (void *)pmsgMess;
      } 
      break;

    case MSG_MESSAGEPACKET:
      {
	MsgMessagePacket *pmsgMess = 
	  (MsgMessagePacket *)MEM_Alloc(sizeof(MsgMessagePacket));

	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strMessage));
	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strFrom));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iTo));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_TURNNOTIFY:
      {
	MsgTurnNotify *pmsgMess = 
	  (MsgTurnNotify *)MEM_Alloc(sizeof(MsgTurnNotify));
	
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iClient));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_CLIENTIDENT:
      {
	MsgClientIdent *pmsgMess = 
	  (MsgClientIdent *)MEM_Alloc(sizeof(MsgClientIdent));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iClientID));
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_REQUESTCARD:
      {
	MsgRequestCard *pmsgMess = 
	  (MsgRequestCard *)MEM_Alloc(sizeof(MsgRequestCard));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer));
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_ENTERSTATE:
      {
	MsgEnterState *pmsgMess = 
	  (MsgEnterState *)MEM_Alloc(sizeof(MsgEnterState));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iState));
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_OBJSTRUPDATE:
      {
	MsgObjStrUpdate *pmsgMess = 
	  (MsgObjStrUpdate *)MEM_Alloc(sizeof(MsgObjStrUpdate));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iField));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex1));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex2));
	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strNewValue));
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_OBJINTUPDATE:
      {
	MsgObjIntUpdate *pmsgMess = 
	  (MsgObjIntUpdate *)MEM_Alloc(sizeof(MsgObjIntUpdate));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iField));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex1));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iIndex2));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iNewValue));
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_FREEPLAYER:
      {
	MsgFreePlayer *pmsgMess = 
	  (MsgFreePlayer *)MEM_Alloc(sizeof(MsgFreePlayer));
	
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iPlayer));
	*ppvMessage = (void *)pmsgMess;
      }
      break;      

    /* These happen to be identical, so we can lump them. */  
    case MSG_NETMESSAGE:
    case MSG_NETPOPUP:
      {
	MsgNetMessage *pmsgMess = 
	  (MsgNetMessage *)MEM_Alloc(sizeof(MsgNetMessage));
	
	ReturnIfError(_NET_RecvCString(iSocket, &pmsgMess->strMessage));
	*ppvMessage = (void *)pmsgMess;
      }
      break;      

    case MSG_ENDOFGAME:
      {
	MsgEndOfGame *pmsgMess = 
	  (MsgEndOfGame *)MEM_Alloc(sizeof(MsgEndOfGame));
	
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iWinner));
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_DICEROLL:
      {
	MsgDiceRoll *pmsgMess = 
	  (MsgDiceRoll *)MEM_Alloc(sizeof(MsgDiceRoll));

    	for (i=0; i!=3; i++)
	  ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->pAttackDice[i]));

    	for (i=0; i!=3; i++)
	  ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->pDefendDice[i]));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iDefendingPlayer));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_PLACENOTIFY:
      {
	MsgPlaceNotify *pmsgMess = 
	  (MsgPlaceNotify *)MEM_Alloc(sizeof(MsgPlaceNotify));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iCountry));
	
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_ATTACKNOTIFY:
      {
	MsgAttackNotify *pmsgMess = 
	  (MsgAttackNotify *)MEM_Alloc(sizeof(MsgAttackNotify));

	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iSrcCountry));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iDstCountry));
	
	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_MOVENOTIFY:
      {
	MsgMoveNotify *pmsgMess = 
	  (MsgMoveNotify *)MEM_Alloc(sizeof(MsgMoveNotify));
		
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iSrcCountry));
	ReturnIfError(_NET_RecvLong(iSocket, &pmsgMess->iDstCountry));

	*ppvMessage = (void *)pmsgMess;
      }
      break;

    case MSG_EXIT:
    case MSG_STARTGAME:
    case MSG_ENDTURN:
    case MSG_GAMENEWPLAYERS:
    case MSG_GAMEMOREPLAYERS:
    case MSG_SAMEPLAYERS:
    case MSG_DEREGISTERCLIENT:
    case MSG_ALLOCPLAYER:
    case MSG_POPUPREGISTERBOX:
      *ppvMessage = NULL;
      break;

    default:
      printf("NETWORK: Illegal message!\n");
    }

  return (1);
}

/************************************************************************ 
 *  FUNCTION: _NET_SendCString
 *  HISTORY: 
 *     01.24.94  ESF  Created. 
 *     08.03.94  ESF  Fixed to return error message. 
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 _NET_SendCString(Int32 iSocket, CString strCString)
{
  D_Assert(strCString!=NULL, "This shouldn't be NULL!");

  /* Send the length and then the string itself */
  ReturnIfError(_NET_SendLong(iSocket, (Int32)(strlen(strCString)+1)));
  return (_NET_SocketWrite(iSocket, (Char *)strCString, 
			   strlen(strCString)+1)); 
}


/************************************************************************ 
 *  FUNCTION: _NET_SendLong
 *  HISTORY: 
 *     01.24.94  ESF  Created 
 *     08.03.94  ESF  Fixed to return error message. 
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 _NET_SendLong(Int32 iSocket, Int32 iLong)
{
  Int32 iData = htonl(iLong);
  
  return (_NET_SocketWrite(iSocket, &iData, sizeof(Int32)));
}


/************************************************************************ 
 *  FUNCTION: _NET_RecvCString 
 *  HISTORY: 
 *     01.24.94  ESF  Created 
 *     08.03.94  ESF  Fixed to return error message. 
 *     01.01.94  ESF  Added check for correct number of bytes read.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 _NET_RecvCString(Int32 iSocket, CString *pstrCString)
{
  Int32    iLength;
  CString  strTemp;
  Int32    iRet;

  /* Receive the length and then the byte stream */
  ReturnIfError(_NET_RecvLong(iSocket, &iLength));
  strTemp = (CString)MEM_Alloc(iLength);
  
  iRet = _NET_SocketRead(iSocket, strTemp, iLength);

  /* Return an error if less than the string was read! */
  if (iRet<0 || iRet!=iLength)
    iRet = -1;

  *pstrCString = strTemp;
  return iRet;
}


/************************************************************************ 
 *  FUNCTION: _NET_RecvLong
 *  HISTORY: 
 *     01.24.94  ESF  Created 
 *     08.03.94  ESF  Fixed to return error message. 
 *     01.01.94  ESF  Added check for correct number of bytes read.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 _NET_RecvLong(Int32 iSocket, Int32 *piLong)
{
  Int32 iRet = _NET_SocketRead(iSocket, piLong, sizeof(Int32));
  
  /* Adjust for the network munging */
  *piLong = ntohl(*piLong);
  
  /* Return an error if read returns an error or if the wrong number
   * of bytes come across -- there should be sizeof(Int32) bytes!
   */
  
  if (iRet<0 || iRet!=sizeof(Int32))
    iRet = -1;

  return iRet;
}


/************************************************************************ 
 *  FUNCTION: 
 *  HISTORY: 
 *     01.1.95  ESF  Created.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 _NET_SocketRead(Int32 iSocket, void *ptr, Int32 iNumBytes)
{
  Int32 iBytesLeft, iRet;

  /* We may have to do multiple read() calls here */
  iBytesLeft = iNumBytes;
  
  while (iBytesLeft > 0)
    {
      iRet = read(iSocket, ptr, iBytesLeft);

      /* If an error occured, return */
      if (iRet < 0)
	return iRet;
      else if (iRet == 0)
	break; /* EOF */
      
      iBytesLeft  -= iRet;
      (Byte *)ptr += iRet;
    }
  
  /* Return the number of bytes read */
  return (iNumBytes - iBytesLeft);
}



/************************************************************************ 
 *  FUNCTION: _NET_RecvLong
 *  HISTORY: 
 *     01.24.94  ESF  Created 
 *     08.03.94  ESF  Fixed to return error message. 
 *     01.01.94  ESF  Added check for correct number of bytes read.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 _NET_SocketWrite(Int32 iSocket, void *ptr, Int32 iNumBytes)
{
  Int32 iBytesLeft, iRet;

  /* We may have to do multiple read() calls here */
  iBytesLeft = iNumBytes;
  
  while (iBytesLeft > 0)
    {
      iRet = write(iSocket, ptr, iBytesLeft);

      /* If an error occured, return */
      if (iRet < 0)
	return iRet;

      iBytesLeft  -= iRet;
      (Byte *)ptr += iRet;
    }
  
  /* Return the number of bytes read */
  return (iNumBytes - iBytesLeft);
}


/************************************************************************ 
 *  FUNCTION: NET_DeleteMessage
 *  HISTORY: 
 *     06.24.94  ESF  Created 
 *     07.31.94  ESF  Added MSG_NETPOPUP.
 *     09.31.94  ESF  Changed MSG_ENDOFGAME to take a string parameter.
 *     10.29.94  ESF  Added MSG_DICEROLL.
 *     10.30.94  ESF  Added MSG_PLACENOTIFY.
 *     10.30.94  ESF  Added MSG_ATTACKNOTIFY.
 *     10.30.94  ESF  Added MSG_MOVENOTIFY.
 *     01.17.95  ESF  Removed MSG_DELETEMSGDST.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void NET_DeleteMessage(Int32 iMessType, void *pvMessage)
{
  switch(iMessType)
    {
    case MSG_REGISTERCLIENT:  
      {
	MsgRegisterClient *pmsgMess = (MsgRegisterClient *)pvMessage;
	MEM_Free(pmsgMess->strClientAddress);
	MEM_Free(pmsgMess);
      }
      break;

    case MSG_EXCHANGECARDS:
      MEM_Free(pvMessage);
      break;

    case MSG_CARDPACKET:
      MEM_Free(pvMessage);
      break;
      
    case MSG_REPLYPACKET:
      MEM_Free(pvMessage);
      break;

    case MSG_SENDMESSAGE:
      {
	MsgSendMessage *pmsgMess = (MsgSendMessage *)pvMessage;

	MEM_Free(pmsgMess->strMessage);
	MEM_Free(pmsgMess->strDestination);
	MEM_Free(pvMessage);
      } 
      break;

    case MSG_MESSAGEPACKET:
      {
	MsgMessagePacket *pmsgMess = (MsgMessagePacket *)pvMessage;

	MEM_Free(pmsgMess->strMessage);
	MEM_Free(pmsgMess->strFrom);
	MEM_Free(pvMessage);
      }
      break;

    case MSG_TURNNOTIFY:
      MEM_Free(pvMessage);
      break;
      
    case MSG_CLIENTIDENT:
      MEM_Free(pvMessage);
      break;

    case MSG_REQUESTCARD:
      MEM_Free(pvMessage);
      break;

    case MSG_ENTERSTATE:
      MEM_Free(pvMessage);
      break;

    case MSG_OBJSTRUPDATE:
      {
	MsgObjStrUpdate *pmsgMess = (MsgObjStrUpdate*)pvMessage;
	
	MEM_Free(pmsgMess->strNewValue);
	MEM_Free(pvMessage);
      }
      break;
      
    case MSG_OBJINTUPDATE:
      MEM_Free(pvMessage);
      break;

    case MSG_FREEPLAYER:
      MEM_Free(pvMessage);
      break;

    /* These happen to be identical, so we can lump them. */  
    case MSG_NETMESSAGE:
    case MSG_NETPOPUP:
      {
	MsgNetMessage *pmsgMess = (MsgNetMessage *)pvMessage;
	MEM_Free(pmsgMess->strMessage);
	MEM_Free(pvMessage);
      }
      break;

    case MSG_ENDOFGAME:
      MEM_Free(pvMessage);
      break;

    case MSG_DICEROLL:
      MEM_Free(pvMessage);
      break;

    case MSG_PLACENOTIFY:
      MEM_Free(pvMessage);
      break;

    case MSG_ATTACKNOTIFY:
      MEM_Free(pvMessage);
      break;

    case MSG_MOVENOTIFY:
      MEM_Free(pvMessage);
      break;

    case MSG_EXIT:
    case MSG_STARTGAME:
    case MSG_ENDTURN:
    case MSG_GAMENEWPLAYERS:
    case MSG_GAMEMOREPLAYERS:
    case MSG_SAMEPLAYERS:
    case MSG_DEREGISTERCLIENT:
    case MSG_ALLOCPLAYER:
    case MSG_POPUPREGISTERBOX:
      /* No parameters */
      D_Assert(pvMessage == NULL, "Hum...this shouldn't happen.");
      break;

    default:
      D_Assert(FALSE, "Add case for a new message in NET_DeleteMessage!");
    }
}
