Freeciv-3.3: /fast/freeciv/nightly/main/server/connecthand.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
connecthand.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <string.h>
19
20/* utility */
21#include "capability.h"
22#include "fcintl.h"
23#include "log.h"
24#include "mem.h"
25#include "rand.h"
26#include "support.h"
27
28/* common */
29#include "capstr.h"
30#include "events.h"
31#include "game.h"
32#include "packets.h"
33#include "player.h"
34#include "version.h"
35
36/* server */
37#include "aiiface.h"
38#include "auth.h"
39#include "diplhand.h"
40#include "edithand.h"
41#include "gamehand.h"
42#include "maphand.h"
43#include "meta.h"
44#include "notify.h"
45#include "plrhand.h"
46#include "report.h"
47#include "ruleload.h"
48#include "sernet.h"
49#include "settings.h"
50#include "srv_main.h"
51#include "stdinhand.h"
52#include "voting.h"
53
54/* server/scripting */
55#include "script_fcdb.h"
56
57#include "connecthand.h"
58
59
60static bool connection_attach_real(struct connection *pconn,
61 struct player *pplayer,
62 bool observing, bool connecting);
63
64/**********************************************************************/
72 void conn_set_access(struct connection *pconn, enum cmdlevel new_level,
73 bool granted)
74{
75 enum cmdlevel old_level = conn_get_access(pconn);
76
77 pconn->access_level = new_level;
78 if (granted) {
79 pconn->server.granted_access_level = new_level;
80 }
81
82 /* Send updated settings only if settings control already sent.
83 * Otherwise client is not ready to receive them, AND we will send
84 * them later anyway. */
85 if (old_level != new_level && pconn->server.settings_sent) {
86 send_server_access_level_settings(pconn->self, old_level, new_level);
87 }
88}
89
90/**********************************************************************/
97 static void restore_access_level(struct connection *pconn)
98{
99 /* Restore previous privileges. */
100 enum cmdlevel level = pconn->server.granted_access_level;
101
102 /* Detached connections must have at most the same privileges
103 * as observers, unless they were granted something higher than
104 * ALLOW_BASIC in the first place. */
105 if ((pconn->observer || !pconn->playing) && level == ALLOW_BASIC) {
106 level = ALLOW_INFO;
107 }
108
109 conn_set_access(pconn, level, FALSE);
110}
111
112/**********************************************************************/
130 void establish_new_connection(struct connection *pconn)
131{
132 struct conn_list *dest = pconn->self;
133 struct player *pplayer;
134 struct packet_server_join_reply packet;
135 struct packet_chat_msg connect_info;
136 char hostname[512];
137 bool delegation_error = FALSE;
138 struct packet_set_topology topo_packet;
139
140 /* Zero out the password */
141 memset(pconn->server.password, 0, sizeof(pconn->server.password));
142
143 /* Send join_reply packet */
144 packet.you_can_join = TRUE;
145 sz_strlcpy(packet.capability, our_capability);
146 fc_snprintf(packet.message, sizeof(packet.message), _("%s Welcome"),
147 pconn->username);
148 sz_strlcpy(packet.challenge_file, new_challenge_filename(pconn));
149 packet.conn_id = pconn->id;
150 send_packet_server_join_reply(pconn, &packet);
151
152 /* "establish" the connection */
153 pconn->established = TRUE;
154 pconn->server.status = AS_ESTABLISHED;
155
156 pconn->server.delegation.status = FALSE;
157 pconn->server.delegation.playing = nullptr;
158 pconn->server.delegation.observer = FALSE;
159 pconn->server.settings_sent = FALSE;
160
161 conn_list_append(game.est_connections, pconn);
162 if (conn_list_size(game.est_connections) == 1) {
163 /* First connection
164 * Replace "restarting in x seconds" meta message */
165 maybe_automatic_meta_message(default_meta_message_string());
166 (void) send_server_info_to_metaserver(META_INFO);
167 }
168
169 /* Introduce the server to the connection */
170 if (fc_gethostname(hostname, sizeof(hostname)) == 0) {
171 notify_conn(dest, nullptr, E_CONNECTION, ftc_any,
172 _("Welcome to the %s Server running at %s port %d."),
173 freeciv_name_version(), hostname, srvarg.port);
174 } else {
175 notify_conn(dest, nullptr, E_CONNECTION, ftc_any,
176 _("Welcome to the %s Server at port %d."),
177 freeciv_name_version(), srvarg.port);
178 }
179
180 /* FIXME: this (getting messages about others logging on) should be
181 * a message option for the client with event */
182
183 /* Notify the console that you're here. */
184 log_normal(_("%s has connected from %s."), pconn->username, pconn->addr);
185
186 if (srvarg.fcdb_enabled) {
187 script_fcdb_call("conn_established", pconn);
188 }
189
190 conn_compression_freeze(pconn);
191 send_rulesets(dest);
192 send_server_setting_control(pconn);
193 send_server_settings(dest);
194 send_scenario_info(dest);
195 send_scenario_description(dest);
196 send_game_info(dest);
197 topo_packet.topology_id = wld.map.topology_id;
198 topo_packet.wrap_id = wld.map.wrap_id;
199 send_packet_set_topology(pconn, &topo_packet);
200
201 /* Do we have a player that a delegate is currently controlling? */
202 if ((pplayer = player_by_user_delegated(pconn->username))) {
203 /* Reassert our control over the player. */
204 struct connection *pdelegate;
205
206 fc_assert_ret(player_delegation_get(pplayer) != nullptr);
207 pdelegate = conn_by_user(player_delegation_get(pplayer));
208
209 if (pdelegate && connection_delegate_restore(pdelegate)) {
210 /* Delegate now detached from our player. We will restore control
211 * over them as normal below. */
212 notify_conn(pconn->self, nullptr, E_CONNECTION, ftc_server,
213 _("Your delegate %s was controlling your player '%s'; "
214 "now detached."), pdelegate->username,
215 player_name(pplayer));
216 notify_conn(pdelegate->self, nullptr, E_CONNECTION, ftc_server,
217 _("%s reconnected, ending your delegated control of "
218 "player '%s'."), pconn->username, player_name(pplayer));
219 } else {
220 fc_assert(pdelegate);
221 /* This really shouldn't happen. */
222 log_error("Failed to revoke delegate %s's control of %s, so owner %s "
223 "can't regain control.", pdelegate->username,
224 player_name(pplayer), pconn->username);
225 notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
226 _("Couldn't get control of '%s' from delegation to %s."),
227 player_name(pplayer), pdelegate->username);
228 delegation_error = TRUE;
229 pplayer = nullptr;
230 }
231 }
232
233 if (!delegation_error) {
234 if ((pplayer = player_by_user(pconn->username))
235 && connection_attach_real(pconn, pplayer, FALSE, TRUE)) {
236 /* A player has already been created for this user, reconnect */
237
238 if (S_S_INITIAL == server_state()) {
239 send_player_info_c(nullptr, dest);
240 }
241 } else {
242 int total_free_weight = 0;
243
244 players_iterate(wplayer) {
245 if (wplayer->autoselect_weight > 0
246 && !wplayer->is_connected
247 && !player_has_flag(wplayer, PLRF_SCENARIO_RESERVED)) {
248 total_free_weight += wplayer->autoselect_weight;
249 }
250 } players_iterate_end;
251
252 if (total_free_weight > 0) {
253 int weight_rand = fc_rand(total_free_weight);
254
255 players_iterate(wplayer) {
256 if (wplayer->autoselect_weight > 0
257 && !wplayer->is_connected
258 && !player_has_flag(wplayer, PLRF_SCENARIO_RESERVED)) {
259 weight_rand -= wplayer->autoselect_weight;
260 if (weight_rand < 0) {
261 log_normal("Trying to attach %s to %s",
262 pconn->username, wplayer->name);
263 if (!connection_attach_real(pconn, wplayer, FALSE, TRUE)) {
264 notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
265 _("Couldn't attach your connection to a scenario player."));
266 log_verbose("%s is not attached to a player", pconn->username);
267 }
268 break;
269 }
270 }
271 } players_iterate_end;
272 } else if (!game_was_started()) {
273 if (connection_attach_real(pconn, nullptr, FALSE, TRUE)) {
274 pplayer = conn_get_player(pconn);
275 fc_assert(pplayer != nullptr);
276 } else {
277 notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
278 _("Couldn't attach your connection to new player."));
279 log_verbose("%s is not attached to a player", pconn->username);
280 }
281 }
282 send_player_info_c(nullptr, dest);
283 }
284 }
285
286 send_conn_info(game.est_connections, dest);
287
288 if (pplayer == nullptr) {
289 /* Else this has already been done in connection_attach_real(). */
290 send_pending_events(pconn, TRUE);
291 send_running_votes(pconn, FALSE);
292 restore_access_level(pconn);
293 send_conn_info(dest, game.est_connections);
294
295 notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
296 _("You are logged in as '%s' connected to no player."),
297 pconn->username);
298 } else {
299 notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
300 _("You are logged in as '%s' connected to %s."),
301 pconn->username,
302 player_name(pconn->playing));
303 }
304
305 /* Send information about delegation(s). */
306 send_delegation_info(pconn);
307
308 /* Notify the *other* established connections that you are connected, and
309 * add the info for all in event cache. Note we must to do it after we
310 * sent the pending events to pconn (from this function and also
311 * connection_attach()), otherwise pconn will receive it too. */
312 if (conn_controls_player(pconn)) {
313 if (game.server.ip_hide) {
314 package_event(&connect_info, nullptr, E_CONNECTION, ftc_server,
315 _("%s has connected (player %s)."),
316 pconn->username,
317 player_name(conn_get_player(pconn)));
318 } else {
319 package_event(&connect_info, nullptr, E_CONNECTION, ftc_server,
320 _("%s has connected from %s (player %s)."),
321 pconn->username, pconn->addr,
322 player_name(conn_get_player(pconn)));
323 }
324 } else {
325 if (game.server.ip_hide) {
326 package_event(&connect_info, nullptr, E_CONNECTION, ftc_server,
327 _("%s has connected."),
328 pconn->username);
329 } else {
330 package_event(&connect_info, nullptr, E_CONNECTION, ftc_server,
331 _("%s has connected from %s."),
332 pconn->username, pconn->addr);
333 }
334 }
335 conn_list_iterate(game.est_connections, aconn) {
336 if (aconn != pconn) {
337 send_packet_chat_msg(aconn, &connect_info);
338 }
339 } conn_list_iterate_end;
340 event_cache_add_for_all(&connect_info);
341
342 /* If need be, tell who we're waiting on to end the game.info.turn */
343 if (S_S_RUNNING == server_state() && game.server.turnblock) {
344 players_iterate_alive(cplayer) {
345 if (is_human(cplayer)
346 && !cplayer->phase_done
347 && cplayer != pconn->playing) { /* skip current player */
348 notify_conn(dest, nullptr, E_CONNECTION, ftc_any,
349 _("Turn-blocking game play: "
350 "waiting on %s to finish turn..."),
351 player_name(cplayer));
352 }
353 } players_iterate_alive_end;
354 }
355
356 if (game.info.is_edit_mode) {
357 notify_conn(dest, nullptr, E_SETTING, ftc_editor,
358 _(" *** Server is in edit mode. *** "));
359 }
360
361 if (pplayer != nullptr) {
362 /* Else, no need to do anything. */
363 reset_all_start_commands(TRUE);
364 (void) send_server_info_to_metaserver(META_INFO);
365 }
366
367 send_current_history_report(pconn->self);
368
369 conn_compression_thaw(pconn);
370}
371
372/**********************************************************************/
375 void reject_new_connection(const char *msg, struct connection *pconn)
376{
377 struct packet_server_join_reply packet;
378
379 /* Zero out the password */
380 memset(pconn->server.password, 0, sizeof(pconn->server.password));
381
382 packet.you_can_join = FALSE;
383 sz_strlcpy(packet.capability, our_capability);
384 sz_strlcpy(packet.message, msg);
385 packet.challenge_file[0] = '\0';
386 packet.conn_id = -1;
387 send_packet_server_join_reply(pconn, &packet);
388 log_normal(_("Client rejected: %s."), conn_description(pconn));
389 flush_connection_send_buffer_all(pconn);
390}
391
392/**********************************************************************/
396 bool handle_login_request(struct connection *pconn,
397 struct packet_server_join_req *req)
398{
399 char msg[MAX_LEN_MSG];
400 int kick_time_remaining;
401
402 if (pconn->established || pconn->server.status != AS_NOT_ESTABLISHED) {
403 /* We read the PACKET_SERVER_JOIN_REQ twice from this connection,
404 * this is probably not a Freeciv client. */
405 return FALSE;
406 }
407
408 log_normal(_("Connection request from %s from %s"),
409 req->username, pconn->addr);
410
411 /* Print server and client capabilities to console */
412 log_normal(_("%s has client version %d.%d.%d%s"),
413 pconn->username, req->major_version, req->minor_version,
414 req->patch_version, req->version_label);
415 log_verbose("Client caps: %s", req->capability);
416 log_verbose("Server caps: %s", our_capability);
417 conn_set_capability(pconn, req->capability);
418
419 /* Make sure the server has every capability the client needs */
420 if (!has_capabilities(our_capability, req->capability)) {
421 fc_snprintf(msg, sizeof(msg),
422 _("The client is missing a capability that this server needs.\n"
423 "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
424 " Upgrading may help!"),
425 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
426 req->major_version, req->minor_version,
427 req->patch_version, req->version_label);
428 reject_new_connection(msg, pconn);
429 log_normal(_("%s was rejected: Mismatched capabilities."),
430 req->username);
431 return FALSE;
432 }
433
434 /* Make sure the client has every capability the server needs */
435 if (!has_capabilities(req->capability, our_capability)) {
436 fc_snprintf(msg, sizeof(msg),
437 _("The server is missing a capability that the client needs.\n"
438 "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
439 " Upgrading may help!"),
440 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
441 req->major_version, req->minor_version,
442 req->patch_version, req->version_label);
443 reject_new_connection(msg, pconn);
444 log_normal(_("%s was rejected: Mismatched capabilities."),
445 req->username);
446 return FALSE;
447 }
448
449 {
450 /* Client is compatible. That includes ability to receive server info.
451 * Send it. */
452 struct packet_server_info info;
453
454 info.major_version = MAJOR_VERSION;
455 info.minor_version = MINOR_VERSION;
456 info.patch_version = PATCH_VERSION;
457#ifdef EMERGENCY_VERSION
458 info.emerg_version = EMERGENCY_VERSION;
459#else
460 info.emerg_version = 0;
461#endif
462 sz_strlcpy(info.version_label, VERSION_LABEL);
463 send_packet_server_info(pconn, &info);
464 }
465
466 remove_leading_trailing_spaces(req->username);
467
468 /* Name-sanity check: could add more checks? */
469 if (!is_valid_username(req->username)) {
470 fc_snprintf(msg, sizeof(msg), _("Invalid username '%s'"), req->username);
471 reject_new_connection(msg, pconn);
472 log_normal(_("%s was rejected: Invalid name [%s]."),
473 req->username, pconn->addr);
474 return FALSE;
475 }
476
477 if (conn_is_kicked(pconn, &kick_time_remaining)) {
478 fc_snprintf(msg, sizeof(msg), _("You have been kicked from this server "
479 "and cannot reconnect for %d seconds."),
480 kick_time_remaining);
481 reject_new_connection(msg, pconn);
482 log_normal(_("%s was rejected: Connection kicked "
483 "(%d seconds remaining)."),
484 req->username, kick_time_remaining);
485 return FALSE;
486 }
487
488 /* Don't allow duplicate logins */
489 conn_list_iterate(game.all_connections, aconn) {
490 if (fc_strcasecmp(req->username, aconn->username) == 0) {
491 fc_snprintf(msg, sizeof(msg), _("'%s' already connected."),
492 req->username);
493 reject_new_connection(msg, pconn);
494 log_normal(_("%s was rejected: Duplicate login name [%s]."),
495 req->username, pconn->addr);
496 return FALSE;
497 }
498 } conn_list_iterate_end;
499
500 /* Remove the ping timeout given in sernet.c:server_make_connection(). */
501 fc_assert_msg(1 == timer_list_size(pconn->server.ping_timers),
502 "Ping timer list size %d, should be 1. Have we sent "
503 "a ping to unestablished connection %s?",
504 timer_list_size(pconn->server.ping_timers),
505 conn_description(pconn));
506 timer_list_pop_front(pconn->server.ping_timers);
507
508 if (game.server.connectmsg[0] != '\0') {
509 log_debug("Sending connectmsg: %s", game.server.connectmsg);
510 dsend_packet_connect_msg(pconn, game.server.connectmsg);
511 }
512
513 if (srvarg.auth_enabled) {
514 return auth_user(pconn, req->username);
515 } else {
516 sz_strlcpy(pconn->username, req->username);
517 establish_new_connection(pconn);
518 return TRUE;
519 }
520}
521
522/**********************************************************************/
530 void lost_connection_to_client(struct connection *pconn)
531{
532 const char *desc = conn_description(pconn);
533
534 fc_assert_ret(pconn->server.is_closing);
535
536 log_normal(_("Lost connection: %s."), desc);
537
538 /* Special color (white on black) for player loss */
539 notify_conn(game.est_connections, nullptr, E_CONNECTION,
540 conn_controls_player(pconn) ? ftc_player_lost : ftc_server,
541 _("Lost connection: %s."), desc);
542
543 connection_detach(pconn, TRUE);
544 send_conn_info_remove(pconn->self, game.est_connections);
545 notify_if_first_access_level_is_available();
546
547 check_for_full_turn_done();
548}
549
550/**********************************************************************/
553 static void package_conn_info(struct connection *pconn,
554 struct packet_conn_info *packet)
555{
556 packet->id = pconn->id;
557 packet->used = pconn->used;
558 packet->established = pconn->established;
559 packet->player_num = (pconn->playing != nullptr)
560 ? player_number(pconn->playing)
561 : player_slot_count();
562 packet->observer = pconn->observer;
563 packet->access_level = pconn->access_level;
564
565 sz_strlcpy(packet->username, pconn->username);
566 if (game.server.ip_hide) {
567 sz_strlcpy(packet->addr, Q_("?IP:Hidden"));
568 } else {
569 sz_strlcpy(packet->addr, pconn->addr);
570 }
571 sz_strlcpy(packet->capability, pconn->capability);
572}
573
574/**********************************************************************/
579 static void send_conn_info_arg(struct conn_list *src,
580 struct conn_list *dest, bool remove_conn)
581{
582 struct packet_conn_info packet;
583
584 if (!dest) {
585 dest = game.est_connections;
586 }
587
588 conn_list_iterate(src, psrc) {
589 package_conn_info(psrc, &packet);
590 if (remove_conn) {
591 packet.used = FALSE;
592 }
593 lsend_packet_conn_info(dest, &packet);
594 } conn_list_iterate_end;
595}
596
597/**********************************************************************/
601 void send_conn_info(struct conn_list *src, struct conn_list *dest)
602{
603 send_conn_info_arg(src, dest, FALSE);
604}
605
606/**********************************************************************/
610 void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
611{
612 send_conn_info_arg(src, dest, TRUE);
613}
614
615/**********************************************************************/
618 struct player *find_uncontrolled_player(void)
619{
620 players_iterate(played) {
621 if (!played->is_connected && !played->was_created) {
622 return played;
623 }
624 } players_iterate_end;
625
626 return nullptr;
627}
628
629/**********************************************************************/
645 static bool connection_attach_real(struct connection *pconn,
646 struct player *pplayer,
647 bool observing, bool connecting)
648{
649 fc_assert_ret_val(pconn != nullptr, FALSE);
650 fc_assert_ret_val_msg(!pconn->observer && pconn->playing == nullptr, FALSE,
651 "connections must be detached with "
652 "connection_detach() before calling this!");
653
654 if (!observing) {
655 if (pplayer == nullptr) {
656 /* Search for uncontrolled player */
657 pplayer = find_uncontrolled_player();
658
659 if (pplayer == nullptr) {
660 /* No uncontrolled player found */
661 if (player_count() >= game.server.max_players
662 || normal_player_count() >= server.playable_nations) {
663 return FALSE;
664 }
665 /* Add new player, or not */
666 /* Should only be called in such a way as to create a new player
667 * in the pregame */
668 fc_assert_ret_val(!game_was_started(), FALSE);
669 pplayer = server_create_player(-1, default_ai_type_name(),
670 nullptr, FALSE);
671 /* Pregame => no need to assign_player_colors() */
672 if (!pplayer) {
673 return FALSE;
674 }
675 } else {
676 team_remove_player(pplayer);
677 }
678 server_player_init(pplayer, FALSE, TRUE);
679
680 /* Make it human! */
681 set_as_human(pplayer);
682 }
683
684 sz_strlcpy(pplayer->username, pconn->username);
685 pplayer->unassigned_user = FALSE;
686 pplayer->user_turns = 0; /* Reset for a new user */
687 pplayer->is_connected = TRUE;
688
689 if (!game_was_started()) {
690 if (!pplayer->was_created && pplayer->nation == nullptr) {
691 /* Temporarily set player_name() to username. */
692 server_player_set_name(pplayer, pconn->username);
693 }
694 (void) aifill(game.info.aifill);
695 }
696
697 if (game.server.auto_ai_toggle && !is_human(pplayer)) {
698 toggle_ai_player_direct(nullptr, pplayer);
699 }
700
701 send_player_info_c(pplayer, game.est_connections);
702
703 /* Remove from global observers list, if was there */
704 conn_list_remove(game.glob_observers, pconn);
705 } else if (pplayer == nullptr) {
706 /* Global observer */
707 bool already = FALSE;
708
709 fc_assert(observing);
710
711 conn_list_iterate(game.glob_observers, pconn2) {
712 if (pconn2 == pconn) {
713 already = TRUE;
714 break;
715 }
716 } conn_list_iterate_end;
717
718 if (!already) {
719 conn_list_append(game.glob_observers, pconn);
720 }
721 }
722
723 /* We don't want the connection's username on another player. */
724 players_iterate(aplayer) {
725 if (aplayer != pplayer
726 && !fc_strncmp(aplayer->username, pconn->username, MAX_LEN_NAME)) {
727 sz_strlcpy(aplayer->username, _(ANON_USER_NAME));
728 aplayer->unassigned_user = TRUE;
729 send_player_info_c(aplayer, nullptr);
730 }
731 } players_iterate_end;
732
733 pconn->observer = observing;
734 pconn->playing = pplayer;
735 if (pplayer) {
736 conn_list_append(pplayer->connections, pconn);
737 }
738
739 restore_access_level(pconn);
740
741 /* Reset the delta-state. */
742 send_conn_info(pconn->self, game.est_connections); /* Client side. */
743 conn_reset_delta_state(pconn); /* Server side. */
744
745 /* Initial packets don't need to be resent. See comment for
746 * connecthand.c::establish_new_connection(). */
747 switch (server_state()) {
748 case S_S_INITIAL:
749 send_pending_events(pconn, connecting);
750 send_running_votes(pconn, !connecting);
751 break;
752
753 case S_S_RUNNING:
754 conn_compression_freeze(pconn);
755 send_all_info(pconn->self);
756 if (game.info.is_edit_mode && can_conn_edit(pconn)) {
757 edithand_send_initial_packets(pconn->self);
758 }
759 conn_compression_thaw(pconn);
760 /* Enter C_S_RUNNING client state. */
761 dsend_packet_start_phase(pconn, game.info.phase);
762 /* Must be after C_S_RUNNING client state to be effective. */
763 send_diplomatic_meetings(pconn);
764 send_pending_events(pconn, connecting);
765 send_running_votes(pconn, !connecting);
766 break;
767
768 case S_S_OVER:
769 conn_compression_freeze(pconn);
770 send_all_info(pconn->self);
771 if (game.info.is_edit_mode && can_conn_edit(pconn)) {
772 edithand_send_initial_packets(pconn->self);
773 }
774 conn_compression_thaw(pconn);
775 report_final_scores(pconn->self);
776 send_pending_events(pconn, connecting);
777 send_running_votes(pconn, !connecting);
778 if (!connecting) {
779 /* Send information about delegation(s). */
780 send_delegation_info(pconn);
781 }
782 break;
783 }
784
785 send_updated_vote_totals(nullptr);
786
787 return TRUE;
788}
789
790/**********************************************************************/
793 bool connection_attach(struct connection *pconn, struct player *pplayer,
794 bool observing)
795{
796 return connection_attach_real(pconn, pplayer, observing, FALSE);
797}
798
799/**********************************************************************/
809 void connection_detach(struct connection *pconn, bool remove_unused_player)
810{
811 struct player *pplayer;
812
813 fc_assert_ret(pconn != nullptr);
814
815 if ((pplayer = pconn->playing) != nullptr) {
816 bool was_connected = pplayer->is_connected;
817
818 send_remove_team_votes(pconn);
819 conn_list_remove(pplayer->connections, pconn);
820 pconn->playing = nullptr;
821 pconn->observer = FALSE;
822 restore_access_level(pconn);
823 cancel_connection_votes(pconn);
824 send_updated_vote_totals(nullptr);
825 send_conn_info(pconn->self, game.est_connections);
826
827 /* If any other (non-observing) conn is attached to this player, the
828 * player is still connected. */
829 pplayer->is_connected = FALSE;
830 conn_list_iterate(pplayer->connections, aconn) {
831 if (!aconn->observer) {
832 pplayer->is_connected = TRUE;
833 break;
834 }
835 } conn_list_iterate_end;
836
837 if (was_connected && !pplayer->is_connected) {
838 /* Player just lost its controlling connection. */
839 if (remove_unused_player
840 && !pplayer->was_created && !game_was_started()) {
841 /* Remove player. */
842 conn_list_iterate(pplayer->connections, aconn) {
843 /* Detach all. */
844 fc_assert_action(aconn != pconn, continue);
845 notify_conn(aconn->self, nullptr, E_CONNECTION, ftc_server,
846 _("Detaching from %s."), player_name(pplayer));
847 /* Recursive... but shouldn't be a problem, as this can only
848 * be a non-controlling connection so can't get back here. */
849 connection_detach(aconn, TRUE);
850 } conn_list_iterate_end;
851
852 /* Actually do the removal. */
853 server_remove_player(pplayer);
854 (void) aifill(game.info.aifill);
855 reset_all_start_commands(TRUE);
856 } else {
857 /* Aitoggle the player if no longer connected. */
858 if (game.server.auto_ai_toggle && is_human(pplayer)) {
859 toggle_ai_player_direct(nullptr, pplayer);
860 /* send_player_info_c() was formerly updated by
861 * toggle_ai_player_direct(), so it must be safe to send here now?
862 *
863 * At other times, data from send_conn_info() is used by the
864 * client to display player information.
865 * See establish_new_connection().
866 */
867 log_verbose("connection_detach() calls send_player_info_c()");
868 send_player_info_c(pplayer, nullptr);
869
870 reset_all_start_commands(TRUE);
871 }
872 }
873 }
874 } else {
875 pconn->observer = FALSE;
876 restore_access_level(pconn);
877 send_conn_info(pconn->self, game.est_connections);
878 }
879}
880
881/**********************************************************************/
884 bool connection_delegate_take(struct connection *pconn,
885 struct player *dplayer)
886{
887 fc_assert_ret_val(!pconn->server.delegation.status, FALSE);
888
889 /* Save the original player of this connection and the original username of
890 * the player. */
891 pconn->server.delegation.status = TRUE;
892 pconn->server.delegation.playing = conn_get_player(pconn);
893 pconn->server.delegation.observer = pconn->observer;
894 if (conn_controls_player(pconn)) {
895 /* Setting orig_username in the player we're about to put aside is
896 * a flag that no-one should be allowed to mess with it (e.g. /take). */
897 struct player *oplayer = conn_get_player(pconn);
898
899 fc_assert_ret_val(oplayer != dplayer, FALSE);
900 fc_assert_ret_val(strlen(oplayer->server.orig_username) == 0, FALSE);
901 sz_strlcpy(oplayer->server.orig_username, oplayer->username);
902 }
903 fc_assert_ret_val(strlen(dplayer->server.orig_username) == 0, FALSE);
904 sz_strlcpy(dplayer->server.orig_username, dplayer->username);
905
906 /* Detach the current connection. */
907 if (pconn->playing != nullptr || pconn->observer) {
908 connection_detach(pconn, FALSE);
909 }
910
911 /* Try to attach to the new player */
912 if (!connection_attach(pconn, dplayer, FALSE)) {
913
914 /* Restore original connection. */
915#ifndef FREECIV_NDEBUG
916 bool success =
917#endif
918 connection_attach(pconn,
919 pconn->server.delegation.playing,
920 pconn->server.delegation.observer);
921 fc_assert_ret_val(success, FALSE);
922
923 /* Reset all changes done above. */
924 pconn->server.delegation.status = FALSE;
925 pconn->server.delegation.playing = nullptr;
926 pconn->server.delegation.observer = FALSE;
927 if (conn_controls_player(pconn)) {
928 struct player *oplayer = conn_get_player(pconn);
929 oplayer->server.orig_username[0] = '\0';
930 }
931 dplayer->server.orig_username[0] = '\0';
932
933 return FALSE;
934 }
935
936 return TRUE;
937}
938
939/**********************************************************************/
945 bool connection_delegate_restore(struct connection *pconn)
946{
947 struct player *dplayer;
948
949 if (!pconn->server.delegation.status) {
950 return FALSE;
951 }
952
953 if (pconn->server.delegation.playing
954 && !pconn->server.delegation.observer) {
955 /* If restoring to controlling another player, and we're not the
956 * original controller of that player, something's gone wrong. */
957 fc_assert_ret_val(
958 strcmp(pconn->server.delegation.playing->server.orig_username,
959 pconn->username) == 0, FALSE);
960 }
961
962 /* Save the current (delegated) player. */
963 dplayer = conn_get_player(pconn);
964
965 /* There should be a delegated player connected to pconn. */
966 fc_assert_ret_val(dplayer, FALSE);
967
968 /* Detach the current (delegate) connection from the delegated player. */
969 if (pconn->playing != nullptr || pconn->observer) {
970 connection_detach(pconn, FALSE);
971 }
972
973 /* Try to attach to the delegate's original player */
974 if ((pconn->server.delegation.playing != nullptr
975 || pconn->server.delegation.observer)
976 && !connection_attach(pconn, pconn->server.delegation.playing,
977 pconn->server.delegation.observer)) {
978 return FALSE;
979 }
980
981 /* Reset data. */
982 pconn->server.delegation.status = FALSE;
983 pconn->server.delegation.playing = nullptr;
984 pconn->server.delegation.observer = FALSE;
985 if (conn_controls_player(pconn) && conn_get_player(pconn) != nullptr) {
986 /* Remove flag that we had 'put aside' our original player. */
987 struct player *oplayer = conn_get_player(pconn);
988
989 fc_assert_ret_val(oplayer != dplayer, FALSE);
990 oplayer->server.orig_username[0] = '\0';
991 }
992
993 /* Restore the username of the original controller in the previously-
994 * delegated player. */
995 sz_strlcpy(dplayer->username, dplayer->server.orig_username);
996 dplayer->server.orig_username[0] = '\0';
997 /* Send updated username to all connections. */
998 send_player_info_c(dplayer, nullptr);
999
1000 return TRUE;
1001}
1002
1003/**********************************************************************/
1007 void connection_close_server(struct connection *pconn, const char *reason)
1008{
1009 /* Restore possible delegations before the connection is closed. */
1010 connection_delegate_restore(pconn);
1011 connection_close(pconn, reason);
1012}
default_ai_type_name
const char * default_ai_type_name(void)
Definition aiiface.c:264
aiiface.h
auth_user
bool auth_user(struct connection *pconn, char *username)
Definition auth.c:73
auth.h
has_capabilities
bool has_capabilities(const char *us, const char *them)
Definition capability.c:86
capability.h
our_capability
const char *const our_capability
Definition capstr.c:32
capstr.h
incite_cost
char * incite_cost
Definition comments.c:74
MAX_LEN_MSG
#define MAX_LEN_MSG
Definition conn_types.h:37
connection_attach_real
static bool connection_attach_real(struct connection *pconn, struct player *pplayer, bool observing, bool connecting)
Definition connecthand.c:645
send_conn_info
void send_conn_info(struct conn_list *src, struct conn_list *dest)
Definition connecthand.c:601
connection_attach
bool connection_attach(struct connection *pconn, struct player *pplayer, bool observing)
Definition connecthand.c:793
package_conn_info
static void package_conn_info(struct connection *pconn, struct packet_conn_info *packet)
Definition connecthand.c:553
reject_new_connection
void reject_new_connection(const char *msg, struct connection *pconn)
Definition connecthand.c:375
send_conn_info_arg
static void send_conn_info_arg(struct conn_list *src, struct conn_list *dest, bool remove_conn)
Definition connecthand.c:579
connection_delegate_take
bool connection_delegate_take(struct connection *pconn, struct player *dplayer)
Definition connecthand.c:884
handle_login_request
bool handle_login_request(struct connection *pconn, struct packet_server_join_req *req)
Definition connecthand.c:396
find_uncontrolled_player
struct player * find_uncontrolled_player(void)
Definition connecthand.c:618
restore_access_level
static void restore_access_level(struct connection *pconn)
Definition connecthand.c:97
lost_connection_to_client
void lost_connection_to_client(struct connection *pconn)
Definition connecthand.c:530
connection_close_server
void connection_close_server(struct connection *pconn, const char *reason)
Definition connecthand.c:1007
connection_detach
void connection_detach(struct connection *pconn, bool remove_unused_player)
Definition connecthand.c:809
conn_set_access
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Definition connecthand.c:72
connection_delegate_restore
bool connection_delegate_restore(struct connection *pconn)
Definition connecthand.c:945
send_conn_info_remove
void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
Definition connecthand.c:610
establish_new_connection
void establish_new_connection(struct connection *pconn)
Definition connecthand.c:130
connecthand.h
conn_get_player
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:763
can_conn_edit
bool can_conn_edit(const struct connection *pconn)
Definition connection.c:511
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:377
flush_connection_send_buffer_all
void flush_connection_send_buffer_all(struct connection *pc)
Definition connection.c:230
conn_set_capability
void conn_set_capability(struct connection *pconn, const char *capability)
Definition connection.c:661
conn_reset_delta_state
void conn_reset_delta_state(struct connection *pc)
Definition connection.c:673
connection_close
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
conn_controls_player
bool conn_controls_player(const struct connection *pconn)
Definition connection.c:745
conn_description
const char * conn_description(const struct connection *pconn)
Definition connection.c:474
conn_compression_freeze
void conn_compression_freeze(struct connection *pconn)
Definition connection.c:694
conn_get_access
enum cmdlevel conn_get_access(const struct connection *pconn)
Definition connection.c:775
AS_NOT_ESTABLISHED
@ AS_NOT_ESTABLISHED
Definition connection.h:93
AS_ESTABLISHED
@ AS_ESTABLISHED
Definition connection.h:97
conn_compression_thaw
bool conn_compression_thaw(struct connection *pconn)
Definition packets.c:194
conn_list_iterate
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
conn_list_iterate_end
#define conn_list_iterate_end
Definition connection.h:110
send_diplomatic_meetings
void send_diplomatic_meetings(struct connection *dest)
Definition diplhand.c:885
diplhand.h
edithand_send_initial_packets
void edithand_send_initial_packets(struct conn_list *dest)
Definition edithand.c:112
edithand.h
events.h
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
ftc_player_lost
const struct ft_color ftc_player_lost
Definition featured_text.c:83
ftc_server
const struct ft_color ftc_server
Definition featured_text.c:77
ftc_editor
const struct ft_color ftc_editor
Definition featured_text.c:79
ftc_any
const struct ft_color ftc_any
Definition featured_text.c:73
game
struct civ_game game
Definition game.c:62
wld
struct world wld
Definition game.c:63
game.h
send_scenario_description
void send_scenario_description(struct conn_list *dest)
Definition gamehand.c:967
send_scenario_info
void send_scenario_info(struct conn_list *dest)
Definition gamehand.c:953
send_game_info
void send_game_info(struct conn_list *dest)
Definition gamehand.c:910
new_challenge_filename
const char * new_challenge_filename(struct connection *pc)
Definition gamehand.c:1099
gamehand.h
log.h
fc_assert_msg
#define fc_assert_msg(condition, message,...)
Definition log.h:181
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
fc_assert_action
#define fc_assert_action(condition, action)
Definition log.h:187
log_debug
#define log_debug(message,...)
Definition log.h:115
log_normal
#define log_normal(message,...)
Definition log.h:107
log_error
#define log_error(message,...)
Definition log.h:103
fc_assert_ret_val_msg
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
maphand.h
mem.h
maybe_automatic_meta_message
void maybe_automatic_meta_message(const char *automatic)
Definition meta.c:152
default_meta_message_string
const char * default_meta_message_string(void)
Definition meta.c:91
send_server_info_to_metaserver
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:491
meta.h
META_INFO
@ META_INFO
Definition meta.h:26
send_pending_events
void send_pending_events(struct connection *pconn, bool include_public)
Definition notify.c:754
notify_conn
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:239
package_event
void package_event(struct packet_chat_msg *packet, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:168
event_cache_add_for_all
void event_cache_add_for_all(const struct packet_chat_msg *packet)
Definition notify.c:620
notify.h
packets.h
dsend_packet_connect_msg
int dsend_packet_connect_msg(struct connection *pc, const char *message)
Definition packets_gen.c:12643
lsend_packet_conn_info
void lsend_packet_conn_info(struct conn_list *dest, const struct packet_conn_info *packet)
Definition packets_gen.c:38583
send_packet_server_info
int send_packet_server_info(struct connection *pc, const struct packet_server_info *packet)
Definition packets_gen.c:12974
send_packet_chat_msg
int send_packet_chat_msg(struct connection *pc, const struct packet_chat_msg *packet)
Definition packets_gen.c:11869
send_packet_set_topology
int send_packet_set_topology(struct connection *pc, const struct packet_set_topology *packet)
Definition packets_gen.c:77714
dsend_packet_start_phase
int dsend_packet_start_phase(struct connection *pc, int phase)
Definition packets_gen.c:39671
send_packet_server_join_reply
int send_packet_server_join_reply(struct connection *pc, const struct packet_server_join_reply *packet)
Definition packets_gen.c:1940
is_valid_username
bool is_valid_username(const char *name)
Definition player.c:1912
player_count
int player_count(void)
Definition player.c:817
player_slot_count
int player_slot_count(void)
Definition player.c:418
player_number
int player_number(const struct player *pplayer)
Definition player.c:837
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:895
player_has_flag
bool player_has_flag(const struct player *pplayer, enum plr_flag_id flag)
Definition player.c:1994
player_by_user
struct player * player_by_user(const char *name)
Definition player.c:940
player.h
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
ANON_USER_NAME
#define ANON_USER_NAME
Definition player.h:48
set_as_human
#define set_as_human(plr)
Definition player.h:233
players_iterate_alive_end
#define players_iterate_alive_end
Definition player.h:549
is_human
#define is_human(plr)
Definition player.h:231
players_iterate_alive
#define players_iterate_alive(_pplayer)
Definition player.h:544
server_player_set_name
void server_player_set_name(struct player *pplayer, const char *name)
Definition plrhand.c:2268
server_create_player
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Definition plrhand.c:1894
normal_player_count
int normal_player_count(void)
Definition plrhand.c:3208
player_by_user_delegated
struct player * player_by_user_delegated(const char *name)
Definition plrhand.c:3322
send_player_info_c
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1146
send_delegation_info
void send_delegation_info(const struct connection *pconn)
Definition plrhand.c:3278
server_remove_player
void server_remove_player(struct player *pplayer)
Definition plrhand.c:1943
server_player_init
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Definition plrhand.c:1618
player_delegation_get
const char * player_delegation_get(const struct player *pplayer)
Definition plrhand.c:3241
reset_all_start_commands
void reset_all_start_commands(bool plrchange)
Definition plrhand.c:2724
plrhand.h
rand.h
fc_rand
#define fc_rand(_size)
Definition rand.h:56
report_final_scores
void report_final_scores(struct conn_list *dest)
Definition report.c:1690
send_current_history_report
void send_current_history_report(struct conn_list *dest)
Definition report.c:302
report.h
send_rulesets
void send_rulesets(struct conn_list *dest)
Definition ruleload.c:9536
ruleload.h
script_fcdb_call
bool script_fcdb_call(const char *func_name,...)
Definition script_fcdb.c:359
script_fcdb.h
sernet.h
level
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
send_server_setting_control
void send_server_setting_control(struct connection *pconn)
Definition settings.c:5431
send_server_settings
void send_server_settings(struct conn_list *dest)
Definition settings.c:5387
send_server_access_level_settings
void send_server_access_level_settings(struct conn_list *dest, enum cmdlevel old_level, enum cmdlevel new_level)
Definition settings.c:5399
settings.h
remove_leading_trailing_spaces
void remove_leading_trailing_spaces(char *s)
Definition shared.c:444
aifill
const char * aifill(int amount)
Definition srv_main.c:2503
game_was_started
bool game_was_started(void)
Definition srv_main.c:353
srvarg
struct server_arguments srvarg
Definition srv_main.c:180
check_for_full_turn_done
void check_for_full_turn_done(void)
Definition srv_main.c:2253
send_all_info
void send_all_info(struct conn_list *dest)
Definition srv_main.c:729
server_state
enum server_states server_state(void)
Definition srv_main.c:337
srv_main.h
notify_if_first_access_level_is_available
void notify_if_first_access_level_is_available(void)
Definition stdinhand.c:1450
conn_is_kicked
bool conn_is_kicked(struct connection *pconn, int *time_remaining)
Definition stdinhand.c:6281
toggle_ai_player_direct
void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
Definition stdinhand.c:705
stdinhand.h
civ_game::connectmsg
char connectmsg[MAX_LEN_MSG]
Definition game.h:219
civ_game::glob_observers
struct conn_list * glob_observers
Definition game.h:98
civ_game::est_connections
struct conn_list * est_connections
Definition game.h:97
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_game::ip_hide
bool ip_hide
Definition game.h:174
civ_game::all_connections
struct conn_list * all_connections
Definition game.h:96
civ_game::server
struct civ_game::@31::@35 server
civ_game::max_players
int max_players
Definition game.h:156
civ_game::auto_ai_toggle
bool auto_ai_toggle
Definition game.h:130
civ_game::turnblock
bool turnblock
Definition game.h:197
civ_map::topology_id
int topology_id
Definition map_types.h:72
civ_map::wrap_id
int wrap_id
Definition map_types.h:73
connection
Definition connection.h:136
packet_chat_msg
Definition packets_gen.h:298
packet_conn_info
Definition packets_gen.h:855
packet_conn_info::capability
char capability[MAX_LEN_CAPSTR]
Definition packets_gen.h:864
packet_conn_info::established
bool established
Definition packets_gen.h:858
packet_conn_info::observer
bool observer
Definition packets_gen.h:859
packet_conn_info::used
bool used
Definition packets_gen.h:857
packet_conn_info::addr
char addr[MAX_LEN_ADDR]
Definition packets_gen.h:863
packet_conn_info::player_num
int player_num
Definition packets_gen.h:860
packet_conn_info::username
char username[MAX_LEN_NAME]
Definition packets_gen.h:862
packet_conn_info::id
int id
Definition packets_gen.h:856
packet_conn_info::access_level
enum cmdlevel access_level
Definition packets_gen.h:861
packet_game_info::aifill
int aifill
Definition packets_gen.h:122
packet_game_info::is_edit_mode
bool is_edit_mode
Definition packets_gen.h:191
packet_game_info::phase
int phase
Definition packets_gen.h:212
packet_server_info
Definition packets_gen.h:324
packet_server_info::major_version
int major_version
Definition packets_gen.h:326
packet_server_info::version_label
char version_label[48]
Definition packets_gen.h:325
packet_server_info::patch_version
int patch_version
Definition packets_gen.h:328
packet_server_info::minor_version
int minor_version
Definition packets_gen.h:327
packet_server_info::emerg_version
int emerg_version
Definition packets_gen.h:329
packet_server_join_reply
Definition packets_gen.h:55
packet_server_join_reply::challenge_file
char challenge_file[4095]
Definition packets_gen.h:59
packet_server_join_reply::you_can_join
bool you_can_join
Definition packets_gen.h:56
packet_server_join_reply::conn_id
int conn_id
Definition packets_gen.h:60
packet_server_join_reply::capability
char capability[512]
Definition packets_gen.h:58
packet_server_join_reply::message
char message[1536]
Definition packets_gen.h:57
packet_server_join_req
Definition packets_gen.h:46
packet_server_join_req::version_label
char version_label[48]
Definition packets_gen.h:49
packet_server_join_req::capability
char capability[512]
Definition packets_gen.h:48
packet_server_join_req::minor_version
int minor_version
Definition packets_gen.h:51
packet_server_join_req::patch_version
int patch_version
Definition packets_gen.h:52
packet_server_join_req::major_version
int major_version
Definition packets_gen.h:50
packet_server_join_req::username
char username[48]
Definition packets_gen.h:47
packet_set_topology
Definition packets_gen.h:1593
player
Definition player.h:249
player::username
char username[MAX_LEN_NAME]
Definition player.h:252
player::is_connected
bool is_connected
Definition player.h:296
player::was_created
bool was_created
Definition player.h:294
player::connections
struct conn_list * connections
Definition player.h:298
player::nation
struct nation_type * nation
Definition player.h:260
player::user_turns
int user_turns
Definition player.h:256
player::unassigned_user
bool unassigned_user
Definition player.h:253
server_arguments::fcdb_enabled
bool fcdb_enabled
Definition srv_main.h:55
server_arguments::auth_enabled
bool auth_enabled
Definition srv_main.h:57
server_arguments::port
int port
Definition srv_main.h:36
server
Definition servers.h:29
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1007
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fc_strncmp
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154
team_remove_player
void team_remove_player(struct player *pplayer)
Definition team.c:502
freeciv_name_version
const char * freeciv_name_version(void)
Definition version.c:35
version.h
send_running_votes
void send_running_votes(struct connection *pconn, bool only_team_votes)
Definition voting.c:810
send_remove_team_votes
void send_remove_team_votes(struct connection *pconn)
Definition voting.c:841
cancel_connection_votes
void cancel_connection_votes(struct connection *pconn)
Definition voting.c:691
send_updated_vote_totals
void send_updated_vote_totals(struct conn_list *dest)
Definition voting.c:866
voting.h