Rev 140 | Rev 171 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | // network.cpp |
| 2 | |||
| 3 | #include "common.h" |
||
| 4 | |||
| 5 | |||
| 6 | // prototypes of local functions |
||
| 7 | static void EvaluateServerReply (player_t *player); |
||
| 8 | |||
| 9 | |||
| 153 | pmbaty | 10 | bool Network_Init (void) |
| 11 | { |
||
| 12 | // this function initializes the network subsystem on operating systems that require it |
||
| 13 | |||
| 14 | #ifdef _WIN32 |
||
| 15 | static bool is_winsock_initialized = false; |
||
| 16 | WSADATA wsa_data; |
||
| 17 | |||
| 18 | if (!is_winsock_initialized) |
||
| 19 | is_winsock_initialized = (WSAStartup (MAKEWORD (2, 2), &wsa_data) == 0); |
||
| 20 | |||
| 21 | return (is_winsock_initialized); // return whether the network subsystem was successfully initialized |
||
| 22 | #else // !_WIN32 |
||
| 23 | return (true); // all other systems than Win32 don't need to initialize the network |
||
| 24 | #endif // _WIN32 |
||
| 25 | } |
||
| 26 | |||
| 27 | |||
| 1 | pmbaty | 28 | bool PlayerNetwork_Init (player_t *player) |
| 29 | { |
||
| 30 | // this function initializes the network layer and connects to the chess server |
||
| 31 | |||
| 32 | struct hostent *hostinfo; |
||
| 33 | struct sockaddr_in service; |
||
| 34 | unsigned long nonblocking_mode; |
||
| 35 | char ascii_hostname[256]; |
||
| 36 | |||
| 37 | onlineplayers = NULL; // ensure the online players array is empty |
||
| 38 | onlineplayer_count = 0; // and reset the online players count |
||
| 39 | onlineplayers_updated = false; |
||
| 40 | |||
| 41 | soughtgames = NULL; // ensure the sought games array is empty |
||
| 42 | soughtgame_count = 0; // and reset the sought games count |
||
| 43 | soughtgames_updated = false; |
||
| 44 | lastsought_time = 0; |
||
| 45 | |||
| 46 | chatterchannels = NULL; // ensure the chatter channels array is empty |
||
| 47 | chatterchannel_count = 0; // and reset the chatter channels count |
||
| 48 | chatterchannels_updated = false; |
||
| 49 | selected_chatterchannel = NULL; |
||
| 50 | |||
| 51 | PlayerCards_Init (); // initialize the player cards array |
||
| 52 | Challenges_Init (); // initialize the challenges array |
||
| 53 | Interlocutors_Init (); // initialize the interlocutors array |
||
| 54 | |||
| 55 | server_motd[0] = 0; // reset the server MOTD |
||
| 56 | |||
| 57 | player->is_connected = false; // remember we aren't connected yet |
||
| 58 | player->is_logged_in = false; // and not logged in either |
||
| 59 | player->is_in_game = false; // we aren't in game either |
||
| 60 | player->game_number = 0; |
||
| 61 | player->remaining_seconds = 0; |
||
| 62 | player->our_socket = INVALID_SOCKET; // and that we have no socket yet |
||
| 63 | player->name[0] = 0; // player name undefined |
||
| 64 | |||
| 153 | pmbaty | 65 | // initialize the network subsystem if required |
| 66 | if (!Network_Init ()) |
||
| 1 | pmbaty | 67 | { |
| 68 | messagebox.hWndParent = hMainWnd; |
||
| 69 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 70 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed")); |
||
| 71 | messagebox.flags = MB_ICONWARNING | MB_OK; |
||
| 72 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 73 | |||
| 74 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 75 | return (false); |
||
| 76 | } |
||
| 77 | |||
| 78 | // get the chess server's IP address from the host name |
||
| 79 | ConvertTo7BitASCII (ascii_hostname, sizeof (ascii_hostname), options.network.server_address); |
||
| 80 | hostinfo = gethostbyname (ascii_hostname); |
||
| 81 | if (hostinfo == NULL) |
||
| 82 | { |
||
| 83 | messagebox.hWndParent = hMainWnd; |
||
| 84 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 85 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed")); |
||
| 86 | messagebox.flags = MB_ICONWARNING | MB_OK; |
||
| 87 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 88 | |||
| 89 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 90 | return (false); |
||
| 91 | } |
||
| 92 | |||
| 93 | // fill in the sockaddr server structure with the server hostinfo data |
||
| 94 | service.sin_family = AF_INET; |
||
| 95 | service.sin_addr.s_addr = inet_addr (inet_ntoa (*(struct in_addr *) hostinfo->h_addr_list[0])); |
||
| 96 | service.sin_port = htons (options.network.server_port); |
||
| 97 | |||
| 98 | // create our socket |
||
| 99 | if ((player->our_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) |
||
| 100 | { |
||
| 101 | messagebox.hWndParent = hMainWnd; |
||
| 102 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 103 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed")); |
||
| 104 | messagebox.flags = MB_ICONWARNING | MB_OK; |
||
| 105 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 106 | |||
| 107 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 108 | return (false); |
||
| 109 | } |
||
| 110 | |||
| 111 | // connect the game to the chess server using that socket |
||
| 112 | if (connect (player->our_socket, (struct sockaddr *) &service, sizeof (service)) == -1) |
||
| 113 | { |
||
| 114 | messagebox.hWndParent = hMainWnd; |
||
| 115 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 116 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed")); |
||
| 117 | messagebox.flags = MB_ICONWARNING | MB_OK; |
||
| 118 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 119 | |||
| 120 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 121 | return (false); |
||
| 122 | } |
||
| 123 | |||
| 124 | // set it to be non-blocking (but only AFTER the connection is made) |
||
| 125 | nonblocking_mode = 1; |
||
| 126 | if (ioctlsocket (player->our_socket, FIONBIO, &nonblocking_mode) == SOCKET_ERROR) |
||
| 127 | { |
||
| 128 | messagebox.hWndParent = hMainWnd; |
||
| 129 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 130 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed")); |
||
| 131 | messagebox.flags = MB_ICONWARNING | MB_OK; |
||
| 132 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 133 | |||
| 134 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 135 | return (false); |
||
| 136 | } |
||
| 137 | |||
| 138 | // initialize the debug log file |
||
| 139 | Debug_Init (L"Chess server output.txt"); |
||
| 140 | |||
| 141 | player->is_connected = true; // remember we are connected |
||
| 142 | return (true); // finished, we have a valid, connected socket |
||
| 143 | } |
||
| 144 | |||
| 145 | |||
| 146 | void PlayerNetwork_Shutdown (player_t *player) |
||
| 147 | { |
||
| 148 | // this function shutdowns the network layer |
||
| 149 | |||
| 150 | int chatterchannel_index; |
||
| 151 | |||
| 152 | // shutdown the socket if it is open. This will disconnect us from the server. |
||
| 153 | if (player->our_socket != INVALID_SOCKET) |
||
| 154 | closesocket (player->our_socket); // close the network socket |
||
| 155 | player->our_socket = INVALID_SOCKET; |
||
| 156 | |||
| 157 | player->is_connected = false; // remember we are no longer connected |
||
| 158 | player->is_logged_in = false; // and not logged in either |
||
| 159 | player->is_in_game = false; // we aren't in game either |
||
| 160 | player->game_number = 0; |
||
| 161 | player->remaining_seconds = 0; |
||
| 162 | player->name[0] = 0; // player name undefined |
||
| 163 | |||
| 164 | server_motd[0] = 0; // reset the server MOTD |
||
| 165 | |||
| 166 | // cycle through all chatter channels we know... |
||
| 167 | for (chatterchannel_index = 0; chatterchannel_index < chatterchannel_count; chatterchannel_index++) |
||
| 168 | { |
||
| 169 | SAFE_free ((void **) &chatterchannels[chatterchannel_index].members); // free their member list |
||
| 170 | chatterchannels[chatterchannel_index].member_count = 0; // reset their members count |
||
| 171 | } |
||
| 172 | SAFE_free ((void **) &chatterchannels); // free the chatter channels array |
||
| 173 | chatterchannel_count = 0; // and reset the chatter channels count |
||
| 174 | chatterchannels_updated = false; |
||
| 175 | selected_chatterchannel = NULL; |
||
| 176 | |||
| 177 | SAFE_free ((void **) &soughtgames); // free the sought games array |
||
| 178 | soughtgame_count = 0; // and reset the sought games count |
||
| 179 | soughtgames_updated = false; |
||
| 180 | |||
| 181 | SAFE_free ((void **) &onlineplayers); // free the online players array |
||
| 182 | onlineplayer_count = 0; // and reset the online players count |
||
| 183 | onlineplayers_updated = false; |
||
| 184 | |||
| 185 | Interlocutors_Shutdown (); // shutdown the interlocutors |
||
| 186 | Challenges_Shutdown (); // shutdown the challenges |
||
| 187 | PlayerCards_Shutdown (); // shutdown the player cards |
||
| 188 | |||
| 189 | // shutdown all possible opened UI windows |
||
| 190 | if (IsWindow (hChatterChannelsWnd)) |
||
| 191 | DestroyWindow (hChatterChannelsWnd); |
||
| 192 | hChatterChannelsWnd = NULL; |
||
| 193 | if (IsWindow (hGamesWnd)) |
||
| 194 | DestroyWindow (hGamesWnd); |
||
| 195 | hGamesWnd = NULL; |
||
| 196 | if (IsWindow (hMOTDWnd)) |
||
| 197 | DestroyWindow (hMOTDWnd); |
||
| 198 | hMOTDWnd = NULL; |
||
| 199 | if (IsWindow (hOpponentsWnd)) |
||
| 200 | DestroyWindow (hOpponentsWnd); |
||
| 201 | hOpponentsWnd = NULL; |
||
| 202 | if (IsWindow (hSoughtWnd)) |
||
| 203 | DestroyWindow (hSoughtWnd); |
||
| 204 | hSoughtWnd = NULL; |
||
| 205 | |||
| 206 | // shutdown WinSock |
||
| 207 | WSACleanup (); |
||
| 208 | |||
| 209 | return; // finished |
||
| 210 | } |
||
| 211 | |||
| 212 | |||
| 213 | bool PlayerNetwork_Think (player_t *player) |
||
| 214 | { |
||
| 215 | // this function is called once per game tick to listen to the network and react to what the server tells us. Returns TRUE |
||
| 216 | // if we need to update the scene. |
||
| 217 | |||
| 218 | player_t *local_player; |
||
| 219 | char *block_start; |
||
| 220 | char *block_end; |
||
| 221 | char *ascii_sendbuffer; // mallocated |
||
| 222 | wchar_t *widechar_buffer; // mallocated |
||
| 223 | wchar_t *widechar_line; |
||
| 224 | int send_retval; |
||
| 225 | int recv_retval; |
||
| 226 | int byte_index; |
||
| 227 | int rewrite_index; |
||
| 228 | int length; |
||
| 229 | bool do_update; |
||
| 230 | |||
| 231 | // are we NOT connected yet ? |
||
| 232 | if (!player->is_connected) |
||
| 233 | return (false); // consistency check: if we aren't connected, don't do anything |
||
| 234 | |||
| 235 | // are we NOT logged in yet AND is our socket valid AND is there nothing in the center of the screen yet ? |
||
| 236 | if (!player->is_logged_in && (player->our_socket != INVALID_SOCKET) && !the_scene.gui.central_text.is_displayed) |
||
| 237 | { |
||
| 140 | pmbaty | 238 | Scene_UpdateText (&the_scene.gui.central_text, RGBA_TO_RGBACOLOR (255, 255, 255, 191), DURATION_INFINITE, true, LOCALIZE (L"Connecting")); // display "connecting" in the middle of the screen |
| 1 | pmbaty | 239 | the_scene.gui.want_spinwheel = true; // start spinning wheel |
| 240 | } |
||
| 241 | |||
| 242 | do_update = false; // assume we don't need to update the scene until told otherwise |
||
| 243 | |||
| 244 | //////////////////////////// |
||
| 245 | // BEGIN listening to server |
||
| 246 | |||
| 247 | // proceed in filling the ascii buffer with what's coming |
||
| 248 | |||
| 249 | // get a hand on the end of the player's recv buffer and compute its remaining size |
||
| 250 | length = strlen (player->ascii_recvbuffer); |
||
| 251 | |||
| 252 | // if the server sent us something, append it to what we've received |
||
| 253 | recv_retval = recv (player->our_socket, &player->ascii_recvbuffer[length], player->recvbuffer_size - length, 0); |
||
| 254 | if (recv_retval > 0) |
||
| 255 | { |
||
| 256 | // parse all received data and eradicate all carriage returns. Also convert %'s to a safer glyph. |
||
| 257 | rewrite_index = 0; |
||
| 258 | for (byte_index = 0; byte_index < recv_retval; byte_index++) |
||
| 259 | if (player->ascii_recvbuffer[length + byte_index] != '\r') |
||
| 260 | { |
||
| 261 | if (player->ascii_recvbuffer[length + byte_index] == '%') |
||
| 262 | player->ascii_recvbuffer[length + rewrite_index] = '¤'; |
||
| 263 | else |
||
| 264 | player->ascii_recvbuffer[length + rewrite_index] = player->ascii_recvbuffer[length + byte_index]; |
||
| 265 | rewrite_index++; |
||
| 266 | } |
||
| 267 | player->ascii_recvbuffer[length + rewrite_index] = 0; // terminate the buffer ourselves |
||
| 268 | length = strlen (player->ascii_recvbuffer); // and update the new recvbuffer's length |
||
| 269 | } |
||
| 270 | else if (recv_retval == SOCKET_ERROR) |
||
| 271 | { |
||
| 272 | recv_retval = WSAGetLastError (); // ask Windows to be more specific about the error |
||
| 273 | if (recv_retval == WSAEWOULDBLOCK) |
||
| 274 | ; // it's okay. We're a non-blocking socket. |
||
| 275 | else if (recv_retval == WSAETIMEDOUT) |
||
| 276 | { |
||
| 277 | messagebox.hWndParent = hMainWnd; |
||
| 278 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 279 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_ConnectionToChessServerLost")); |
||
| 280 | messagebox.flags = MB_ICONWARNING | MB_OK; |
||
| 281 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 282 | |||
| 283 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 284 | return (false); |
||
| 285 | } |
||
| 286 | } |
||
| 287 | |||
| 288 | // END listening to server |
||
| 289 | ////////////////////////// |
||
| 290 | |||
| 291 | ////////////////////////////////// |
||
| 292 | // BEGIN evaluating server replies |
||
| 293 | |||
| 294 | // are we NOT logged in yet ? |
||
| 295 | if (!player->is_logged_in) |
||
| 296 | { |
||
| 297 | // is it a login prompt ? |
||
| 298 | if ((length > 7) && (strcmp (&player->ascii_recvbuffer[length - 7], "login: ") == 0)) |
||
| 299 | { |
||
| 300 | Player_SendBuffer_Add (player, 1000, L"%s\n", options.network.login); // send the login string |
||
| 301 | player->ascii_recvbuffer[0] = 0; // and discard recvbuffer as we've processed this message |
||
| 302 | } |
||
| 303 | |||
| 304 | // else is it a password prompt ? |
||
| 305 | else if (((length > 10) && (strcmp (&player->ascii_recvbuffer[length - 10], "password: ") == 0)) |
||
| 306 | || ((length > 3) && (strcmp (&player->ascii_recvbuffer[length - 3], "\":\n") == 0))) |
||
| 307 | { |
||
| 308 | Player_SendBuffer_Add (player, 1000, L"%s\n", options.network.password); // send the password string |
||
| 309 | player->ascii_recvbuffer[0] = 0; // and discard recvbuffer as we've processed this message |
||
| 310 | } |
||
| 311 | |||
| 312 | // else is it a confirmation that we've successfully logged in ? |
||
| 313 | else if (((block_start = strstr (player->ascii_recvbuffer, "\n**** Starting FICS session as ")) != NULL) |
||
| 314 | && (block_end = strstr (player->ascii_recvbuffer, " ****\n"))) |
||
| 315 | { |
||
| 316 | player->is_logged_in = true; // remember we are logged in |
||
| 317 | the_scene.gui.central_text.disappear_time = current_time + 1.0f; // fade the "connecting" phrase out now (FIXME: ugly) |
||
| 318 | the_scene.gui.want_spinwheel = false; // stop spinning wheel |
||
| 319 | do_update = true; // and update the scene |
||
| 320 | |||
| 321 | block_start += 31; // skip the "\n**** Starting FICS session as " substring |
||
| 322 | local_player = Player_FindByType (PLAYER_HUMAN); // get a pointer to the local player |
||
| 323 | |||
| 324 | // copy out local player's login name, as reported by server, and convert it to wchar_t |
||
| 325 | for (byte_index = 0; (byte_index < WCHAR_SIZEOF (local_player->name)) && isalpha (block_start[byte_index]); byte_index++) |
||
| 326 | local_player->name[byte_index] = (wchar_t) block_start[byte_index]; // copy nickname one character after the other. Very dirty conversion. |
||
| 327 | if (byte_index < WCHAR_SIZEOF (local_player->name)) |
||
| 328 | local_player->name[byte_index] = 0; // finish the string ourselves |
||
| 329 | else |
||
| 330 | local_player->name[WCHAR_SIZEOF (local_player->name) - 1] = 0; // truncate it if neeeded |
||
| 331 | |||
| 332 | server_motd[0] = 0; // remember we haven't read the MOTD yet |
||
| 333 | the_board.reevaluate = true; // reeevaluate the board (to update the title bar) |
||
| 334 | |||
| 335 | // see if there's more data to parse after this message, in which case move it in place |
||
| 336 | length = strlen (block_end + 6); |
||
| 337 | if (length > 0) |
||
| 338 | memmove (player->ascii_recvbuffer, block_end + 6, length + 1); |
||
| 339 | else |
||
| 340 | player->ascii_recvbuffer[0] = 0; // else discard recvbuffer as we've processed this message |
||
| 341 | } |
||
| 342 | } |
||
| 343 | |||
| 344 | // else we are logged in |
||
| 345 | else |
||
| 346 | { |
||
| 347 | // see if we have a complete reply block (remember: percent sign was replaced with '¤') |
||
| 348 | block_end = strstr (player->ascii_recvbuffer, "\nfics¤ "); |
||
| 349 | |||
| 350 | // as long as we can find some... |
||
| 351 | while (block_end != NULL) |
||
| 352 | { |
||
| 353 | *block_end = 0; // break the string here |
||
| 354 | |||
| 355 | // convert the block to wide char and evaluate it, taking action if needed |
||
| 356 | ConvertToWideChar (player->recvbuffer, player->recvbuffer_size, player->ascii_recvbuffer); |
||
| 357 | Debug_Log (L"RECEIVED:[%s]\n", player->recvbuffer); // log what we've received |
||
| 358 | EvaluateServerReply (player); // and evaluate it |
||
| 359 | |||
| 360 | // see if there's more data to parse after this message, in which case move it in place |
||
| 361 | length = strlen (block_end + 7); |
||
| 362 | if (length > 0) |
||
| 363 | memmove (player->ascii_recvbuffer, block_end + 7, length + 1); |
||
| 364 | else |
||
| 365 | { |
||
| 366 | player->ascii_recvbuffer[0] = 0; |
||
| 367 | break; // it was the last prompt, so discard recvbuffer as we've processed this message |
||
| 368 | } |
||
| 369 | block_end = strstr (player->ascii_recvbuffer, "\nfics¤ "); // remember: percent sign was replaced with '¤' |
||
| 370 | } |
||
| 371 | } |
||
| 372 | |||
| 373 | // END evaluating server replies |
||
| 374 | //////////////////////////////// |
||
| 375 | |||
| 376 | // have we been notified that the current player just changed, has at least one move been played AND is it the remote player's turn now ? |
||
| 377 | if (the_board.has_playerchanged && (the_board.move_count > 1) && (Board_ColorToMove (&the_board) == player->color)) |
||
| 378 | { |
||
| 379 | Debug_Log (L"===Local player just played, sending the chosen move to chess server===\n"); |
||
| 380 | Player_SendBuffer_Add (player, 1000, L"%s\n", the_board.moves[the_board.move_count - 1].pgntext); // send the move string to the chess server |
||
| 381 | } |
||
| 382 | |||
| 383 | // has the user entered some chatter text ? |
||
| 384 | if (!the_scene.gui.is_entering_text && (the_scene.gui.entered_ccreply.text != NULL)) |
||
| 385 | { |
||
| 386 | // is player logged in AND has a chatter channel been selected ? if so, send chat string to server |
||
| 387 | if (player->is_logged_in && (selected_chatterchannel != NULL)) |
||
| 388 | Player_SendBuffer_Add (player, 1000, L"+channel %d\ntell %d %s\n", selected_chatterchannel->id, selected_chatterchannel->id, the_scene.gui.entered_ccreply.text); |
||
| 389 | |||
| 390 | // reset the entered text buffer |
||
| 391 | SAFE_free ((void **) &the_scene.gui.entered_ccreply.text); // reset the entered text buffer |
||
| 392 | the_scene.gui.entered_ccreply.text_length = 0; // and set its length to zero |
||
| 393 | } |
||
| 394 | |||
| 395 | // does the local player want to cancel its last move ? this can be either HIS move or HIS OPPONENTS's move... |
||
| 396 | local_player = Player_FindByType (PLAYER_HUMAN); // get a pointer to the local player |
||
| 397 | if ((local_player != NULL) && local_player->wants_cancel) |
||
| 398 | { |
||
| 399 | Player_SendBuffer_Add (player, 1000, L"takeback\n"); // send the takeback request to our opponent |
||
| 400 | Interlocutor_Notify (Interlocutor_FindOrCreate (player->name), LOCALIZE (L"Chat_TakebackRequestSent"), player->name); // send a notification to its chat window |
||
| 136 | pmbaty | 401 | the_board.game_state = STATE_PLAYING; // remember the game is now playing (in case we wanted to cancel the closing move of a finished game, this opens the game again) |
| 1 | pmbaty | 402 | local_player->wants_cancel = false; // don't do this all day long |
| 403 | } |
||
| 404 | if (player->wants_cancel) |
||
| 405 | { |
||
| 406 | Player_SendBuffer_Add (player, 1000, L"takeback\n"); // send the takeback request to our opponent |
||
| 407 | Interlocutor_Notify (Interlocutor_FindOrCreate (player->name), LOCALIZE (L"Chat_TakebackRequestSent"), player->name); // send a notification to its chat window |
||
| 136 | pmbaty | 408 | the_board.game_state = STATE_PLAYING; // remember the game is now playing (in case we wanted to cancel the closing move of a finished game, this opens the game again) |
| 1 | pmbaty | 409 | player->wants_cancel = false; // don't do this all day long |
| 410 | } |
||
| 411 | |||
| 412 | // if we have something to send, do it |
||
| 413 | if (!player->sendbuffer_locked && (player->sendbuffer[0] != 0) && (animation_endtime + 1.0f < current_time)) |
||
| 414 | { |
||
| 415 | // log what we're sending |
||
| 416 | Debug_Log (L"SENDING:[%s]\n", player->sendbuffer); |
||
| 417 | |||
| 418 | player->sendbuffer_locked = true; // lock the buffer |
||
| 419 | |||
| 420 | // now read line per line (mallocate a line buffer as large as necessary) |
||
| 421 | length = wcslen (player->sendbuffer) + 1 + 1; // +1 for \n, +1 for null terminator |
||
| 422 | ascii_sendbuffer = (char *) SAFE_malloc (length, sizeof (char), false); |
||
| 423 | widechar_buffer = (wchar_t *) SAFE_malloc (length, sizeof (wchar_t), false); |
||
| 424 | widechar_line = player->sendbuffer; // start at the first character |
||
| 425 | while ((widechar_line = wcsgets (widechar_buffer, length, widechar_line)) != NULL) |
||
| 426 | { |
||
| 427 | wcscat_s (widechar_buffer, length, L"\n"); // put the carriage return back |
||
| 428 | ConvertTo7BitASCII (ascii_sendbuffer, length, widechar_buffer); // convert to ASCII |
||
| 429 | send_retval = send (player->our_socket, ascii_sendbuffer, strlen (ascii_sendbuffer), 0); // send data |
||
| 430 | } |
||
| 431 | SAFE_free ((void **) &widechar_buffer); // we no longer need the line buffer, so free it |
||
| 432 | SAFE_free ((void **) &ascii_sendbuffer); |
||
| 433 | |||
| 434 | player->sendbuffer[0] = 0; // what we had to send has been sent, reset the send buffer |
||
| 435 | player->sendbuffer_locked = false; // and unlock it |
||
| 436 | |||
| 437 | // did send() report an error ? |
||
| 438 | if (send_retval == SOCKET_ERROR) |
||
| 439 | { |
||
| 440 | messagebox.hWndParent = hMainWnd; |
||
| 441 | wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage")); |
||
| 442 | wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_ConnectionToChessServerLost")); |
||
| 443 | messagebox.flags = MB_ICONERROR | MB_OK; |
||
| 444 | DialogBox_Message (&messagebox); // display a modeless error message box |
||
| 445 | |||
| 446 | PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message |
||
| 447 | return (true); // on error, cancel |
||
| 448 | } |
||
| 449 | } |
||
| 450 | |||
| 451 | return (do_update); // finished |
||
| 452 | } |
||
| 453 | |||
| 454 | |||
| 455 | static void EvaluateServerReply (player_t *player) |
||
| 456 | { |
||
| 457 | // this function parses a network reply and evaluates it, deciding what to do |
||
| 458 | |||
| 459 | ////////////////////// |
||
| 460 | // OUT OF GAME REPLIES |
||
| 461 | |||
| 462 | // the MOTD is the first reply to be evaluated |
||
| 463 | EvaluateServerReply_MOTD (player); |
||
| 464 | |||
| 465 | // evaluate dangerous replies first, i.e. those that contain user-settable text |
||
| 466 | EvaluateServerReply_Announcement (player); |
||
| 467 | EvaluateServerReply_ChannelMessage (player); |
||
| 468 | EvaluateServerReply_PrivateMessage (player); |
||
| 469 | EvaluateServerReply_Finger (player); |
||
| 470 | |||
| 471 | // the less dangerous replies can now be evaluated without ambiguity |
||
| 472 | EvaluateServerReply_Seek (player); |
||
| 473 | EvaluateServerReply_Challenge (player); |
||
| 474 | EvaluateServerReply_ChallengeAccepted (player); |
||
| 475 | EvaluateServerReply_ChallengeDeclined (player); |
||
| 476 | EvaluateServerReply_Takeback (player); |
||
| 477 | EvaluateServerReply_TakebackDeclinedByOther (player); |
||
| 478 | EvaluateServerReply_TakebackDeclinedByYou (player); |
||
| 479 | EvaluateServerReply_PlayNotAllowed (player); |
||
| 480 | EvaluateServerReply_PlayUnexistent (player); |
||
| 481 | EvaluateServerReply_PlayWrongRating (player); |
||
| 482 | EvaluateServerReply_ChannelsAndMembers (player); |
||
| 483 | EvaluateServerReply_SoughtList (player); |
||
| 484 | EvaluateServerReply_PlayersList (player); |
||
| 485 | |||
| 486 | ////////////////// |
||
| 487 | // IN GAME REPLIES |
||
| 488 | |||
| 489 | EvaluateServerReply_GameStarting (player); |
||
| 490 | EvaluateServerReply_GameState (player); |
||
| 491 | EvaluateServerReply_GameResults (player); |
||
| 492 | |||
| 493 | return; // finished evaluating this reply |
||
| 494 | } |