/*==============================================================*\
 *  clnpthrd.c - Pipe Server end of Tic-Tac-Toe sample app
 *	Copyright 1992 IBM Corp.
 *--------------------------------------------------------------
 *
 *  DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
 *  sample code created by IBM Corporation. This sample code is not
 *  part of any standard or IBM product and is provided to you solely
 *  for	 the purpose of assisting you in the development of your
 *  applications.  The code is provided "AS IS", without
 *  warranty of any kind.  IBM shall not be liable for any damages
 *  arising out of your use of the sample code, even if they have been
 *  advised of the possibility of   such damages.						      *
 *
 *--------------------------------------------------------------
 *
 *  This c file contains the thread creation routines and
 *  manages the named pipe.
 *
\*==============================================================*/


/*--------------------------------------------------------------*\
 *  Include files, macros, defined constants, and externs
\*--------------------------------------------------------------*/
#define INCL_WINHELP
#define INCL_DOSPROCESS
#define INCL_WINMESSAGEMGR
#define INCL_WINWINDOWMGR
#define INCL_DOSNMPIPES
#define INCL_DOSFILEMGR
#define INCL_DOSERRORS
#define INCL_DOSSEMAPHORES
#define INCL_WINDIALOGS

#include <os2.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include "namepipe.h"

static struct _THREADPARAM {
   CHAR	 StartPipe[MAXPIPENAME];
   CHAR	 GamePipe[MAXPIPENAME];
   BOOL	 fMeFirst;
   };

typedef struct _THREADPARAM THREADPARAM;

#include "clnpmain.h"
#include "clnpxtrn.h"
#include "clnpglbl.h"

#define	 STACKSIZE  8192

CHAR  pszServer[MAXSERVERNAME];

BOOL InitThread()
{
   static THREADPARAM  tpPipeNames;
   ULONG	       usErrorMsg=0;

   /* load and open dialog box to get server name from user */
   if (IDC_OK == WinDlgBox(HWND_DESKTOP, hwndMainFrame, ServerDlgProc, 0, IDD_SERVER, NULL))
   {
      strcpy(tpPipeNames.StartPipe, "\\\\");
      strcat(tpPipeNames.StartPipe, pszServer);
      strcat(tpPipeNames.StartPipe, START_PIPE_NAME);
      strcpy(tpPipeNames.GamePipe, "\\\\");
      strcat(tpPipeNames.GamePipe, pszServer);
      strcat(tpPipeNames.GamePipe, GAME_PIPE_NAME);
   }

   else
   {
      strcpy(tpPipeNames.StartPipe, START_PIPE_NAME);
      strcpy(tpPipeNames.GamePipe, GAME_PIPE_NAME);
   }

   /* create event semaphore to communicate with pipe thread */
   if ((BOOL)DosCreateEventSem(NULL, &hevWritePipe, DC_SEM_SHARED, FALSE))
   {
      usErrorMsg = IDMSG_CREATE_SEM_FAILED;
   }

   else if (0 > _beginthread(ManagePipe,
			     NULL,
			     STACKSIZE,
			     (VOID *)&tpPipeNames))
   {
      usErrorMsg = IDMSG_CREATE_THREAD_FAILED;
   }

   if (usErrorMsg != 0)
   {
      MessageBox(hwndMain, usErrorMsg, 0, MB_WARNING | MB_OK, NULL, TRUE);
   }

   return((BOOL)(!(BOOL)usErrorMsg));
}


MRESULT EXPENTRY ServerDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
   ULONG       ulErrorReply=0, ulUserCommand;
   FILESTATUS  fs;
   APIRET      apiRC;

   switch (msg)
   {
      case WM_COMMAND:
	 switch ((ulUserCommand=SHORT1FROMMP(mp1)))
	 {
	    case ID_OK:
	       if (0 != WinQueryWindowText(WinWindowFromID(hwnd,
							   DID_PIPE_SVR),
					   MAXSERVERNAME,
					   pszServer))
	       {
		  while (ERROR_FILE_NOT_FOUND == (apiRC=DosQueryPathInfo(pszServer,
								  FIL_STANDARD,
								  &fs,
								  sizeof(FILESTATUS)))
			 || ERROR_PATH_NOT_FOUND == apiRC)
		  {
		     if (MBID_RETRY!=(ulErrorReply=MessageBox(hwnd,
					       IDMSG_INVALID_NAME,
					       0,
					       MB_CUAWARNING | MB_ABORTRETRYIGNORE,
					       NULL,
					       TRUE)))
		     {
			if (MBID_ABORT == ulErrorReply)
			{
			   ulUserCommand = ID_CANCEL;
			}

			break;
		     }
		  }
	       }

	       else
	       {
		  ulUserCommand = ID_CANCEL;
	       }

	    case ID_CANCEL:
	       WinDismissDlg(hwnd, ulUserCommand);
	       return (MRFROMLONG(0));
	 }
	 break;
   }
   return(WinDefDlgProc(hwnd, msg, mp1, mp2));
}


VOID ManagePipe(VOID *tpPipeNames)
{
   BOOL	   fSuccess=TRUE;
   USHORT  usMsg;
   ULONG   ulErrorMsg, ulIcon;
   HPIPE   hpPipe;
   PSZ	   pszServer;
   ULONG   ulAction;
   APIRET  apiRC;

/*
 *   Attempt to open named pipe.  If the pipe is busy, wait on it, and when
 *   it becomes free try to open it again.  Continue until success or error.
 */

   do
   {
      apiRC = DosOpen(((THREADPARAM *)tpPipeNames)->StartPipe,	/* pointer to filename	    */
		(PHFILE) &hpPipe,	     /* pointer to variable for file handle	     */
		&ulAction,		     /* pointer to variable for action taken	     */
		0L,			     /* file size if created or truncated	     */
		0L,			     /* file attribute				     */
		FILE_OPEN,		     /* action taken if file exists/does not exist   */
		FS_CLI_STARTPIPE_OPEN_MODE,  /* open mode of file			     */
		NULL);			     /* pointer to structure for extended attributes */
   }
   while (ERROR_PIPE_BUSY == apiRC &&
	  !(BOOL)(apiRC=DosWaitNPipe(pszServer, NP_INDEFINITE_WAIT)));

   if (apiRC != 0)
   {
      ulErrorMsg = IDMSG_CONNECT_FAILED;
      ulIcon = MB_CUAWARNING | MB_OK;
      fSuccess = FALSE;
   }

   if (TRUE == fSuccess)
   {
      /* connect to the game pipe */
      if ((BOOL)(hpPipe = ConnectGamePipe(hpPipe,
					  ((THREADPARAM *)tpPipeNames)->GamePipe)))
      {
	 /* enable the File-Start menu choice */
	 WinPostMsg(hwndMain, WM_START, MPVOID, MPVOID);

	 while (WritePipe(hpPipe, &usMsg) &&
		usMsg != CLIENT_QUIT &&
		usMsg != ERROR_MSG)
	 {
	    if (!(BOOL)ReadPipe(hpPipe, &usMsg))
	    {
	       break;
	    }
	 }
      }

      else
      {
	 ulErrorMsg = IDMSG_CONNECT_FAILED;
	 ulIcon = MB_CUAWARNING | MB_OK;
	 fSuccess = FALSE;
      }
   }

   if (FALSE == fSuccess)
   {
      WinPostMsg(hwndMain,
		 WM_MSG,
		 MPFROM2SHORT(ulErrorMsg, ulIcon),
		 MPFROMLONG(apiRC));
   }

   if (!fAppExit)
   {
      fAppExit = TRUE;
   }

   DosCloseEventSem(hevWritePipe);
   DosClose(hpPipe);
   fThrdsDead = TRUE;
}


/*
 *   open game pipe, notify server of success or failure, and close start pipe.
 */
HPIPE ConnectGamePipe(HPIPE hpPipe, PSZ pszGamePipe)
{
   HPIPE     hpGamePipe;
   USHORT    usMsg=ERROR_MSG;
   ULONG     ulCount, ulAction;
   PIPE_MSG  pmsgPipeMsg;
   APIRET    apiRC;

   /* block on read, and open game pipe if server sends START_MSG */
   if ((BOOL)ReadPipe(hpPipe, &usMsg) &&
       START_MSG == usMsg)
   {

      do
      {
	 apiRC = DosOpen(pszGamePipe,	      /* pointer to filename			      */
		  (PHFILE) &hpGamePipe,	      /* pointer to variable for file handle	      */
		  &ulAction,		      /* pointer to variable for action taken	      */
		  0L,			      /* file size if created or truncated	      */
		  0L,			      /* file attribute				      */
		  FILE_OPEN,		      /* action taken if file exists/does not exist   */
		  FS_CLI_GAMEPIPE_OPEN_MODE,  /* open mode of file			      */
		  NULL);		      /* pointer to structure for extended attributes */
      }
      while (ERROR_PIPE_BUSY == apiRC &&
	     !(BOOL)(apiRC=DosWaitNPipe(pszGamePipe, NP_INDEFINITE_WAIT)));
   }

   if (apiRC != 0)
   {
      usMsg = ERROR_MSG;
      hpGamePipe = 0;
   }

   if (START_MSG == usMsg)
   {
      pmsgPipeMsg.usMsgType = usMsg;
      pmsgPipeMsg.usMsgData = 0;

      /* notify server of success or failure */
      DosWrite(hpPipe, (VOID *)&pmsgPipeMsg, sizeof(PIPE_MSG), &ulCount);
   }

   /* if it is not a start message, return an error */
   else
   {
      hpGamePipe = 0;
   }

   /* close start pipe */
   DosClose(hpPipe);
   return(hpGamePipe);
}


/*
 *   wait for PM thread to post message, and write it to pipe.
 */
BOOL WritePipe(HPIPE hpPipe, USHORT *usMsg)
{
   ULONG   ulCount;
   BOOL	   fSuccess=TRUE;
   APIRET  apiRC;


   if (!(BOOL)DosWaitEventSem(hevWritePipe, SEM_INDEFINITE_WAIT))
   {
      DosResetEventSem(hevWritePipe, &ulCount);
      if ((BOOL)DosWrite(hpPipe, (VOID *)&pmsgPipeMsg, sizeof(PIPE_MSG), &ulCount))
      {
	 WinPostMsg(hwndMain, WM_MSG, MPFROM2SHORT(IDMSG_PIPE_WRITE_FAILED, MB_CUAWARNING | MB_OK), MPFROMLONG(apiRC));
	 fSuccess = FALSE;
      }

      *usMsg = pmsgPipeMsg.usMsgType;
   }

   else if (!fAppExit)
   {
      WinPostMsg(hwndMain, WM_MSG, MPFROM2SHORT(IDMSG_SEMAPHORE_ERROR, MB_CUAWARNING | MB_OK), MPVOID);
      fSuccess = FALSE;
   }

   return(fSuccess);
}


/*
 *   Read message from pipe, and post to PM thread.
 */
BOOL ReadPipe(HPIPE hpPipe, USHORT *usMsg)
{
   static PIPE_MSG  pmsgPipeMsg;
   BOOL		    fSuccess=TRUE;
   ULONG	    ulCount;
   APIRET	    apiRC;

   /* DosRead returns an error code of 0 and 0 bytes read with a broken pipe */
   if (!(BOOL)DosRead(hpPipe, (VOID *)&pmsgPipeMsg, sizeof(PIPE_MSG), &ulCount)
       && ulCount > 0)
   {
      if (START_MSG != (*usMsg = pmsgPipeMsg.usMsgType))
      {
	 WinPostMsg(hwndMain, (WM_USER+pmsgPipeMsg.usMsgType), MPFROMSHORT((SHORT)pmsgPipeMsg.usMsgData), MPVOID);
      }
   }

   else if (!fAppExit)
   {
      WinPostMsg(hwndMain, WM_MSG, MPFROM2SHORT(IDMSG_PIPE_READ_FAILED, MB_CUAWARNING | MB_OK), MPFROMLONG(apiRC));
      fSuccess = FALSE;
   }

   return(fSuccess);
}
