home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
games
/
volume14
/
okbridge2
/
part06
/
cs.c
next >
Wrap
C/C++ Source or Header
|
1993-01-27
|
17KB
|
600 lines
/* cs.c -- client/server routines
*
! Copyright (C) 1990-1992 by Matthew Clegg. All Rights Reserved
!
! OKbridge is made available as a free service to the Internet.
! Accordingly, the following restrictions are placed on its use:
!
! 1. OKbridge may not be modified in any way without the explicit
! permission of Matthew Clegg.
!
! 2. OKbridge may not be used in any way for commercial advantage.
! It may not be placed on for-profit networks or on for-profit
! computer systems. It may not be bundled as part of a package
! or service provided by a for-profit organization.
!
! If you have questions about restrictions on the use of OKbridge,
! write to mclegg@cs.ucsd.edu.
!
! DISCLAIMER: The user of OKbridge accepts full responsibility for any
! damage which may be caused by OKbridge.
*
*/
#include <stdio.h>
#include <string.h>
#include "socket.h"
#include "network.h"
#include "state.h"
#include "gps.h"
#include "cs.h"
#ifdef LOGFILE
extern FILE *net_log;
#endif
#ifdef GCC
extern strcasecmp ();
extern fprintf ();
extern fflush ();
#endif
extern char Parser_Error_Buf [];
extern void Generate_reset ();
extern void Network_Comment ();
void Clear_Spectators (t)
Table t;
/* Clears the spectator mode flag for each of the players at the table t. */
{
Connection c;
FOREACH_PLAYER (c, t)
c->spectator = 0;
spectator_mode = 0;
}
void Vacate_seat (t, s)
Table t; int s;
/* Clears the seat s in the table t. */
{
if (IS_PLAYER(s)) {
t->Seats[s].connection = NULL;
sprintf (t->Seats[s].player_name, "%s", seat_names[s]);
t->Seats[s].occupied = 0;
}
}
void Assign_seat (t, c, seat)
Table t; Connection c; int seat;
/* void Assign_seat (Table t, Connection c, int seat) */
/* Assigns the given seat to the player with connection c. */
{
Vacate_seat (t, c->seat);
c->seat = seat;
if (IS_PLAYER(seat)) {
t->Seats[seat].connection = c;
sprintf (PLAYER_NAME(t, seat), "%s", c->player_name);
t->Seats[seat].occupied = 1;
}
}
int Request_Seat (c, requested)
Connection c; int requested;
/* int Request_Seat (Connection c, int requested) */
/* Requests the given seat for the player with connection c.
. If the request can be granted, then assigns the player to the seat,
. sends an acknowledgment message to the requesting player, and returns
. the seat index of the seat assigned. If it cannot be granted, then sends
. an error message to the requesting player and returns -1.
*/
{
int i;
char message_buf [100];
Table t = c->table;
if (VACANT(t,requested)) {
Send_seat (c->table, c->seat, requested, c->player_name);
Assign_seat (c->table, c, requested);
sprintf (message_buf, "SEATPOS %s", seat_names[requested]);
send_private_message (c, message_buf);
return (requested);
} else {
/* Construct a SEATERR message indicating which seats are free: */
sprintf (message_buf, "SEATERR");
for (i = 0; i < 4; i++)
if (!t->Seats[i].occupied)
sprintf (message_buf+strlen(message_buf), " %s", seat_names[i]);
send_private_message (c, message_buf);
return (-1);
}
}
static void Respond_to_who_message (who_msg)
Message who_msg;
{
char msg_buf[100], message[120];
int i;
Connection c;
Table t = who_msg->source->table;
msg_buf[0] = '\0';
for (i = 0; i < 4; i++)
if (OCCUPIED(t,i))
sprintf (msg_buf+strlen(msg_buf),"%s(%c) %s",
(strlen(msg_buf) > 0)? ", ": "",
*("NESW" + i), PLAYER_NAME(t, i));
if (strlen(msg_buf) > 0) {
sprintf (message, "COMMENT %s", msg_buf);
send_private_message (who_msg->source, message);
}
msg_buf[0] = '\0';
FOREACH_PLAYER (c, t) {
if (IS_OBSERVER(c->seat) && !c->spectator) {
sprintf (msg_buf+strlen(msg_buf), "%s%s",
(strlen(msg_buf) > 0)? ", ": " ", c->player_name);
}
if (strlen (msg_buf) > 50) {
sprintf (message, "COMMENT OBSERVERS: %s", msg_buf);
send_private_message (who_msg->source, message);
msg_buf[0] = '\0';
}
}
if (strlen(msg_buf) > 0) {
sprintf (message, "COMMENT OBSERVERS: %s", msg_buf);
send_private_message (who_msg->source, message);
}
msg_buf[0] = '\0';
FOREACH_PLAYER (c, t) {
if (c->spectator) {
sprintf (msg_buf+strlen(msg_buf), "%s%s",
(strlen(msg_buf) > 0)? ", ": " ", c->player_name);
}
if (strlen (msg_buf) > 50) {
sprintf (message, "COMMENT SPECTATORS: %s", msg_buf);
send_private_message (who_msg->source, message);
msg_buf[0] = '\0';
}
}
if (strlen(msg_buf) > 0) {
sprintf (message, "COMMENT SPECTATORS: %s", msg_buf);
send_private_message (who_msg->source, message);
}
}
static void Transmit_State_Information (t, c)
Table t;
Connection c;
/* If a board is currently being played at the table t, then transmits
* the state information for that board.
*/
{
char buf1[100], buf2[100], buf3[100];
Play_record *p;
Connection d;
sprintf (buf1, "TABLE %d", t->table_no);
send_private_message (c, buf1);
FOREACH_PLAYER (d, t) {
if (d != c) {
sprintf (buf1, "ACK %s %s", d->player_name,
IS_PLAYER(d->seat)? seat_names[d->seat]: "");
send_private_message (c, buf1);
}
}
if (IS_PLAYER(c->seat)) {
sprintf (buf1, "SEATPOS %s", seat_names[c->seat]);
send_private_message (c, buf1);
}
c->state = CSTATE_PLAYING;
if (t->game_mode == STARTUP_MODE)
return;
send_private_message (c, "DEAL");
if (t->board == NULL)
return;
sprintf (buf1, "BOARD %s %d", t->board->source, t->board->serial_no);
send_private_message (c, buf1);
Encode_board (t->board, buf1, buf2);
server_send_unformatted (c, buf1);
server_send_unformatted (c, buf2);
for (p = t->board->play_records; p != NULL; p = p->next) {
sprintf (buf1, "RECORD %s %d", t->board->source, t->board->serial_no);
send_private_message (c, buf1);
Encode_play_record (p, buf1, buf2, buf3);
server_send_unformatted (c, buf1);
server_send_unformatted (c, buf2);
server_send_unformatted (c, buf3);
}
if ((p = t->play_record) != NULL) {
sprintf (buf1, "USEREC %s %s %s %s",
p->player_names[PLAYER_NORTH], p->player_names[PLAYER_EAST],
p->player_names[PLAYER_SOUTH], p->player_names[PLAYER_WEST]);
send_private_message (c, buf1);
}
sprintf (buf1, "SCORE %d %d %d %d",
t->above_line[SIDE_NS], t->above_line[SIDE_EW],
t->below_line[SIDE_NS], t->below_line[SIDE_EW]);
send_private_message (c, buf1);
switch (t->playing_mode) {
case CLUB_PLAYING_MODE:
send_private_message (c, "MODE CLUB");
break;
case FORMAL_PLAYING_MODE:
send_private_message (c, "MODE FORMAL");
break;
case PRACTICE_PLAYING_MODE:
send_private_message (c, "MODE PRACTICE");
break;
}
send_private_message (c, "BEGIN");
if (t->game_mode != SCORING_MODE)
return;
send_private_message (c, "END");
}
static void Who_Response (who_msg, c, response)
Message who_msg;
Connection c;
char *response;
{
char buf[100];
sprintf (buf, "WHORESP %s %s", c->player_name, response);
send_private_message (who_msg->source, buf);
}
static void Respond_to_Whois_Message (msg)
Message msg;
{
Connection c;
char buf[80];
if (!strcmp(msg->p.data.whois.name, "*ALL*")) {
FOREACH_PLAYER (c, msg->source->table) {
if (strlen(c->fullname))
Who_Response (msg, c, c->fullname);
if (strlen(c->email))
Who_Response (msg, c, c->email);
}
return;
}
FOREACH_CONNECTION (c)
if (!strcasecmp(msg->p.data.whois.name, c->player_name))
break;
if (c == NULL) {
sprintf (buf, "WHORESP %s %s", msg->p.data.whois.name,
"THERE IS NO PLAYER WITH THIS NAME.");
send_private_message (msg->source, buf);
} else if ((strlen(c->fullname) == 0) && (strlen(c->email) == 0))
Who_Response (msg, c, "NO INFORMATION AVAILABLE.");
else {
if (strlen(c->fullname))
Who_Response (msg, c, c->fullname);
if (strlen(c->email))
Who_Response (msg, c, c->email);
}
}
void Handle_Protocol_Message_for_Server (msg)
Message msg;
/* Processes the message m. If the message is a protocol message, then
takes appropriate action based on the message. Appends the message
to the appropriate conversation queue if further action is warranted.
*/
{
char message_buf [100];
int s;
int propagate;
/* A boolean flag which in the server mode indicates that the message
received should automatically be propagated to all other players. */
int pass_upwards;
/* A boolean flag which indicates that the message should be put
onto the conversation queue to be processed at the next level. */
Table t = msg->source->table;
Table tp;
propagate = !msg->private;
pass_upwards = 1;
switch (msg->p.command) {
case CMD_ERROR :
if (msg->source->state == CSTATE_CONNECTED) {
sprintf (message_buf, "NORTH SEATERR OKBRIDGE %s: %s",
major_revision_level, "I DON'T RECOGNIZE YOU -- GO AWAY!");
fd_writeln (msg->source->channel, message_buf);
close_connection (msg->source);
} else {
/*
sprintf (message_buf, "ERROR!! %s", msg->p.data.error.message);
send_private_message (msg->source, message_buf);
*/
#ifdef LOGFILE
fprintf (net_log, "** %s\n", msg->p.command_text);
fprintf (net_log, "** %s\n", message_buf);
fflush (net_log);
#endif
}
propagate = pass_upwards = 0;
break;
case CMD_EMAIL:
propagate = 0;
if (msg->source->local)
sprintf (Local_Player_Connection->email, "%s", msg->p.data.email.addr);
else
sprintf (msg->source->email, "%s", msg->p.data.email.addr);
break;
case CMD_FULLNAME:
propagate = 0;
if (msg->source->local)
sprintf (Local_Player_Connection->fullname, "%s",
msg->p.data.fullname.name);
else
sprintf (msg->source->fullname, "%s", msg->p.data.fullname.name);
GPS_Broadcast_Server_Silently ();
break;
case CMD_HELLO :
if (strcmp(major_revision_level, msg->p.data.hello.version)) {
if (strcmp(msg->p.data.hello.version, "1.6")) {
sprintf (message_buf, "CONNERR %s %s %s",
"INCOMPATIBLE VERSIONS OF OKBRIDGE --",
"SERVER IS USING VERSION", major_revision_level);
send_private_message (msg->source, message_buf);
close_connection (msg->source);
} else {
sprintf (message_buf, "OKBRIDGE ERROR !! OKBRIDGE %s%s: %s",
major_revision_level, minor_revision_level,
"I DON'T RECOGNIZE YOU -- GO AWAY!");
server_send_unformatted (msg->source, message_buf);
write (msg->source->channel, "\0", 1);
close_connection (msg->source);
}
propagate = 0;
} else {
sprintf (msg->source->player_name, "%s", msg->p.player_name);
msg->source->state = CSTATE_PLAYING;
if (OCCUPIED(t, msg->p.data.hello.seat_req)) {
msg->p.data.hello.seat_req = PLAYER_OBS;
sprintf (msg->p.command_text, "%s HELLO %s %s OBS",
msg->p.player_name, major_revision_level,
msg->p.player_name);
}
Assign_seat (t, msg->source, msg->p.data.hello.seat_req);
Transmit_State_Information (t, msg->source);
/* GPS_Broadcast_Server_Silently (); */
propagate = 1;
}
break;
case CMD_NAME:
sprintf (msg->source->player_name, "%s", msg->p.data.name.new_name);
break;
case CMD_QUIT :
if (!msg->source->local) {
Vacate_seat (msg->source->table, msg->p.player_no);
close_connection (msg->source);
}
GPS_Broadcast_Server_Silently ();
break;
case CMD_PLAYREQ:
propagate = 0;
break;
case CMD_REGISTRY:
propagate = 0;
strcpy (msg->source->registry, msg->p.data.registry.id);
break;
case CMD_SEATERR:
propagate = 0;
break;
case CMD_SEATPOS:
propagate = 0;
break;
case CMD_SEATREQ:
propagate = 0;
Request_Seat (msg->source, msg->p.data.seatreq);
break;
case CMD_SERVEREQ:
propagate = 0;
if (Parse_Server_Command (msg->p.data.servereq.command)) {
sprintf (message_buf, "COMMENT %s", Parser_Error_Buf);
send_private_message (msg->source, message_buf);
} else
send_private_message (msg->source,
"COMMENT SERVER REQUEST ACKNOWLEDGED.");
break;
case CMD_TABLE:
propagate = 0;
for (tp = Table_List; tp != NULL; tp = tp->next)
if (tp->table_no == msg->p.data.tablereq)
break;
if (tp != NULL)
Local_table = tp;
break;
case CMD_TABLEREQ:
propagate = 0;
for (tp = Table_List; tp != NULL; tp = tp->next)
if (tp->table_no == msg->p.data.tablereq)
break;
if (tp == NULL) {
sprintf (message_buf, "COMMENT THERE IS NO TABLE NUMBER %d.",
msg->p.data.tablereq);
send_private_message (msg->source, message_buf);
} else if (tp->table_no == t->table_no) {
sprintf (message_buf, "COMMENT YOU ARE ALREADY AT TABLE %d.",
msg->p.data.tablereq);
send_private_message (msg->source, message_buf);
} else {
Assign_seat (msg->source->table, msg->source, PLAYER_OBS);
Switch_Table (msg->source, tp);
Transmit_State_Information (tp, msg->source);
Send_seat (tp, PLAYER_OBS, PLAYER_OBS, msg->p.player_name);
}
break;
case CMD_WHO:
Respond_to_who_message (msg);
propagate = pass_upwards = 0;
break;
case CMD_WHOIS:
propagate = pass_upwards = 0;
Respond_to_Whois_Message (msg);
break;
default:
break;
}
if (propagate) {
if (msg->loopback)
Relay_message (msg->source->table, msg->source, msg->p.command,
msg->p.command_text);
else {
sprintf (message_buf, "%s %s",
seat_names[msg->p.player_no], msg->p.command_text);
Relay_message (msg->source->table, msg->source, msg->p.command,
message_buf);
}
if (msg->p.command == CMD_BOARD)
Relay_board (t, msg->source, msg->p.data.board.record);
else if (msg->p.command == CMD_RECORD)
Relay_play_record (t, msg->source, msg->p.data.record.play);
}
if (pass_upwards)
enqueue_message (t->conversation_queue, msg);
else
deallocate_message (msg);
}
void Handle_Protocol_Message_for_Client (msg)
Message msg;
/* Performs the corresponding action as Handle_Protocol_Message_for_Server */
{
int pass_upwards = 1;
/* A boolean flag which indicates that the message should be put
onto the conversation queue to be processed at the next level. */
char message_buf[80];
Table t = Local_table;
switch (msg->p.command) {
case CMD_ERROR:
sprintf (message_buf, "ERROR!! %s", msg->p.data.error.message);
Network_Comment (message_buf);
Network_Comment (msg->p.command_text);
#ifdef LOGFILE
fprintf (net_log, "** %s\n", msg->p.command_text);
fprintf (net_log, "** %s\n", message_buf);
fflush (net_log);
#endif
break;
case CMD_ACK:
if (IS_PLAYER(msg->p.data.ack.position)) {
sprintf (PLAYER_NAME(t, msg->p.data.ack.position), "%s",
msg->p.data.ack.player_name);
t->Seats[msg->p.data.ack.position].occupied = 1;
}
break;
case CMD_HELLO:
if (IS_PLAYER(msg->p.data.hello.seat_req)) {
sprintf (PLAYER_NAME(t, msg->p.data.hello.seat_req), "%s",
msg->p.data.hello.player_name);
t->Seats[msg->p.data.hello.seat_req].occupied = 1;
}
break;
case CMD_QUIT :
Vacate_seat (t, msg->p.player_no);
break;
case CMD_SEAT :
if (msg->p.data.seat.old_pos != local_player)
Vacate_seat (t, msg->p.data.seat.old_pos);
if (IS_PLAYER(msg->p.data.seat.new_pos)) {
sprintf (PLAYER_NAME(t, msg->p.data.seat.new_pos), "%s",
msg->p.data.seat.player_name);
t->Seats[msg->p.data.seat.new_pos].occupied = 1;
}
break;
case CMD_SEATREQ:
if (!client_mode)
Request_Seat (msg->source, msg->p.data.seatreq);
break;
case CMD_TABLE:
t->table_no = msg->p.data.table;
Vacate_seat (t, PLAYER_NORTH);
Vacate_seat (t, PLAYER_EAST);
Vacate_seat (t, PLAYER_SOUTH);
Vacate_seat (t, PLAYER_WEST);
break;
case CMD_WHO:
if (!client_mode)
Respond_to_who_message (msg);
pass_upwards = 0;
break;
case CMD_WHOIS:
if (!client_mode) {
if (local_player_full_name != NULL)
sprintf (Local_Player_Connection->fullname, "%s",
local_player_full_name);
if (local_player_email != NULL)
sprintf (Local_Player_Connection->email, "%s", local_player_email);
Respond_to_Whois_Message (msg);
}
pass_upwards = 0;
break;
default:
break;
}
if (pass_upwards)
enqueue_message (t->conversation_queue, msg);
else
deallocate_message (msg);
}