home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume14 / okbridge2 / part06 / cs.c next >
C/C++ Source or Header  |  1993-01-27  |  17KB  |  600 lines

  1. /* cs.c -- client/server routines
  2.  *
  3.  ! Copyright (C) 1990-1992 by Matthew Clegg.  All Rights Reserved
  4.  ! 
  5.  ! OKbridge is made available as a free service to the Internet.
  6.  ! Accordingly, the following restrictions are placed on its use:
  7.  ! 
  8.  ! 1.  OKbridge may not be modified in any way without the explicit 
  9.  !     permission of Matthew Clegg.  
  10.  ! 
  11.  ! 2.  OKbridge may not be used in any way for commercial advantage.
  12.  !     It may not be placed on for-profit networks or on for-profit
  13.  !     computer systems.  It may not be bundled as part of a package
  14.  !     or service provided by a for-profit organization.
  15.  ! 
  16.  ! If you have questions about restrictions on the use of OKbridge,
  17.  ! write to mclegg@cs.ucsd.edu.
  18.  ! 
  19.  ! DISCLAIMER:  The user of OKbridge accepts full responsibility for any
  20.  ! damage which may be caused by OKbridge.
  21.  *
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <string.h>
  26.  
  27. #include "socket.h"
  28. #include "network.h"
  29. #include "state.h"
  30. #include "gps.h"
  31. #include "cs.h"
  32.  
  33. #ifdef LOGFILE
  34. extern FILE *net_log;
  35. #endif
  36.  
  37. #ifdef GCC
  38. extern strcasecmp ();
  39. extern fprintf ();
  40. extern fflush ();
  41. #endif
  42.  
  43. extern char Parser_Error_Buf [];
  44.  
  45. extern void Generate_reset ();
  46. extern void Network_Comment ();
  47.  
  48. void Clear_Spectators (t)
  49.      Table t;
  50. /* Clears the spectator mode flag for each of the players at the table t. */
  51. {
  52.   Connection c;
  53.  
  54.   FOREACH_PLAYER (c, t) 
  55.     c->spectator = 0;
  56.   spectator_mode = 0;
  57.  
  58. }
  59.  
  60. void Vacate_seat (t, s)
  61.      Table t; int s;
  62. /* Clears the seat s in the table t. */
  63. {
  64.   if (IS_PLAYER(s)) {
  65.     t->Seats[s].connection = NULL;
  66.     sprintf (t->Seats[s].player_name, "%s", seat_names[s]);
  67.     t->Seats[s].occupied = 0;
  68.   }
  69.  
  70. }
  71.  
  72. void Assign_seat (t, c, seat)
  73.      Table t; Connection c; int seat;
  74. /* void Assign_seat (Table t, Connection c, int seat) */
  75. /* Assigns the given seat to the player with connection c. */
  76. {
  77.   Vacate_seat (t, c->seat);
  78.  
  79.   c->seat = seat;
  80.   if (IS_PLAYER(seat)) {
  81.     t->Seats[seat].connection = c;
  82.     sprintf (PLAYER_NAME(t, seat), "%s", c->player_name);
  83.     t->Seats[seat].occupied = 1;
  84.   }
  85. }
  86.  
  87. int Request_Seat (c, requested)
  88.      Connection c; int requested;
  89. /* int Request_Seat (Connection c, int requested) */
  90. /* Requests the given seat for the player with connection c.
  91.  . If the request can be granted, then assigns the player to the seat,
  92.  . sends an acknowledgment message to the requesting player, and returns 
  93.  . the seat index of the seat assigned.  If it cannot be granted, then sends 
  94.  . an error message to the requesting player and returns -1.
  95.  */
  96. {
  97.   int i;
  98.   char message_buf [100];
  99.   Table t = c->table;
  100.  
  101.   if (VACANT(t,requested)) {
  102.     Send_seat (c->table, c->seat, requested, c->player_name);
  103.     Assign_seat (c->table, c, requested);
  104.     sprintf (message_buf, "SEATPOS %s", seat_names[requested]);
  105.     send_private_message (c, message_buf);
  106.     return (requested);
  107.   } else {
  108.     /* Construct a SEATERR message indicating which seats are free: */
  109.     sprintf (message_buf, "SEATERR");
  110.     for (i = 0; i < 4; i++)
  111.       if (!t->Seats[i].occupied)
  112.     sprintf (message_buf+strlen(message_buf), " %s", seat_names[i]);
  113.     send_private_message (c, message_buf);
  114.     return (-1);
  115.   }
  116. }
  117.  
  118. static void Respond_to_who_message (who_msg)
  119.      Message who_msg;
  120. {
  121.   char msg_buf[100], message[120];
  122.   int i;
  123.   Connection c;
  124.   Table t = who_msg->source->table;
  125.  
  126.   msg_buf[0] = '\0';
  127.   for (i = 0; i < 4; i++)
  128.     if (OCCUPIED(t,i))
  129.       sprintf (msg_buf+strlen(msg_buf),"%s(%c) %s",
  130.            (strlen(msg_buf) > 0)? ", ": "",
  131.            *("NESW" + i), PLAYER_NAME(t, i));
  132.   if (strlen(msg_buf) > 0) {
  133.     sprintf (message, "COMMENT %s", msg_buf);
  134.     send_private_message (who_msg->source, message);
  135.   }
  136.  
  137.   msg_buf[0] = '\0';
  138.   FOREACH_PLAYER (c, t) {
  139.     if (IS_OBSERVER(c->seat) && !c->spectator) {
  140.       sprintf (msg_buf+strlen(msg_buf), "%s%s",
  141.            (strlen(msg_buf) > 0)? ", ": " ", c->player_name);
  142.     }
  143.     if (strlen (msg_buf) > 50) {
  144.       sprintf (message, "COMMENT OBSERVERS: %s", msg_buf);
  145.       send_private_message (who_msg->source, message);
  146.       msg_buf[0] = '\0';
  147.     }
  148.   }
  149.   if (strlen(msg_buf) > 0) {
  150.     sprintf (message, "COMMENT OBSERVERS: %s", msg_buf);
  151.     send_private_message (who_msg->source, message);
  152.   }
  153.  
  154.   msg_buf[0] = '\0';
  155.   FOREACH_PLAYER (c, t) {
  156.     if (c->spectator) {
  157.       sprintf (msg_buf+strlen(msg_buf), "%s%s",
  158.            (strlen(msg_buf) > 0)? ", ": " ", c->player_name);
  159.     }
  160.     if (strlen (msg_buf) > 50) {
  161.       sprintf (message, "COMMENT SPECTATORS: %s", msg_buf);
  162.       send_private_message (who_msg->source, message);
  163.       msg_buf[0] = '\0';
  164.     }
  165.   }
  166.   if (strlen(msg_buf) > 0) {
  167.     sprintf (message, "COMMENT SPECTATORS: %s", msg_buf);
  168.     send_private_message (who_msg->source, message);
  169.   }
  170. }
  171.  
  172. static void Transmit_State_Information (t, c)
  173.      Table t;
  174.      Connection c;
  175. /* If a board is currently being played at the table t, then transmits
  176.  * the state information for that board. 
  177.  */
  178. {
  179.   char buf1[100], buf2[100], buf3[100];
  180.   Play_record *p;
  181.   Connection d;
  182.  
  183.   sprintf (buf1, "TABLE %d", t->table_no);
  184.   send_private_message (c, buf1);
  185.  
  186.   FOREACH_PLAYER (d, t) {
  187.     if (d != c) {
  188.       sprintf (buf1, "ACK %s %s", d->player_name,
  189.            IS_PLAYER(d->seat)? seat_names[d->seat]: "");
  190.       send_private_message (c, buf1);
  191.     }
  192.   } 
  193.  
  194.   if (IS_PLAYER(c->seat)) {
  195.     sprintf (buf1, "SEATPOS %s", seat_names[c->seat]);
  196.     send_private_message (c, buf1);
  197.   }
  198.  
  199.   c->state = CSTATE_PLAYING;
  200.   if (t->game_mode == STARTUP_MODE)
  201.     return;
  202.  
  203.   send_private_message (c, "DEAL");
  204.  
  205.   if (t->board == NULL)
  206.     return;
  207.  
  208.   sprintf (buf1, "BOARD %s %d", t->board->source, t->board->serial_no);
  209.   send_private_message (c, buf1);
  210.  
  211.   Encode_board (t->board, buf1, buf2);
  212.   server_send_unformatted (c, buf1);
  213.   server_send_unformatted (c, buf2);
  214.  
  215.   for (p = t->board->play_records; p != NULL; p = p->next) {
  216.     sprintf (buf1, "RECORD %s %d", t->board->source, t->board->serial_no);
  217.     send_private_message (c, buf1);
  218.     Encode_play_record (p, buf1, buf2, buf3);
  219.     server_send_unformatted (c, buf1);
  220.     server_send_unformatted (c, buf2);
  221.     server_send_unformatted (c, buf3);
  222.   }
  223.  
  224.   if ((p = t->play_record) != NULL) {
  225.     sprintf (buf1, "USEREC %s %s %s %s", 
  226.          p->player_names[PLAYER_NORTH], p->player_names[PLAYER_EAST],
  227.          p->player_names[PLAYER_SOUTH], p->player_names[PLAYER_WEST]);
  228.     send_private_message (c, buf1);
  229.   }
  230.  
  231.   sprintf (buf1, "SCORE %d %d %d %d",
  232.        t->above_line[SIDE_NS], t->above_line[SIDE_EW],
  233.        t->below_line[SIDE_NS], t->below_line[SIDE_EW]);
  234.   send_private_message (c, buf1);
  235.   
  236.   switch (t->playing_mode) {
  237.   case CLUB_PLAYING_MODE:
  238.     send_private_message (c, "MODE CLUB");
  239.     break;
  240.   case FORMAL_PLAYING_MODE:
  241.     send_private_message (c, "MODE FORMAL");
  242.     break;
  243.   case PRACTICE_PLAYING_MODE:
  244.     send_private_message (c, "MODE PRACTICE");
  245.     break;
  246.   }
  247.  
  248.   send_private_message (c, "BEGIN");
  249.  
  250.   if (t->game_mode != SCORING_MODE)
  251.     return;
  252.  
  253.   send_private_message (c, "END");
  254. }
  255.  
  256. static void Who_Response (who_msg, c, response)
  257.      Message who_msg;
  258.      Connection c;
  259.      char *response;
  260. {
  261.   char buf[100];
  262.  
  263.   sprintf (buf, "WHORESP %s %s", c->player_name, response);
  264.   send_private_message (who_msg->source, buf);
  265. }
  266.  
  267. static void Respond_to_Whois_Message (msg)
  268.      Message msg;
  269. {
  270.   Connection c;
  271.   char buf[80];
  272.  
  273.   if (!strcmp(msg->p.data.whois.name, "*ALL*")) {
  274.     FOREACH_PLAYER (c, msg->source->table) {
  275.       if (strlen(c->fullname))
  276.     Who_Response (msg, c, c->fullname);
  277.       if (strlen(c->email))
  278.     Who_Response (msg, c, c->email);
  279.     }
  280.     return;
  281.   }
  282.  
  283.   FOREACH_CONNECTION (c)
  284.     if (!strcasecmp(msg->p.data.whois.name, c->player_name))
  285.       break;
  286.  
  287.   if (c == NULL) {
  288.     sprintf (buf, "WHORESP %s %s", msg->p.data.whois.name,
  289.          "THERE IS NO PLAYER WITH THIS NAME.");
  290.     send_private_message (msg->source, buf);
  291.   } else if ((strlen(c->fullname) == 0) && (strlen(c->email) == 0))
  292.     Who_Response (msg, c, "NO INFORMATION AVAILABLE.");
  293.   else {
  294.     if (strlen(c->fullname))
  295.       Who_Response (msg, c, c->fullname);
  296.     if (strlen(c->email))
  297.       Who_Response (msg, c, c->email);
  298.   }
  299. }
  300.  
  301. void Handle_Protocol_Message_for_Server (msg)
  302.      Message msg;
  303. /* Processes the message m.  If the message is a protocol message, then
  304.    takes appropriate action based on the message.  Appends the message
  305.    to the appropriate conversation queue if further action is warranted.
  306. */
  307. {
  308.   char message_buf [100];
  309.   int s;
  310.   int  propagate;
  311.     /* A boolean flag which in the server mode indicates that the message
  312.        received should automatically be propagated to all other players. */
  313.   int pass_upwards;
  314.     /* A boolean flag which indicates that the message should be put
  315.        onto the conversation queue to be processed at the next level. */
  316.   Table t = msg->source->table;
  317.   Table tp;
  318.  
  319.   propagate = !msg->private;
  320.   pass_upwards = 1;
  321.  
  322.   switch (msg->p.command) {
  323.   case CMD_ERROR  :
  324.     if (msg->source->state == CSTATE_CONNECTED) {
  325.       sprintf (message_buf, "NORTH SEATERR OKBRIDGE %s: %s",
  326.            major_revision_level, "I DON'T RECOGNIZE YOU -- GO AWAY!");
  327.       fd_writeln (msg->source->channel, message_buf);
  328.       close_connection (msg->source);
  329.     } else {
  330. /*
  331.       sprintf (message_buf, "ERROR!! %s", msg->p.data.error.message);
  332.       send_private_message (msg->source, message_buf);
  333. */
  334. #ifdef LOGFILE
  335.       fprintf (net_log, "** %s\n", msg->p.command_text);
  336.       fprintf (net_log, "** %s\n", message_buf);
  337.       fflush (net_log);
  338. #endif
  339.     }
  340.     propagate = pass_upwards = 0;
  341.     break;
  342.  
  343.   case CMD_EMAIL:
  344.     propagate = 0;
  345.     if (msg->source->local)
  346.       sprintf (Local_Player_Connection->email, "%s", msg->p.data.email.addr);
  347.     else
  348.       sprintf (msg->source->email, "%s", msg->p.data.email.addr);
  349.     break;
  350.  
  351.   case CMD_FULLNAME:
  352.     propagate = 0;
  353.     if (msg->source->local)
  354.       sprintf (Local_Player_Connection->fullname, "%s", 
  355.            msg->p.data.fullname.name);
  356.     else
  357.       sprintf (msg->source->fullname, "%s", msg->p.data.fullname.name);
  358.     GPS_Broadcast_Server_Silently ();
  359.     break;
  360.  
  361.   case CMD_HELLO  :
  362.     if (strcmp(major_revision_level, msg->p.data.hello.version)) {
  363.       if (strcmp(msg->p.data.hello.version, "1.6")) {
  364.     sprintf (message_buf, "CONNERR %s %s %s",
  365.          "INCOMPATIBLE VERSIONS OF OKBRIDGE --",
  366.          "SERVER IS USING VERSION", major_revision_level);
  367.     send_private_message (msg->source, message_buf);
  368.     close_connection (msg->source);
  369.       } else {
  370.     sprintf (message_buf, "OKBRIDGE ERROR !! OKBRIDGE %s%s: %s",
  371.          major_revision_level, minor_revision_level,
  372.          "I DON'T RECOGNIZE YOU -- GO AWAY!");
  373.     server_send_unformatted (msg->source, message_buf);
  374.     write (msg->source->channel, "\0", 1);
  375.     close_connection (msg->source);
  376.       }
  377.       propagate = 0;
  378.     } else {
  379.       sprintf (msg->source->player_name, "%s", msg->p.player_name);
  380.       msg->source->state = CSTATE_PLAYING;
  381.       if (OCCUPIED(t, msg->p.data.hello.seat_req)) {
  382.     msg->p.data.hello.seat_req = PLAYER_OBS;
  383.     sprintf (msg->p.command_text, "%s HELLO %s %s OBS",
  384.          msg->p.player_name, major_revision_level,
  385.          msg->p.player_name);
  386.       }
  387.       Assign_seat (t, msg->source, msg->p.data.hello.seat_req);
  388.       Transmit_State_Information (t, msg->source);
  389. /*    GPS_Broadcast_Server_Silently (); */
  390.       propagate = 1;
  391.     }
  392.     break;
  393.  
  394.   case CMD_NAME:
  395.     sprintf (msg->source->player_name, "%s", msg->p.data.name.new_name);
  396.     break;
  397.  
  398.   case CMD_QUIT   :
  399.     if (!msg->source->local) {
  400.       Vacate_seat (msg->source->table, msg->p.player_no);
  401.       close_connection (msg->source);
  402.     }
  403.     GPS_Broadcast_Server_Silently ();
  404.     break;
  405.  
  406.   case CMD_PLAYREQ:
  407.     propagate = 0;
  408.     break;
  409.  
  410.   case CMD_REGISTRY:
  411.     propagate = 0;
  412.     strcpy (msg->source->registry, msg->p.data.registry.id);
  413.     break;
  414.  
  415.   case CMD_SEATERR:
  416.     propagate = 0;
  417.     break;
  418.  
  419.   case CMD_SEATPOS:
  420.     propagate = 0;
  421.     break;
  422.  
  423.   case CMD_SEATREQ:
  424.     propagate = 0;
  425.     Request_Seat (msg->source, msg->p.data.seatreq);
  426.     break;
  427.  
  428.   case CMD_SERVEREQ:
  429.     propagate = 0;
  430.     if (Parse_Server_Command (msg->p.data.servereq.command)) {
  431.       sprintf (message_buf, "COMMENT %s", Parser_Error_Buf);
  432.       send_private_message (msg->source, message_buf);
  433.     } else
  434.       send_private_message (msg->source, 
  435.                 "COMMENT SERVER REQUEST ACKNOWLEDGED.");
  436.     break;
  437.  
  438.   case CMD_TABLE:
  439.     propagate = 0;
  440.     for (tp = Table_List; tp != NULL; tp = tp->next)
  441.       if (tp->table_no == msg->p.data.tablereq)
  442.     break;
  443.  
  444.     if (tp != NULL)
  445.       Local_table = tp;
  446.     break;
  447.  
  448.   case CMD_TABLEREQ:
  449.     propagate = 0;
  450.     for (tp = Table_List; tp != NULL; tp = tp->next)
  451.       if (tp->table_no == msg->p.data.tablereq)
  452.     break;
  453.  
  454.     if (tp == NULL) {
  455.       sprintf (message_buf, "COMMENT THERE IS NO TABLE NUMBER %d.",
  456.            msg->p.data.tablereq);
  457.       send_private_message (msg->source, message_buf);
  458.     } else if (tp->table_no == t->table_no) {
  459.       sprintf (message_buf, "COMMENT YOU ARE ALREADY AT TABLE %d.",
  460.            msg->p.data.tablereq);
  461.       send_private_message (msg->source, message_buf);
  462.     } else {
  463.       Assign_seat (msg->source->table, msg->source, PLAYER_OBS);
  464.       Switch_Table (msg->source, tp);
  465.       Transmit_State_Information (tp, msg->source);
  466.       Send_seat (tp, PLAYER_OBS, PLAYER_OBS, msg->p.player_name);
  467.     }
  468.     break;
  469.  
  470.   case CMD_WHO:
  471.     Respond_to_who_message (msg);
  472.     propagate = pass_upwards = 0;
  473.     break;
  474.  
  475.   case CMD_WHOIS:
  476.     propagate = pass_upwards = 0;
  477.     Respond_to_Whois_Message (msg);
  478.     break;
  479.  
  480.   default:
  481.     break;
  482.   }
  483.  
  484.   if (propagate) {
  485.     if (msg->loopback)
  486.       Relay_message (msg->source->table, msg->source, msg->p.command,
  487.              msg->p.command_text);
  488.     else {
  489.       sprintf (message_buf, "%s %s", 
  490.            seat_names[msg->p.player_no],   msg->p.command_text);
  491.       Relay_message (msg->source->table, msg->source, msg->p.command, 
  492.              message_buf);
  493.     }
  494.     if (msg->p.command == CMD_BOARD)
  495.       Relay_board (t, msg->source, msg->p.data.board.record);
  496.     else if (msg->p.command == CMD_RECORD)
  497.       Relay_play_record (t, msg->source, msg->p.data.record.play);
  498.   }
  499.  
  500.   if (pass_upwards)
  501.     enqueue_message (t->conversation_queue, msg);
  502.   else
  503.     deallocate_message (msg);
  504.  
  505. }
  506.  
  507. void Handle_Protocol_Message_for_Client (msg)
  508.      Message msg;
  509. /* Performs the corresponding action as Handle_Protocol_Message_for_Server */
  510. {
  511.   int pass_upwards = 1;
  512.     /* A boolean flag which indicates that the message should be put
  513.        onto the conversation queue to be processed at the next level. */
  514.   char message_buf[80];
  515.  
  516.   Table t = Local_table;
  517.  
  518.   switch (msg->p.command) {
  519.   case CMD_ERROR:
  520.     sprintf (message_buf, "ERROR!! %s", msg->p.data.error.message);
  521.     Network_Comment (message_buf);
  522.     Network_Comment (msg->p.command_text);
  523. #ifdef LOGFILE
  524.     fprintf (net_log, "** %s\n", msg->p.command_text);
  525.     fprintf (net_log, "** %s\n", message_buf);
  526.     fflush (net_log);
  527. #endif
  528.     break;
  529.  
  530.   case CMD_ACK:
  531.     if (IS_PLAYER(msg->p.data.ack.position)) {
  532.       sprintf (PLAYER_NAME(t, msg->p.data.ack.position), "%s", 
  533.            msg->p.data.ack.player_name);
  534.       t->Seats[msg->p.data.ack.position].occupied = 1;
  535.     }
  536.     break;
  537.  
  538.   case CMD_HELLO:
  539.     if (IS_PLAYER(msg->p.data.hello.seat_req)) {
  540.       sprintf (PLAYER_NAME(t, msg->p.data.hello.seat_req), "%s", 
  541.            msg->p.data.hello.player_name);
  542.       t->Seats[msg->p.data.hello.seat_req].occupied = 1;
  543.     }
  544.     break;
  545.  
  546.   case CMD_QUIT   :
  547.     Vacate_seat (t, msg->p.player_no);
  548.     break;
  549.  
  550.   case CMD_SEAT   :
  551.     if (msg->p.data.seat.old_pos != local_player)
  552.       Vacate_seat (t, msg->p.data.seat.old_pos);
  553.     if (IS_PLAYER(msg->p.data.seat.new_pos)) { 
  554.       sprintf (PLAYER_NAME(t, msg->p.data.seat.new_pos), "%s", 
  555.            msg->p.data.seat.player_name);
  556.       t->Seats[msg->p.data.seat.new_pos].occupied = 1;
  557.     }
  558.     break;
  559.     
  560.   case CMD_SEATREQ:
  561.     if (!client_mode)
  562.       Request_Seat (msg->source, msg->p.data.seatreq);
  563.     break;
  564.  
  565.   case CMD_TABLE:
  566.     t->table_no = msg->p.data.table;
  567.     Vacate_seat (t, PLAYER_NORTH);
  568.     Vacate_seat (t, PLAYER_EAST);
  569.     Vacate_seat (t, PLAYER_SOUTH);
  570.     Vacate_seat (t, PLAYER_WEST);
  571.     break;
  572.  
  573.   case CMD_WHO:
  574.     if (!client_mode)
  575.       Respond_to_who_message (msg);
  576.     pass_upwards = 0;
  577.     break;
  578.  
  579.   case CMD_WHOIS:
  580.     if (!client_mode) {
  581.       if (local_player_full_name != NULL)
  582.     sprintf (Local_Player_Connection->fullname, "%s", 
  583.          local_player_full_name);
  584.       if (local_player_email != NULL)
  585.     sprintf (Local_Player_Connection->email, "%s", local_player_email);
  586.       Respond_to_Whois_Message (msg);
  587.     }
  588.     pass_upwards = 0;
  589.     break;
  590.  
  591.   default:
  592.     break;
  593.   }
  594.  
  595.   if (pass_upwards)
  596.     enqueue_message (t->conversation_queue, msg);
  597.   else
  598.     deallocate_message (msg);
  599. }
  600.