Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!lll-lcc!mordor!sri-spam!sri-unix!hplabs!pesnta!amd!intelca!mipos3!omepd!psu-cs!reed!tektronix!uw-beaver!fluke!toma
From: toma@tc.fluke.COM (Tom Anderson)
Newsgroups: net.sources.games
Subject: network chess (4 of 5)
Message-ID: <259@spock.tc.fluke.COM>
Date: Thu, 8-Jan-87 18:51:44 EST
Article-I.D.: spock.259
Posted: Thu Jan  8 18:51:44 1987
Date-Received: Thu, 15-Jan-87 19:49:46 EST
Organization: John Fluke Mfg. Co., Inc., Everett, WA
Lines: 940


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by spock!toma on Thu Jan  8 14:33:58 PST 1987
# Contents:  ipc.c tool.c controlsw.c
 
echo x - ipc.c
sed 's/^@//' > "ipc.c" <<'@//E*O*F ipc.c//'
/*
 * manage communication with the peer chess tool, if one exists.
 * some communication functions with a background chess process are
 * relayed by functions in this file.
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "nchess.h"

unsigned long MyProgNum = (u_long) 0;	/* my program number */
unsigned long PeerProgNum;		/* program number of peer */
char * PeerHostName;			/* host name of peer */
char * PeerUserName;			/* user name of peer */
BOOL peerDead = FALSE;			/* peer connection lost or chess program died */

BOOL UndoWanted = FALSE;		/* undo was requested locally */
BOOL RestoringGame = FALSE;		/* restoring a saved game via the peer */
SVCXPRT * Xprt;				/* RPC service transport handle */

/* 
 * get a transient program number 
 */
unsigned long
getTransient(vers, sockp)
    unsigned long vers; 
    int * sockp;
{
    unsigned long progNum = 0x52000000L;
    int s, len;
    struct sockaddr_in addr;

    /* create a socket */
    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	fprintf(stderr, "can't create a socket\n");
	exit(1);
    }
    * sockp = s;
    addr.sin_addr.s_addr = 0;
    addr.sin_family = AF_INET;
    addr.sin_port = 0;
    len = sizeof(addr);
    bind(s, (struct sockaddr *) &addr, len);
    if (getsockname(s, (caddr_t) &addr, &len) < 0) {
	fprintf(stderr, "getsockname failed\n");
	exit(1);
    }
    /* now find and reserve an available transient program number */
    while ( ! pmap_set(progNum++, vers, IPPROTO_UDP, addr.sin_port))
	continue;
    return(progNum - 1);
}

/*
 * timed out the peer
 */
void 
peerDied()
{
    Message("Lost connection to your opponent");
    peerDead = GameOver = TRUE;
    Mouse = LOCKED;
}

/*
 * RPC procedure dispatch routine
 */
void
dispatch(request, xprt)
    struct svc_req * request;
    SVCXPRT * xprt;
{
    Move move;
    SetupChange setup;
    GameRequest gr;
    char ans[80];
    int isUndoOK;

    switch (request->rq_proc) {
    /* 
     * are you there? 
     */
    case NULLPROC:
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    fprintf(stderr, "can't reply to remote peer\n");
	    exit(1);
	}
	break;
    /*  
     * game invitation accepted 
     */
    case ACCEPTPROCNUM:
	if ( ! svc_getargs(xprt, XdrGameReq, &gr)) {
	    svcerr_decode(xprt);
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    fprintf(stderr, "can't reply to remote peer\n");
	    exit(1);
	}
	PeerProgNum = gr.progNum;
	PeerColor = gr.color;
	if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) {
	    switch(MyColor) {
	    /* I don't care - pick a color based on what the peer wants */
	    case EITHERCOLOR:
		switch(PeerColor) {
		case WANTSBLACK:
		    MyColor = WANTSWHITE;
		    break;
		case WANTSWHITE:
		    MyColor = WANTSBLACK;
		    break;
		default:
		    fprintf(stderr, "color arbitration botch\n");
		    exit(1);
		}
		break;
	    case WANTSBLACK:
		if (PeerColor == WANTSBLACK) {
		    printf("Your opponent insists on playing black - is that OK? ");
		    scanf("%s", ans);
		    if (ans[0] == 'y' || ans[0] == 'Y') 
			MyColor = WANTSWHITE;
		    else {
			fprintf(stderr, "couldn't agree on colors - bye\n");
			(void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM,
			    xdr_void, (caddr_t) 0,
			    xdr_void, (caddr_t) 0);
			exit(1);
		    }
		}
		break;
	    case WANTSWHITE:
		if (PeerColor == WANTSWHITE) {
		    printf("Your opponent insists on playing white - is that OK? ");
		    scanf("%s", ans);
		    if (ans[0] == 'y' || ans[0] == 'Y') 
			MyColor = WANTSBLACK;
		    else {
			fprintf(stderr, "couldn't agree on colors - bye\n");
			(void) callrpc(PeerHostName, PeerProgNum, VERSNUM, COLORFAILPROCNUM,
			    xdr_void, (caddr_t) 0,
			    xdr_void, (caddr_t) 0);
			exit(1);
		    }
		}
		break;
	    }
	}
	break;
    /* 
     * the other player didn't ameliorate our insistence on color 
     */
    case COLORFAILPROCNUM:
	fprintf(stderr, "couldn't agree on colors - bye\n");
	(void) svc_sendreply(xprt, xdr_void, (caddr_t) 0);
	exit(1);
    /* 
     * receive a move from the other player 
     */
    case MOVEPROCNUM:
	if ( ! svc_getargs(xprt, XdrMove, &move)) {
	    fprintf(stderr, "can't get RPC args\n");
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    DoMove(&move, TRUE); 
	    Turn = MyColor;
	    Flashing = TRUE;
	    if (Mouse != CONFIRMING)
		WhoseMoveMessage((char *) 0);
	}
	break;
    /* 
     * receive a setup change from the other player 
     */
    case SETUPPROCNUM:
	if ( ! svc_getargs(xprt, XdrSetup, &setup)) {
	    fprintf(stderr, "can't get RPC args\n");
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    DoSetupChange(&setup);
	}
	break;
    /* 
     * receive a restoration move from the other player's process
     */
    case RESTOREMOVEPROCNUM:
	if ( ! svc_getargs(xprt, XdrMove, &move)) {
	    fprintf(stderr, "can't get RPC args\n");
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    DoMove(&move, TRUE); 
	    Turn = OTHERCOLOR(Turn);
	}
	break;
    /*
     * restoration complete 
     */
    case ENDRESTOREPROCNUM:
	if ( ! svc_getargs(xprt, xdr_int, &Turn)) {
	    fprintf(stderr, "can't get RPC args\n");
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    WhoseMoveMessage((char *) 0);
	    RestoringGame = FALSE;
	    Mouse = IDLE;	/* unlock the mouse */
	    Flashing = (Turn == MyColor);
	}
	break;
    /* 
     * other player wants to undo his previous move 
     */
    case UNDOPROCNUM:
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    RequestUndo();
	    Flashing = TRUE;
	}
	break;
    /*
     * the other player blew away his tool.
     */
    case GOODBYEPROCNUM:
	svc_sendreply(xprt, xdr_void, (caddr_t) 0);
	KillMouseActivity();
	peerDead = GameOver = TRUE;
	Mouse = LOCKED;
	Message("Your opponent killed his tool process");
	break;
    /*
     * other player is acknowledging our request to undo.
     */
    case UNDOACKPROCNUM:
	if ( ! svc_getargs(xprt, xdr_int, &isUndoOK)) {
	    fprintf(stderr, "can't get RPC args\n");
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    if (isUndoOK) {
		UnDoMove();
		if (Turn == MyColor)
		    UnDoMove();
		else
		    Turn = MyColor;
		WhoseMoveMessage("Undo accepted");
	    } else {
		WhoseMoveMessage("Undo refused");
	    }
	    UndoWanted = FALSE;
	    Mouse = IDLE;
	    Flashing = TRUE;
	}
	break;
    /*
     * other player resigned 
     */
    case RESIGNPROCNUM:
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0))
	    peerDead = TRUE;
	Message(PeerColor == BLACK ? "Black resigns" : "White resigns");
	KillMouseActivity();
	Mouse = LOCKED;		/* game is over */
	DoResignation(OTHERCOLOR(MyColor));
	Flashing = TRUE;
	break;
    case MSGPROCNUM:
	if ( ! svc_getargs(xprt, XdrString, ans)) {
	    fprintf(stderr, "can't get RPC args\n");
	    exit(1);
	}
	if ( ! svc_sendreply(xprt, xdr_void, (caddr_t) 0)) {
	    peerDied();
	} else {
	    RecvTalkMsg(ans);
	    Flashing = TRUE;
	}
	break;
    }
}


/*
 * outstanding invitation - shared by InitRPC() and quitEarly().
 */
GameRequest gr;

/*
 * cancel our invitation with the remote daemon if we receive a signal
 * before the invitee responds.
 */
quitEarly()
{
    callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, CANCELPROCNUM, 
	XdrGameReq, (caddr_t) &gr, 
	xdr_void, (caddr_t) 0);
    exit(1);
}

/*
 * initialize the RPC connection, using the user's "user@host" arg.
 */
void
InitRPC(cp, progName)
    char * cp, * progName;
{
    GameRequest gr2;
    int sock, rfds; 
    char localHostName[256], ans[80];
    BOOL resumeGame = FALSE;

    /*
     * decipher the remote host and user strings 
     */
    if (cp == (char *) 0 || (PeerHostName = index(cp, '@')) == (char *) 0) {
	fprintf(stderr, "%s: illegal/non-existent user@host arg\n", progName);
	exit(1);
    }
    *PeerHostName++ = '\0';
    PeerUserName = cp;
    /* 
     * determine the local host and user names 
     */
    if (gethostname(localHostName, sizeof(localHostName)) != 0) {
	fprintf(stderr, "%s: can't determine local host name\n", progName);
	exit(1);
    }
    /*
     * generate the transient RPC program number used by this player.
     */
    MyProgNum = getTransient(VERSNUM, &sock);
    if ((Xprt = svcudp_create(sock)) == (SVCXPRT *) 0) {
	fprintf(stderr, "svcudp_create failed\n");
	exit(1);
    }
    /*
     * register the peer-to-peer RPC dispatch procedure
     */
    (void) svc_register(Xprt, MyProgNum, VERSNUM, dispatch, 0L);
    /*
     * check for an invitation registered with the local chess
     * daemon, indicating that we are responding to an invitation.
     */
    (void) strcpy(gr.userName, PeerUserName);
    (void) strcpy(gr.hostName, PeerHostName);
    if (callrpc(localHostName, SERVERPROGNUM, VERSNUM, ACKPROCNUM,
	XdrGameReq, (caddr_t) &gr, 
	XdrGameReq, (caddr_t) &gr2) != 0) 
    {
	fprintf(stderr, "error: callrpc of local daemon (%s)\n", localHostName);
	exit(1);
    }
    PeerProgNum = gr2.progNum;
    PeerColor = gr2.color;
    resumeGame = gr2.resumeGame;
    do {
	/* 
	 * if no invitation was registered or the remote program 
	 * is no longer running,
	 * 	 then register an invitation with the remote daemon.
	 */
	if (PeerProgNum == 0L
	|| callrpc(PeerHostName, PeerProgNum, VERSNUM, NULLPROC, 
	    xdr_void, (caddr_t) 0, 
	    xdr_void, (caddr_t) 0) != 0) 
	{
	    gr.progNum = MyProgNum;
	    gr.color = MyColor;
	    gr.resumeGame = (RestoreFile != (FILE *) 0 || SetupMode);
	    (void) strcpy(gr.userName, UserPWEntry->pw_name);
	    (void) strcpy(gr.hostName, localHostName);
	    signal(SIGINT, quitEarly);
	    signal(SIGQUIT, quitEarly);
	    signal(SIGHUP, quitEarly);
	    if (callrpc(PeerHostName, SERVERPROGNUM, VERSNUM, REQPROCNUM, 
		XdrGameReq, (caddr_t) &gr, 
		xdr_void, (caddr_t) 0) != 0) 
	    {
		fprintf(stderr, "error: callrpc of remote daemon\n");
		exit(1);
	    }
	    printf("waiting for %s to respond...\n", PeerUserName);
	    /* 
	     * wait for the remote peer to send us his program number and color 
	     */
	    do {
		rfds = svc_fds;
		switch(select(32, &rfds, (int *) 0, (int *) 0, (struct timeval *) 0)) {
		case -1:
		    if (errno == EINTR)
			continue;
		    fprintf(stderr, "RPC select botch\n");
		    exit(1);
		case 0:
		    break;
		default:
		    svc_getreq(rfds);
		    break;
		}
	    } while(PeerProgNum == 0L);
	    signal(SIGINT, SIG_DFL);
	    signal(SIGQUIT, SIG_DFL);
	    signal(SIGHUP, SIG_DFL);
	}
	/*
	 * else accept the invitation, sending the remote program 
	 * our program number and color.
	 */
	else {
	    if (resumeGame) {
		MyColor = EITHERCOLOR;
		RestoringGame = TRUE;
		SetupMode = FALSE;
	    }
	    /* try to pre-arrange colors */
	    if (MyColor + PeerColor != WANTSWHITE + WANTSBLACK) {
		switch(MyColor) {
		/* I don't care - pick a color based on what the peer wants */
		case EITHERCOLOR:
		    switch(PeerColor) {
		    case EITHERCOLOR:
			MyColor = (random() & 0x01) ? WANTSBLACK : WANTSWHITE;
			break;
		    case WANTSBLACK:
			MyColor = WANTSWHITE;
			break;
		    case WANTSWHITE:
			MyColor = WANTSBLACK;
			break;
		    }
		    break;
		case WANTSBLACK:
		    if (PeerColor == WANTSBLACK) {
			printf("%s also wants to play black - is that OK? ", PeerUserName);
			scanf("%s", ans);
			if (ans[0] == 'y' || ans[0] == 'Y') 
			    MyColor = WANTSWHITE;
		    }
		    break;
		case WANTSWHITE:
		    if (PeerColor == WANTSWHITE) {
			printf("%s also wants to play white - is that OK? ", PeerUserName);
			scanf("%s", ans);
			if (ans[0] == 'y' || ans[0] == 'Y') 
			    MyColor = WANTSBLACK;
		    }
		    break;
		}
	    }
	    gr.progNum = MyProgNum;
	    gr.color = MyColor;
	    if (callrpc(PeerHostName, PeerProgNum, VERSNUM, ACCEPTPROCNUM, 
		XdrGameReq, (caddr_t) &gr, 
		xdr_void, (caddr_t) 0) != 0)
	    {
		PeerProgNum = 0L;
	    }
	}
    } while(PeerProgNum == 0L);
    PeerColor = OTHERCOLOR(MyColor);
    PlayerName[MyColor] = UserPWEntry->pw_name;
    PlayerName[PeerColor] = PeerUserName;
    /*
     * if the other player is shipping us the game state, lock the
     * mouse in the meantime.
     */
    if (RestoringGame)
	Mouse = LOCKED;
}

/*
 * send a move to the 'color' player
 */
BOOL
SendMove(move, color)
    Move * move;
    int color;
{
    if ( ! peerDead) {
	if (IsMachine[color]) {
	    SendMachineMove(move, color);
	} else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, MOVEPROCNUM,
	    XdrMove, (caddr_t) move, 
	    xdr_void, (caddr_t) 0) != 0) 
	{
	    peerDied();
	}
    }
    return( ! peerDead);
}

void
SendRestoreMove(move, color)
    Move * move;
    int color;
{
    if ( ! IsMachine[color] 
    && ! peerDead
    && callrpc(PeerHostName, PeerProgNum, VERSNUM, RESTOREMOVEPROCNUM,
	XdrMove, (caddr_t) move, 
	xdr_void, (caddr_t) 0) != 0)
    {
	peerDied();
    }
}

void
SendEndRestore()
{
    if ( ! peerDead
    && callrpc(PeerHostName, PeerProgNum, VERSNUM, ENDRESTOREPROCNUM,
	xdr_int, (caddr_t) &Turn, 
	xdr_void, (caddr_t) 0) != 0)
    {
	peerDied();
    }
}

void
SendUndoRequest(color)
    int color;
{
    if ( ! peerDead) {
	if (IsMachine[color]) {
	    if (Turn != MyColor) {
		Message("Will undo after machine moves...");
	    } else {
		MachineUndo(color);
		UndoWanted = FALSE;
		Mouse = IDLE;
	    }
	} else {
	    Message("Sending undo request to your opponent (please wait)...");
	    if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOPROCNUM,
		xdr_void, (caddr_t) 0, 
		xdr_void, (caddr_t) 0) != 0)
	    {
		peerDied();
	    }
	}
    }
}

void
SendResignation(color)
    int color;
{
    if ( ! peerDead) {
	if (IsMachine[color]) {
	    KillChessProcesses();
	} else if (callrpc(PeerHostName, PeerProgNum, VERSNUM, RESIGNPROCNUM,
	    xdr_void, (caddr_t) 0, 
	    xdr_void, (caddr_t) 0) != 0)
	{
	    peerDied();
	}
    }
}

void
SendTalkMsg(cp)
    char * cp;
{
    if ( ! peerDead
    && callrpc(PeerHostName, PeerProgNum, VERSNUM, MSGPROCNUM,
	XdrString, (caddr_t) cp, 
	xdr_void, (caddr_t) 0) != 0)
    {
	peerDied();
    }
}

void
SendSetupChange(setup, color)
    SetupChange * setup;
    int color;
{
    if ( ! IsMachine[color] 
    && ! peerDead
    && callrpc(PeerHostName, PeerProgNum, VERSNUM, SETUPPROCNUM,
	XdrSetup, (caddr_t) setup, 
	xdr_void, (caddr_t) 0) != 0)
    {
	peerDied();
    }
}

void
SendUndoAcknowledgement(isUndoOK)
    int isUndoOK;
{
    if (callrpc(PeerHostName, PeerProgNum, VERSNUM, UNDOACKPROCNUM,
	xdr_int, (caddr_t) &isUndoOK, 
	xdr_void, (caddr_t) 0) != 0)
    {
	peerDied();
    } else if (isUndoOK) {
	UnDoMove();
	if (Turn == MyColor) 
	    Turn = OTHERCOLOR(MyColor);
	else 
	    UnDoMove();
	Message(MyColor == WHITE ?
	    "Waiting for black to re-play..." :
	    "Waiting for white to re-play...");
    } else 
	WhoseMoveMessage((char *) 0);
}

void
SendGoodbye()
{
    if ( ! IsMachine[PeerColor] && ! peerDead) {
	callrpc(PeerHostName, PeerProgNum, VERSNUM, GOODBYEPROCNUM,
	    xdr_void, (caddr_t) 0,
	    xdr_void, (caddr_t) 0);
    }
    if (MyProgNum != 0) {
	/* unregister the RPC transport handle */
	xprt_unregister(Xprt);
	/* release my program number for re-use */
	pmap_unset(MyProgNum, VERSNUM);
    }
}
@//E*O*F ipc.c//
chmod u=r,g=r,o=r ipc.c
 
echo x - tool.c
sed 's/^@//' > "tool.c" <<'@//E*O*F tool.c//'
/*
 * handle the tool environment 
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "nchess.h"

Tool * NchessTool;
char ** ToolAttrs = (char **) NULL;
char * ToolName;

/*
 * iconic form of window
 */
unsigned short IconImage[] = {
#include "Icons/nchess.icon"
};

DEFINE_ICON_FROM_IMAGE(WindowIcon, IconImage);

sigwinched()
{
    tool_sigwinch(NchessTool);
}

/*
 * parse the tool args.
 */
void 
ParseToolArgs(argc, argv)
    int *argc;
    char **argv;
{
    ToolName = argv[0];
    (*argc)--;
    argv++;
    if (tool_parse_all(argc, argv, &ToolAttrs, ToolName) == -1) {
	tool_usage(ToolName);
	exit(1);
    }
    (*argc)++;
}

/*
 * set up the tool environment
 */
void
InitTool(useRetained, iconDirectory)
    BOOL useRetained;		/* use a retained pixrect for the board */
    char * iconDirectory;	/* custom piece icon directory */
{
    register unsigned int height;
    register Toolsw * twsp;
    char c[256];

    /* create the tool marquee */
    strcpy(c, " ");
    strcat(c, PlayerName[WHITE]);
    strcat(c, " vs. ");
    strcat(c, PlayerName[BLACK]);
    if ((NchessTool = tool_make( 
	WIN_LABEL, c, 
	WIN_ICON, &WindowIcon, 
	WIN_ATTR_LIST, ToolAttrs,
	WIN_WIDTH, 8 * (SQUARE_WIDTH-1) + 2 * tool_borderwidth(NchessTool) - 1,
	/*
	 * NOTE: The following line was unnecessary in Sun release 2.2,
	 * but is necessary in release 3.0.  For some unknown reason, the
	 * call to tool_set_attributes following the call to InitBoardSW
	 * now fails to uncover the board area that was obscured by the 
	 * default tool height being too small (note that the tool has not 
	 * been installed yet).
	 */
	WIN_HEIGHT, 2000,
	0)) == (Tool *) NULL) 
    {
	fputs("Can't make tool\n", stderr);
	exit(1);
    }
    tool_free_attribute_list(ToolAttrs);
    /* initialize the subwindows */
    InitTalkSW();
    InitMsgSW();
    InitControlSW();
    InitBoardSW(useRetained, iconDirectory);
    /* 
     * add up subwindow heights and force the tool to the resulting size 
     */
    height = tool_stripeheight(NchessTool) + tool_borderwidth(NchessTool) - tool_subwindowspacing(NchessTool);
    for (twsp = NchessTool->tl_sw ; twsp != (Toolsw *) 0 ; twsp = twsp->ts_next) 
	height += twsp->ts_height + tool_subwindowspacing(NchessTool);
    /*
     * NOTE: under 2.2, the above calculation yielded the correct height.
     * under 3.0, we need to add a few pixels to make it come out right (the
     * reason is not yet known).
     */
    height += 2;
    tool_set_attributes(NchessTool, WIN_HEIGHT, height, 0); 
    signal(SIGWINCH, sigwinched);
}

void
RunTool()
{
    /*
     * NOTE: this is another difference between release 2.2 and 3.0:
     * in release 2.2, the SIGWINCH handler would get called once at the
     * outset to draw the board area; in release 3.0, this doesn't happen.
     */
    DrawBoard();
    tool_select(NchessTool, 0);
    tool_destroy(NchessTool);
}

@//E*O*F tool.c//
chmod u=r,g=r,o=r tool.c
 
echo x - controlsw.c
sed 's/^@//' > "controlsw.c" <<'@//E*O*F controlsw.c//'
/*
 * control panel subwindow handling
 */

#include 
#include 
#include 
#include 

#include "nchess.h"

BOOL SaveWanted = FALSE;		/* machine opponent and game save deferred */

struct toolsw * ControlPanelSW;
Panel ControlPanel;

/* button items */
Panel_item UndoButton;
Panel_item LastPlayButton;
Panel_item ResignButton;
Panel_item TranscriptButton;
Panel_item SaveButton;

/*
 * undo move button event handler
 */
/*ARGSUSED*/
undoProc(item, event)
    Panel_item item;
    struct inputevent * event;
{
    if ( ! IHaveMoved()) {
	Message("You haven't moved yet!");
    } else if (Mouse == IDLE) {
	UndoWanted = TRUE;
	Mouse = LOCKED;		/* lock the mouse until the reply arrives */
	SendUndoRequest(PeerColor);
    }
}

/*
 * last play button event handler 
 */
/*ARGSUSED*/
lastPlayProc(item, event)
    Panel_item item;
    struct inputevent * event;
{
    ShowLastPlay();
}

/*
 * resign button event handler 
 */
/*ARGSUSED*/
resignProc(item, event)
    Panel_item item;
    struct inputevent * event;
{
    /* make sure this is what the user wants to do */
    if (Mouse == IDLE) {
	ConfirmResignation();
    }
}

/*
 * write a transcript 
 */
/*ARGSUSED*/
transcriptProc(item, event)
    Panel_item item;
    struct inputevent * event;
{
    WriteTranscript(TranscriptFileName, TranscriptType);
}

/*
 * save the game
 */
/*ARGSUSED*/
saveProc(item, event)
    Panel_item item;
    struct inputevent * event;
{
    /*
     * caveats: can't save games while we're still setting them up,
     * and cannot save a game involving machines after the game is over.
     */
    if (SetupMode 
    || GameOver && (IsMachine[WHITE] || IsMachine[BLACK]))
	return;
    if (IsMachine[WHITE] && IsMachine[BLACK]
    || IsMachine[PeerColor] && Turn != MyColor) {
	Message("Will save game when machine finishes move...");
	SaveWanted = TRUE;
    } else {
	SaveGame(SaveFileName);
    }
}

/*
 * set up the control subwindow
 */
void
InitControlSW()
{
    if ((ControlPanelSW = panel_create(NchessTool, 0)) == NULL) {
	fprintf(stderr, "Can't create control panel\n");
	exit(1);
    }
    ControlPanel = ControlPanelSW->ts_data;
    /* set up the buttons */
    if ( ! IsMachine[WHITE] || ! IsMachine[BLACK]) {
	ResignButton = panel_create_item(ControlPanel, PANEL_BUTTON,
	    PANEL_LABEL_STRING, "(Resign)",
	    PANEL_NOTIFY_PROC, resignProc,
	    0);
	UndoButton = panel_create_item(ControlPanel, PANEL_BUTTON,
	    PANEL_LABEL_STRING, "(Undo)",
	    PANEL_NOTIFY_PROC, undoProc,
	    0);
    }
    LastPlayButton = panel_create_item(ControlPanel, PANEL_BUTTON,
	PANEL_LABEL_STRING, "(Last Play)",
	PANEL_NOTIFY_PROC, lastPlayProc,
	0);
    TranscriptButton = panel_create_item(ControlPanel, PANEL_BUTTON,
	PANEL_LABEL_STRING, "(Transcript)",
	PANEL_NOTIFY_PROC, transcriptProc,
	0);
    SaveButton = panel_create_item(ControlPanel, PANEL_BUTTON,
	PANEL_LABEL_STRING, "(Save)",
	PANEL_NOTIFY_PROC, saveProc,
	0);
    panel_fit_height(ControlPanel);
}
@//E*O*F controlsw.c//
chmod u=r,g=r,o=r controlsw.c
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
     646    1975   15392 ipc.c
     121     392    3019 tool.c
     136     347    3010 controlsw.c
     903    2714   21421 total
!!!
wc  ipc.c tool.c controlsw.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0