|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 12245 (0x2fd5)
Types: TextFile
Names: »announce.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Cubes/announce.c«
/* vi:set sw=4 ts=4: */
#ifndef lint
static char sccsid[] = "@(#)announce.c 5.1 (G.M. Paris) 89/01/22";
#endif lint
/*
**
** cubes 5.1 Copyright 1989 Gregory M. Paris
** Permission granted to redistribute on a no charge basis.
** All other rights are reserved.
**
*/
#include <stdio.h>
#include <strings.h>
#include <syslog.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "cubes.h"
extern int errno;
extern player plr[];
extern int waiting;
extern int watching;
extern int winscore;
extern boolean jokermode;
extern boolean clearobs;
extern boolean adjroster;
extern boolean isproxy();
extern struct timeval poll;
/*
** announce: send a message to all human players but one
*/
announce(but, mesg)
int but;
char *mesg;
{
register int c;
for(c = 0;c < PLAYERS;++c) if(c != but) {
switch(plr[c].p_stat) {
case Active:
case Waiting:
case Watching:
case Spider:
(void) message(c, mesg);
break;
}
}
}
/*
** annscore: announce player score
** announces differently for affected player
*/
annscore(sc)
int sc;
{
char msgbuf[MESGLEN+64];
sprintf(msgbuf, "%d Player %d now has %d points (squandered %d).\r\n",
M_OSCO, sc+1, plr[sc].p_score, plr[sc].p_squander);
announce(sc, msgbuf);
if(plr[sc].p_stat != Computer) {
sprintf(msgbuf, "%d You now have %d points (squandered %d).\r\n",
M_MSCO, plr[sc].p_score, plr[sc].p_squander);
(void) message(sc, msgbuf);
}
}
/*
** annfarewell: bid farewell to player
** doesn't tell player about own leave
*/
annfarewell(oldc)
int oldc;
{
char msgbuf[MESGLEN+64];
sprintf(msgbuf, "%d farewell %d %s\r\n",
M_FARE, oldc+1, plr[oldc].p_name);
announce(oldc, msgbuf);
adjroster = True;
}
/*
** clearroster: send clear roster message to all clients
*/
clearroster()
{
register int c;
clearobs = False;
for(c = 0;c < PLAYERS;++c) {
switch(plr[c].p_stat) {
case Active:
case Waiting:
case Watching:
case Spider:
(void) simp(c, M_CPLR, "Clear player roster.");
break;
}
}
}
/*
** heartbeat: send a noop to Spiders
*/
heartbeat()
{
register int c;
for(c = 0;c < PLAYERS;++c)
if(plr[c].p_stat == Spider)
(void) simp(c, M_NOOP, "Bum-Bum Bum-Bump.");
}
/*
** observers: tell how many observers there are
** If clearobs is True the observers are showing in the
** roster, so report unseen observers as zero.
*/
observers(c)
{
register int cc;
char msgbuf[MESGLEN];
cc = (clearobs == True) ? 0 : (waiting + watching);
sprintf(msgbuf, "%d %d observer%s\r\n", M_NOBS, cc, cc == 1 ? "" : "s");
if(c != -1)
return message(c, msgbuf);
for(cc = 0;cc < PLAYERS;++cc) {
switch(plr[cc].p_stat) {
case Active:
case Waiting:
case Watching:
case Spider:
(void) message(cc, msgbuf);
break;
}
}
return 0;
}
/*
** roster: broadcast the roster to all players
*/
roster(only, showobs)
int only;
boolean showobs;
{
register int c, cc;
char msgbuf[MESGLEN];
clearobs = False; /* no observers showing (yet) */
/*
** Tell each player who he/she is then give a roster.
** Tell Waiting and Watching players, but don't show them
** unless showobjs is True.
*/
for(c = 0;c < PLAYERS;++c) {
if(only != -1 && c != only)
continue;
if(plr[c].p_stat == Inactive || plr[c].p_stat == Computer)
continue;
if(simp(c, M_CPLR, "New player roster.") < 0)
continue;
for(cc = 0;cc < PLAYERS;++cc) {
switch(plr[cc].p_stat) {
case Watching:
case Waiting:
case Spider:
if(showobs == False)
break;
clearobs = True;
/* fall */
case Active:
case Computer:
if(cc == c)
sprintf(msgbuf, "%d You are player %d %s\r\n",
M_UARE, cc+1, plr[cc].p_name);
else
sprintf(msgbuf, "%d player %d %s\r\n",
M_PNUM, cc+1, plr[cc].p_name);
if(message(c, msgbuf) < 0)
goto nextrecip;
if(cc == c)
sprintf(msgbuf,
"%d You now have %d points (squandered %d).\r\n",
M_MSCO, plr[cc].p_score, plr[cc].p_squander);
else
sprintf(msgbuf,
"%d Player %d now has %d points (squandered %d).\r\n",
M_OSCO, cc+1, plr[cc].p_score, plr[cc].p_squander);
if(message(c, msgbuf) < 0)
goto nextrecip;
break;
}
}
(void) observers(c);
nextrecip: ;
}
/*
** If this was a broadcast, the roster is now up to date.
*/
if(only == -1)
adjroster = False;
}
/*
** tellstatus: report a player's status
*/
tellstatus(c)
{
m_num t;
char *m;
switch(plr[c].p_stat) {
case Inactive:
return -1;
case Active:
if(isproxy(c) == False) {
t = M_ACTV, m = "You're now an active player.";
break;
}
t = M_AUTO, m = "You're on autopilot; type g<return> to gain control.";
break;
case Waiting:
t = M_WAIT, m = "You're waiting to be added...";
break;
case Watching:
t = M_VOYR,
m = "You're now a voyeur; type g<return> to enter this game.";
break;
case Spider:
t = M_SPDR, m = "You're now a spider; type g<return> to start a game.";
break;
case Computer:
if(plr[c].p_fd < 0)
return -1;
t = M_AUTO, m = "You've somehow become a computer!!!";
syslog(LOG_DEBUG, "tellstatus: `%s' is a Computer", plr[c].p_name);
break;
default:
t = M_ARGE, m = "You're now in an unknown mode!";
syslog(LOG_ERR, "tellstatus: `%s' is in an unknown mode (%d)",
plr[c].p_name, plr[c].p_stat);
break;
}
return simp(c, t, m);
}
/*
** tellwinscore: notify one or all players about the current winscore
** also notifies player as to whether jokermode is True or False.
*/
tellwinscore(c)
{
register int cc;
char msgbuf[MESGLEN];
sprintf(msgbuf, "%d This is a %d point game%s.\r\n", M_PARM, winscore,
jokermode == True ? " with jokers" : "");
if(c >= 0)
(void) message(c, msgbuf);
else {
for(cc = 0;cc < PLAYERS;++cc) {
switch(plr[cc].p_stat) {
case Active:
case Waiting:
case Watching:
case Spider:
(void) message(cc, msgbuf);
break;
}
}
}
}
/*
** simp: format and send a simple message
*/
simp(c, type, mtxt)
int c;
m_num type;
char *mtxt;
{
char msgbuf[MESGLEN];
sprintf(msgbuf, "%3d %.*s\r\n", type, MESGLEN-7, mtxt);
return message(c, msgbuf);
}
/*
** invalid: invalid command message
*/
invalid(c)
int c;
{
return simp(c, M_ARGE, "Invalid command; type ?<return> for help.");
}
/*
** multimesg: send multi-line message
*/
multimesg(c, type, marr)
int c;
m_num type;
char *marr[];
{
int n;
char msgbuf[MESGLEN];
/*
** Send each line of the message. All but the final
** has a period between the type number and the message.
*/
for(n = 0;marr[n] != 0;++n) {
sprintf(msgbuf, "%d%c%s\r\n",
type, marr[n+1] == 0 ? ' ' : '.', marr[n]);
if(message(c, msgbuf) < 0)
return -1;
}
return n;
}
/*
** messagejmp, messagetimo: message timeout handler
*/
static jmp_buf messagejmp;
static int
messagetimo(sig)
{
longjmp(messagejmp, sig);
}
/*
** message: write a message on a channel
*/
message(c, mesg)
int c;
char *mesg;
{
int n, mesglen;
int (*oldalrm)();
int (*oldpipe)();
unsigned alarmv;
fd_set rdy;
switch(plr[c].p_stat) {
case Inactive:
syslog(LOG_DEBUG, "message: to Inactive: %s", mesg);
return -1;
case Computer:
syslog(LOG_DEBUG, "message: to Computer: %s", mesg);
return 0; /* "succeeds" */
}
if(plr[c].p_fd < 0) {
if(plr[c].p_stat == Waiting && plr[c].p_computer != 0)
return 0; /* OK, Waiting Computer */
syslog(LOG_DEBUG,
"message: bad fd (c=%d;stat=%d): %s", c, plr[c].p_stat, mesg);
oldplayer(c);
return -1;
}
if((mesglen = strlen(mesg)) == 0)
return 0;
oldalrm = signal(SIGALRM, SIG_IGN);
oldpipe = signal(SIGPIPE, SIG_IGN);
alarmv = alarm(0);
switch(setjmp(messagejmp)) {
case 0:
break;
case SIGALRM:
syslog(LOG_DEBUG, "message: timeout: %s", mesg);
goto common;
case SIGPIPE:
(void) alarm(0);
syslog(LOG_DEBUG, "message: dead pipe: %s", mesg);
goto common;
default:
(void) alarm(0);
syslog(LOG_DEBUG, "message: unexpected signal: %s", mesg);
common:
oldplayer(c);
(void) signal(SIGALRM, oldalrm);
(void) signal(SIGPIPE, oldpipe);
(void) alarm(alarmv);
return -1;
}
(void) signal(SIGALRM, messagetimo);
(void) signal(SIGPIPE, messagetimo); /* treat like timeout */
(void) alarm(WRITETIMO);
FD_ZERO(&rdy);
FD_SET(plr[c].p_fd, &rdy);
(void) select(plr[c].p_fd+1, NOSEL, &rdy, NOSEL, &poll);
if((n = write(plr[c].p_fd, mesg, mesglen)) < 0) {
if(errno != EPIPE && errno != ENOTCONN)
syslog(LOG_DEBUG, "message: write: %m: %s", mesg);
(void) alarm(0);
oldplayer(c);
(void) signal(SIGALRM, oldalrm);
(void) signal(SIGPIPE, oldpipe);
(void) alarm(alarmv);
return -1;
}
(void) alarm(0);
(void) signal(SIGALRM, oldalrm);
(void) signal(SIGPIPE, oldpipe);
(void) alarm(alarmv);
return n;
}
/*
** replyjmp, replytimo: reply timeout handler
*/
static jmp_buf replyjmp;
static int
replytimo()
{
longjmp(replyjmp, 1);
}
/*
** reply: read a reply from a channel
*/
reply(c, mesg, mesglen)
int c, mesglen;
char *mesg;
{
int n, ntot;
int (*oldalrm)();
unsigned alarmv;
fd_set rdy;
switch(plr[c].p_stat) {
case Inactive:
syslog(LOG_DEBUG, "reply: from Inactive");
return -1;
case Computer:
syslog(LOG_DEBUG, "reply: from Computer");
return -1;
}
/*
** Handle read timeout.
*/
oldalrm = signal(SIGALRM, SIG_IGN);
alarmv = alarm(0);
if(setjmp(replyjmp) != 0) {
(void) signal(SIGALRM, oldalrm);
(void) alarm(alarmv);
/*
** Increment this player's timeout count. If we've
** reached or exceeded MAXTIMO, then say goodbye.
*/
if(++plr[c].p_timeouts >= MAXTIMO) {
syslog(LOG_DEBUG, "reply: too many timeouts");
(void) simp(c, M_DOWN, "Too many timeouts -- goodbye!");
oldplayer(c);
return -1;
}
/*
** Send a message to the client indicating timeout.
*/
syslog(LOG_DEBUG, "reply: timeout");
if(simp(c, M_INFO, "Timed out waiting for your response!") < 0)
return -1;
(void) send(plr[c].p_fd, "\001", 1, MSG_OOB);
return -2;
}
/*
** Read until we get a newline.
*/
(void) signal(SIGALRM, replytimo);
(void) alarm(READTIMO);
ntot = 0, mesg[0] = '\0';
while(index(mesg, '\n') == 0) {
FD_ZERO(&rdy);
FD_SET(plr[c].p_fd, &rdy);
(void) select(plr[c].p_fd+1, &rdy, NOSEL, NOSEL, HANG);
if((n = read(plr[c].p_fd, mesg+ntot, mesglen-ntot)) <= 0) {
(void) alarm(0);
#ifdef notdef
if(n < 0)
syslog(LOG_DEBUG, "reply: read: %m");
else
syslog(LOG_DEBUG, "reply: read got zero bytes");
#endif notdef
oldplayer(c);
(void) signal(SIGALRM, oldalrm);
(void) alarm(alarmv);
return -1;
}
ntot += n, mesg[ntot] = '\0';
}
(void) alarm(0);
/*
** Had a successful read, so zero timeout count.
*/
plr[c].p_timeouts = 0;
/*
** Strip trailing control characters and spaces.
** Then get rid of control characters in the message.
** We must be careful to preserve ASYNCMARK at position 0.
XXX Assumes iscntrl(ASYNCMARK) is true.
*/
for(n = ntot - 1;n >= 0;--n) {
mesg[n] &= 0x7f; /* strip high bit */
if(iscntrl(mesg[n])) {
if(n != 0 || mesg[n] != ASYNCMARK)
mesg[n] = '\0';
} else if(isspace(mesg[n]))
mesg[n] = '\0';
else
break;
}
for(n = 0;mesg[n] != '\0';++n)
if(iscntrl(mesg[n]))
if(n != 0 || mesg[n] != ASYNCMARK)
mesg[n] = '?';
(void) signal(SIGALRM, oldalrm);
(void) alarm(alarmv);
return n;
}
/*
** dialogue: flush pending data, send message, read reply
*/
dialogue(c, msg, len)
int c, len;
char *msg;
{
long q;
int n;
char junk[MESGLEN];
if(plr[c].p_fd < 0)
return -1;
if(plr[c].p_stat == Inactive || plr[c].p_stat == Computer)
return -1;
/*
** Because of the way this protocol is set up, any pending input at
** this point should be discarded, because it means that the client
** has somehow gotten out of sync.
*/
while(ioctl(plr[c].p_fd, FIONREAD, (char *)&q) != -1 && q > 0) {
if(q > sizeof junk)
q = sizeof junk;
(void) read(plr[c].p_fd, junk, (int)q);
}
/*
** Send message.
*/
if(message(c, msg) < 0)
return -1;
/*
** We keep reading here until we get a non-asynchronous reply.
*/
for(;;) {
if((n = reply(c, msg, len)) < 0) /* error or timeout */
return n;
if(msg[0] != ASYNCMARK) /* not asynchronous */
return n;
}
}