Freeciv-3.1
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 "support.h"
26
27/* common */
28#include "capstr.h"
29#include "events.h"
30#include "game.h"
31#include "packets.h"
32#include "player.h"
33#include "version.h"
34
35/* server */
36#include "aiiface.h"
37#include "auth.h"
38#include "diplhand.h"
39#include "edithand.h"
40#include "gamehand.h"
41#include "maphand.h"
42#include "meta.h"
43#include "notify.h"
44#include "plrhand.h"
45#include "report.h"
46#include "ruleset.h"
47#include "sernet.h"
48#include "settings.h"
49#include "srv_main.h"
50#include "stdinhand.h"
51#include "voting.h"
52
53#include "connecthand.h"
54
55
56static bool connection_attach_real(struct connection *pconn,
57 struct player *pplayer,
58 bool observing, bool connecting);
59
60/**********************************************************************/
68void conn_set_access(struct connection *pconn, enum cmdlevel new_level,
69 bool granted)
70{
71 enum cmdlevel old_level = conn_get_access(pconn);
72
73 pconn->access_level = new_level;
74 if (granted) {
75 pconn->server.granted_access_level = new_level;
76 }
77
78 if (old_level != new_level) {
79 send_server_access_level_settings(pconn->self, old_level, new_level);
80 }
81}
82
83/**********************************************************************/
90static void restore_access_level(struct connection *pconn)
91{
92 /* Restore previous privileges. */
93 enum cmdlevel level = pconn->server.granted_access_level;
94
95 /* Detached connections must have at most the same privileges
96 * as observers, unless they were granted something higher than
97 * ALLOW_BASIC in the first place. */
98 if ((pconn->observer || !pconn->playing) && level == ALLOW_BASIC) {
99 level = ALLOW_INFO;
100 }
101
102 conn_set_access(pconn, level, FALSE);
103}
104
105/**********************************************************************/
124{
125 struct conn_list *dest = pconn->self;
126 struct player *pplayer;
127 struct packet_server_join_reply packet;
128 struct packet_chat_msg connect_info;
129 char hostname[512];
130 bool delegation_error = FALSE;
131 struct packet_set_topology topo_packet;
132
133 /* zero out the password */
134 memset(pconn->server.password, 0, sizeof(pconn->server.password));
135
136 /* send join_reply packet */
137 packet.you_can_join = TRUE;
139 fc_snprintf(packet.message, sizeof(packet.message), _("%s Welcome"),
140 pconn->username);
142 packet.conn_id = pconn->id;
143 send_packet_server_join_reply(pconn, &packet);
144
145 /* "establish" the connection */
146 pconn->established = TRUE;
148
149 pconn->server.delegation.status = FALSE;
150 pconn->server.delegation.playing = NULL;
152
153 conn_list_append(game.est_connections, pconn);
154 if (conn_list_size(game.est_connections) == 1) {
155 /* First connection
156 * Replace "restarting in x seconds" meta message */
159 }
160
161 /* introduce the server to the connection */
162 if (fc_gethostname(hostname, sizeof(hostname)) == 0) {
163 notify_conn(dest, NULL, E_CONNECTION, ftc_any,
164 _("Welcome to the %s Server running at %s port %d."),
165 freeciv_name_version(), hostname, srvarg.port);
166 } else {
167 notify_conn(dest, NULL, E_CONNECTION, ftc_any,
168 _("Welcome to the %s Server at port %d."),
170 }
171
172 /* FIXME: this (getting messages about others logging on) should be a
173 * message option for the client with event */
174
175 /* Notify the console that you're here. */
176 log_normal(_("%s has connected from %s."), pconn->username, pconn->addr);
177
179 send_rulesets(dest);
182 send_scenario_info(dest);
184 send_game_info(dest);
185 topo_packet.topology_id = wld.map.topology_id;
186 send_packet_set_topology(pconn, &topo_packet);
187
188 /* Do we have a player that a delegate is currently controlling? */
189 if ((pplayer = player_by_user_delegated(pconn->username))) {
190 /* Reassert our control over the player. */
191 struct connection *pdelegate;
192 fc_assert_ret(player_delegation_get(pplayer) != NULL);
193 pdelegate = conn_by_user(player_delegation_get(pplayer));
194
195 if (pdelegate && connection_delegate_restore(pdelegate)) {
196 /* Delegate now detached from our player. We will restore control
197 * over them as normal below. */
198 notify_conn(pconn->self, NULL, E_CONNECTION, ftc_server,
199 _("Your delegate %s was controlling your player '%s'; "
200 "now detached."), pdelegate->username,
201 player_name(pplayer));
202 notify_conn(pdelegate->self, NULL, E_CONNECTION, ftc_server,
203 _("%s reconnected, ending your delegated control of "
204 "player '%s'."), pconn->username, player_name(pplayer));
205 } else {
206 fc_assert(pdelegate);
207 /* This really shouldn't happen. */
208 log_error("Failed to revoke delegate %s's control of %s, so owner %s "
209 "can't regain control.", pdelegate->username,
210 player_name(pplayer), pconn->username);
211 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
212 _("Couldn't get control of '%s' from delegation to %s."),
213 player_name(pplayer), pdelegate->username);
214 delegation_error = TRUE;
215 pplayer = NULL;
216 }
217 }
218
219 if (!delegation_error) {
220 if ((pplayer = player_by_user(pconn->username))
221 && connection_attach_real(pconn, pplayer, FALSE, TRUE)) {
222 /* a player has already been created for this user, reconnect */
223
224 if (S_S_INITIAL == server_state()) {
225 send_player_info_c(NULL, dest);
226 }
227 } else {
228 if (!game_was_started()) {
229 if (connection_attach_real(pconn, NULL, FALSE, TRUE)) {
230 pplayer = conn_get_player(pconn);
231 fc_assert(pplayer != NULL);
232 } else {
233 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
234 _("Couldn't attach your connection to new player."));
235 log_verbose("%s is not attached to a player", pconn->username);
236 }
237 }
238 send_player_info_c(NULL, dest);
239 }
240 }
241
243
244 if (NULL == pplayer) {
245 /* Else this has already been done in connection_attach_real(). */
250
251 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
252 _("You are logged in as '%s' connected to no player."),
253 pconn->username);
254 } else {
255 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
256 _("You are logged in as '%s' connected to %s."),
257 pconn->username,
258 player_name(pconn->playing));
259 }
260
261 /* Send information about delegation(s). */
263
264 /* Notify the *other* established connections that you are connected, and
265 * add the info for all in event cache. Note we must to do it after we
266 * sent the pending events to pconn (from this function and also
267 * connection_attach()), otherwise pconn will receive it too. */
268 if (conn_controls_player(pconn)) {
269 if (game.server.ip_hide) {
270 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
271 _("%s has connected (player %s)."),
272 pconn->username,
274 } else {
275 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
276 _("%s has connected from %s (player %s)."),
277 pconn->username, pconn->addr,
279 }
280 } else {
281 if (game.server.ip_hide) {
282 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
283 _("%s has connected."),
284 pconn->username);
285 } else {
286 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
287 _("%s has connected from %s."),
288 pconn->username, pconn->addr);
289 }
290 }
292 if (aconn != pconn) {
293 send_packet_chat_msg(aconn, &connect_info);
294 }
296 event_cache_add_for_all(&connect_info);
297
298 /* if need be, tell who we're waiting on to end the game.info.turn */
299 if (S_S_RUNNING == server_state() && game.server.turnblock) {
300 players_iterate_alive(cplayer) {
301 if (is_human(cplayer)
302 && !cplayer->phase_done
303 && cplayer != pconn->playing) { /* skip current player */
304 notify_conn(dest, NULL, E_CONNECTION, ftc_any,
305 _("Turn-blocking game play: "
306 "waiting on %s to finish turn..."),
307 player_name(cplayer));
308 }
310 }
311
312 if (game.info.is_edit_mode) {
313 notify_conn(dest, NULL, E_SETTING, ftc_editor,
314 _(" *** Server is in edit mode. *** "));
315 }
316
317 if (NULL != pplayer) {
318 /* Else, no need to do anything. */
321 }
322
324
326}
327
328/**********************************************************************/
331void reject_new_connection(const char *msg, struct connection *pconn)
332{
333 struct packet_server_join_reply packet;
334
335 /* zero out the password */
336 memset(pconn->server.password, 0, sizeof(pconn->server.password));
337
338 packet.you_can_join = FALSE;
340 sz_strlcpy(packet.message, msg);
341 packet.challenge_file[0] = '\0';
342 packet.conn_id = -1;
343 send_packet_server_join_reply(pconn, &packet);
344 log_normal(_("Client rejected: %s."), conn_description(pconn));
346}
347
348/**********************************************************************/
353 struct packet_server_join_req *req)
354{
355 char msg[MAX_LEN_MSG];
356 int kick_time_remaining;
357
358 if (pconn->established || pconn->server.status != AS_NOT_ESTABLISHED) {
359 /* We read the PACKET_SERVER_JOIN_REQ twice from this connection,
360 * this is probably not a Freeciv client. */
361 return FALSE;
362 }
363
364 log_normal(_("Connection request from %s from %s"),
365 req->username, pconn->addr);
366
367 /* print server and client capabilities to console */
368 log_normal(_("%s has client version %d.%d.%d%s"),
369 pconn->username, req->major_version, req->minor_version,
370 req->patch_version, req->version_label);
371 log_verbose("Client caps: %s", req->capability);
372 log_verbose("Server caps: %s", our_capability);
373 conn_set_capability(pconn, req->capability);
374
375 /* Make sure the server has every capability the client needs */
377 fc_snprintf(msg, sizeof(msg),
378 _("The client is missing a capability that this server needs.\n"
379 "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
380 " Upgrading may help!"),
381 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
382 req->major_version, req->minor_version,
383 req->patch_version, req->version_label);
384 reject_new_connection(msg, pconn);
385 log_normal(_("%s was rejected: Mismatched capabilities."),
386 req->username);
387 return FALSE;
388 }
389
390 /* Make sure the client has every capability the server needs */
392 fc_snprintf(msg, sizeof(msg),
393 _("The server is missing a capability that the client needs.\n"
394 "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
395 " Upgrading may help!"),
396 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
397 req->major_version, req->minor_version,
398 req->patch_version, req->version_label);
399 reject_new_connection(msg, pconn);
400 log_normal(_("%s was rejected: Mismatched capabilities."),
401 req->username);
402 return FALSE;
403 }
404
405 {
406 /* Client is compatible. That includes ability to receive server info.
407 * Send it. */
408 struct packet_server_info info;
409
410 info.major_version = MAJOR_VERSION;
411 info.minor_version = MINOR_VERSION;
412 info.patch_version = PATCH_VERSION;
413#ifdef EMERGENCY_VERSION
414 info.emerg_version = EMERGENCY_VERSION;
415#else
416 info.emerg_version = 0;
417#endif
418 sz_strlcpy(info.version_label, VERSION_LABEL);
419 send_packet_server_info(pconn, &info);
420 }
421
423
424 /* Name-sanity check: could add more checks? */
425 if (!is_valid_username(req->username)) {
426 fc_snprintf(msg, sizeof(msg), _("Invalid username '%s'"), req->username);
427 reject_new_connection(msg, pconn);
428 log_normal(_("%s was rejected: Invalid name [%s]."),
429 req->username, pconn->addr);
430 return FALSE;
431 }
432
433 if (conn_is_kicked(pconn, &kick_time_remaining)) {
434 fc_snprintf(msg, sizeof(msg), _("You have been kicked from this server "
435 "and cannot reconnect for %d seconds."),
436 kick_time_remaining);
437 reject_new_connection(msg, pconn);
438 log_normal(_("%s was rejected: Connection kicked "
439 "(%d seconds remaining)."),
440 req->username, kick_time_remaining);
441 return FALSE;
442 }
443
444 /* don't allow duplicate logins */
446 if (fc_strcasecmp(req->username, aconn->username) == 0) {
447 fc_snprintf(msg, sizeof(msg), _("'%s' already connected."),
448 req->username);
449 reject_new_connection(msg, pconn);
450 log_normal(_("%s was rejected: Duplicate login name [%s]."),
451 req->username, pconn->addr);
452 return FALSE;
453 }
455
456 /* Remove the ping timeout given in sernet.c:server_make_connection(). */
457 fc_assert_msg(1 == timer_list_size(pconn->server.ping_timers),
458 "Ping timer list size %d, should be 1. Have we sent "
459 "a ping to unestablished connection %s?",
460 timer_list_size(pconn->server.ping_timers),
461 conn_description(pconn));
462 timer_list_pop_front(pconn->server.ping_timers);
463
464 if (game.server.connectmsg[0] != '\0') {
465 log_debug("Sending connectmsg: %s", game.server.connectmsg);
467 }
468
469 if (srvarg.auth_enabled) {
470 return auth_user(pconn, req->username);
471 } else {
472 sz_strlcpy(pconn->username, req->username);
474 return TRUE;
475 }
476}
477
478/**********************************************************************/
487{
488 const char *desc = conn_description(pconn);
489
491
492 log_normal(_("Lost connection: %s."), desc);
493
494 /* Special color (white on black) for player loss */
495 notify_conn(game.est_connections, NULL, E_CONNECTION,
497 _("Lost connection: %s."), desc);
498
499 connection_detach(pconn, TRUE);
502
504}
505
506/**********************************************************************/
509static void package_conn_info(struct connection *pconn,
510 struct packet_conn_info *packet)
511{
512 packet->id = pconn->id;
513 packet->used = pconn->used;
514 packet->established = pconn->established;
515 packet->player_num = (NULL != pconn->playing)
516 ? player_number(pconn->playing)
518 packet->observer = pconn->observer;
519 packet->access_level = pconn->access_level;
520
521 sz_strlcpy(packet->username, pconn->username);
522 if (game.server.ip_hide) {
523 sz_strlcpy(packet->addr, Q_("?IP:Hidden"));
524 } else {
525 sz_strlcpy(packet->addr, pconn->addr);
526 }
527 sz_strlcpy(packet->capability, pconn->capability);
528}
529
530/**********************************************************************/
535static void send_conn_info_arg(struct conn_list *src,
536 struct conn_list *dest, bool remove_conn)
537{
538 struct packet_conn_info packet;
539
540 if (!dest) {
541 dest = game.est_connections;
542 }
543
544 conn_list_iterate(src, psrc) {
545 package_conn_info(psrc, &packet);
546 if (remove_conn) {
547 packet.used = FALSE;
548 }
549 lsend_packet_conn_info(dest, &packet);
551}
552
553/**********************************************************************/
557void send_conn_info(struct conn_list *src, struct conn_list *dest)
558{
559 send_conn_info_arg(src, dest, FALSE);
560}
561
562/**********************************************************************/
566void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
567{
568 send_conn_info_arg(src, dest, TRUE);
569}
570
571/**********************************************************************/
575{
576 players_iterate(played) {
577 if (!played->is_connected && !played->was_created) {
578 return played;
579 }
581
582 return NULL;
583}
584
585/**********************************************************************/
601static bool connection_attach_real(struct connection *pconn,
602 struct player *pplayer,
603 bool observing, bool connecting)
604{
605 fc_assert_ret_val(pconn != NULL, FALSE);
606 fc_assert_ret_val_msg(!pconn->observer && pconn->playing == NULL, FALSE,
607 "connections must be detached with "
608 "connection_detach() before calling this!");
609
610 if (!observing) {
611 if (NULL == pplayer) {
612 /* search for uncontrolled player */
613 pplayer = find_uncontrolled_player();
614
615 if (NULL == pplayer) {
616 /* no uncontrolled player found */
618 || normal_player_count() >= server.playable_nations) {
619 return FALSE;
620 }
621 /* add new player, or not */
622 /* Should only be called in such a way as to create a new player
623 * in the pregame */
626 NULL, FALSE);
627 /* Pregame => no need to assign_player_colors() */
628 if (!pplayer) {
629 return FALSE;
630 }
631 } else {
632 team_remove_player(pplayer);
633 }
634 server_player_init(pplayer, FALSE, TRUE);
635
636 /* Make it human! */
637 set_as_human(pplayer);
638 }
639
640 sz_strlcpy(pplayer->username, pconn->username);
641 pplayer->unassigned_user = FALSE;
642 pplayer->user_turns = 0; /* reset for a new user */
643 pplayer->is_connected = TRUE;
644
645 if (!game_was_started()) {
646 if (!pplayer->was_created && NULL == pplayer->nation) {
647 /* Temporarily set player_name() to username. */
648 server_player_set_name(pplayer, pconn->username);
649 }
650 (void) aifill(game.info.aifill);
651 }
652
653 if (game.server.auto_ai_toggle && !is_human(pplayer)) {
654 toggle_ai_player_direct(NULL, pplayer);
655 }
656
658
659 /* Remove from global observers list, if was there */
660 conn_list_remove(game.glob_observers, pconn);
661 } else if (pplayer == NULL) {
662 /* Global observer */
663 bool already = FALSE;
664
665 fc_assert(observing);
666
668 if (pconn2 == pconn) {
669 already = TRUE;
670 break;
671 }
673
674 if (!already) {
675 conn_list_append(game.glob_observers, pconn);
676 }
677 }
678
679 /* We don't want the connection's username on another player. */
680 players_iterate(aplayer) {
681 if (aplayer != pplayer
682 && 0 == strncmp(aplayer->username, pconn->username, MAX_LEN_NAME)) {
683 sz_strlcpy(aplayer->username, _(ANON_USER_NAME));
684 aplayer->unassigned_user = TRUE;
685 send_player_info_c(aplayer, NULL);
686 }
688
689 pconn->observer = observing;
690 pconn->playing = pplayer;
691 if (pplayer) {
692 conn_list_append(pplayer->connections, pconn);
693 }
694
696
697 /* Reset the delta-state. */
698 send_conn_info(pconn->self, game.est_connections); /* Client side. */
699 conn_reset_delta_state(pconn); /* Server side. */
700
701 /* Initial packets don't need to be resent. See comment for
702 * connecthand.c::establish_new_connection(). */
703 switch (server_state()) {
704 case S_S_INITIAL:
705 send_pending_events(pconn, connecting);
706 send_running_votes(pconn, !connecting);
707 break;
708
709 case S_S_RUNNING:
711 send_all_info(pconn->self);
712 if (game.info.is_edit_mode && can_conn_edit(pconn)) {
714 }
716 /* Enter C_S_RUNNING client state. */
718 /* Must be after C_S_RUNNING client state to be effective. */
720 send_pending_events(pconn, connecting);
721 send_running_votes(pconn, !connecting);
722 break;
723
724 case S_S_OVER:
726 send_all_info(pconn->self);
727 if (game.info.is_edit_mode && can_conn_edit(pconn)) {
729 }
732 send_pending_events(pconn, connecting);
733 send_running_votes(pconn, !connecting);
734 if (!connecting) {
735 /* Send information about delegation(s). */
737 }
738 break;
739 }
740
742
743 return TRUE;
744}
745
746/**********************************************************************/
749bool connection_attach(struct connection *pconn, struct player *pplayer,
750 bool observing)
751{
752 return connection_attach_real(pconn, pplayer, observing, FALSE);
753}
754
755/**********************************************************************/
765void connection_detach(struct connection *pconn, bool remove_unused_player)
766{
767 struct player *pplayer;
768
769 fc_assert_ret(pconn != NULL);
770
771 if (NULL != (pplayer = pconn->playing)) {
772 bool was_connected = pplayer->is_connected;
773
775 conn_list_remove(pplayer->connections, pconn);
776 pconn->playing = NULL;
777 pconn->observer = FALSE;
782
783 /* If any other (non-observing) conn is attached to this player, the
784 * player is still connected. */
785 pplayer->is_connected = FALSE;
786 conn_list_iterate(pplayer->connections, aconn) {
787 if (!aconn->observer) {
788 pplayer->is_connected = TRUE;
789 break;
790 }
792
793 if (was_connected && !pplayer->is_connected) {
794 /* Player just lost its controlling connection. */
795 if (remove_unused_player
796 && !pplayer->was_created && !game_was_started()) {
797 /* Remove player. */
798 conn_list_iterate(pplayer->connections, aconn) {
799 /* Detach all. */
800 fc_assert_action(aconn != pconn, continue);
801 notify_conn(aconn->self, NULL, E_CONNECTION, ftc_server,
802 _("Detaching from %s."), player_name(pplayer));
803 /* Recursive... but shouldn't be a problem, as this can only
804 * be a non-controlling connection so can't get back here. */
805 connection_detach(aconn, TRUE);
807
808 /* Actually do the removal. */
809 server_remove_player(pplayer);
810 (void) aifill(game.info.aifill);
812 } else {
813 /* Aitoggle the player if no longer connected. */
814 if (game.server.auto_ai_toggle && is_human(pplayer)) {
815 toggle_ai_player_direct(NULL, pplayer);
816 /* send_player_info_c() was formerly updated by
817 * toggle_ai_player_direct(), so it must be safe to send here now?
818 *
819 * At other times, data from send_conn_info() is used by the
820 * client to display player information.
821 * See establish_new_connection().
822 */
823 log_verbose("connection_detach() calls send_player_info_c()");
824 send_player_info_c(pplayer, NULL);
825
827 }
828 }
829 }
830 } else {
831 pconn->observer = FALSE;
834 }
835}
836
837/**********************************************************************/
841 struct player *dplayer)
842{
844
845 /* Save the original player of this connection and the original username of
846 * the player. */
847 pconn->server.delegation.status = TRUE;
849 pconn->server.delegation.observer = pconn->observer;
850 if (conn_controls_player(pconn)) {
851 /* Setting orig_username in the player we're about to put aside is
852 * a flag that no-one should be allowed to mess with it (e.g. /take). */
853 struct player *oplayer = conn_get_player(pconn);
854
855 fc_assert_ret_val(oplayer != dplayer, FALSE);
856 fc_assert_ret_val(strlen(oplayer->server.orig_username) == 0, FALSE);
857 sz_strlcpy(oplayer->server.orig_username, oplayer->username);
858 }
859 fc_assert_ret_val(strlen(dplayer->server.orig_username) == 0, FALSE);
860 sz_strlcpy(dplayer->server.orig_username, dplayer->username);
861
862 /* Detach the current connection. */
863 if (NULL != pconn->playing || pconn->observer) {
864 connection_detach(pconn, FALSE);
865 }
866
867 /* Try to attach to the new player */
868 if (!connection_attach(pconn, dplayer, FALSE)) {
869
870 /* Restore original connection. */
871#ifndef FREECIV_NDEBUG
872 bool success =
873#endif
874 connection_attach(pconn,
876 pconn->server.delegation.observer);
877 fc_assert_ret_val(success, FALSE);
878
879 /* Reset all changes done above. */
880 pconn->server.delegation.status = FALSE;
881 pconn->server.delegation.playing = NULL;
883 if (conn_controls_player(pconn)) {
884 struct player *oplayer = conn_get_player(pconn);
885 oplayer->server.orig_username[0] = '\0';
886 }
887 dplayer->server.orig_username[0] = '\0';
888
889 return FALSE;
890 }
891
892 return TRUE;
893}
894
895/**********************************************************************/
902{
903 struct player *dplayer;
904
905 if (!pconn->server.delegation.status) {
906 return FALSE;
907 }
908
909 if (pconn->server.delegation.playing
910 && !pconn->server.delegation.observer) {
911 /* If restoring to controlling another player, and we're not the
912 * original controller of that player, something's gone wrong. */
915 pconn->username) == 0, FALSE);
916 }
917
918 /* Save the current (delegated) player. */
919 dplayer = conn_get_player(pconn);
920
921 /* There should be a delegated player connected to pconn. */
922 fc_assert_ret_val(dplayer, FALSE);
923
924 /* Detach the current (delegate) connection from the delegated player. */
925 if (NULL != pconn->playing || pconn->observer) {
926 connection_detach(pconn, FALSE);
927 }
928
929 /* Try to attach to the delegate's original player */
930 if ((NULL != pconn->server.delegation.playing
931 || pconn->server.delegation.observer)
932 && !connection_attach(pconn, pconn->server.delegation.playing,
933 pconn->server.delegation.observer)) {
934 return FALSE;
935 }
936
937 /* Reset data. */
938 pconn->server.delegation.status = FALSE;
939 pconn->server.delegation.playing = NULL;
941 if (conn_controls_player(pconn) && conn_get_player(pconn) != NULL) {
942 /* Remove flag that we had 'put aside' our original player. */
943 struct player *oplayer = conn_get_player(pconn);
944 fc_assert_ret_val(oplayer != dplayer, FALSE);
945 oplayer->server.orig_username[0] = '\0';
946 }
947
948 /* Restore the username of the original controller in the previously-
949 * delegated player. */
950 sz_strlcpy(dplayer->username, dplayer->server.orig_username);
951 dplayer->server.orig_username[0] = '\0';
952 /* Send updated username to all connections. */
953 send_player_info_c(dplayer, NULL);
954
955 return TRUE;
956}
957
958/**********************************************************************/
962void connection_close_server(struct connection *pconn, const char *reason)
963{
964 /* Restore possible delegations before the connection is closed. */
966 connection_close(pconn, reason);
967}
const char * default_ai_type_name(void)
Definition aiiface.c:262
bool auth_user(struct connection *pconn, char *username)
Definition auth.c:73
bool has_capabilities(const char *us, const char *them)
Definition capability.c:86
const char *const our_capability
Definition capstr.c:32
static bool connection_attach_real(struct connection *pconn, struct player *pplayer, bool observing, bool connecting)
void send_conn_info(struct conn_list *src, struct conn_list *dest)
bool connection_attach(struct connection *pconn, struct player *pplayer, bool observing)
static void package_conn_info(struct connection *pconn, struct packet_conn_info *packet)
void reject_new_connection(const char *msg, struct connection *pconn)
static void send_conn_info_arg(struct conn_list *src, struct conn_list *dest, bool remove_conn)
bool connection_delegate_take(struct connection *pconn, struct player *dplayer)
bool handle_login_request(struct connection *pconn, struct packet_server_join_req *req)
struct player * find_uncontrolled_player(void)
static void restore_access_level(struct connection *pconn)
Definition connecthand.c:90
void lost_connection_to_client(struct connection *pconn)
void connection_close_server(struct connection *pconn, const char *reason)
void connection_detach(struct connection *pconn, bool remove_unused_player)
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Definition connecthand.c:68
bool connection_delegate_restore(struct connection *pconn)
void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
void establish_new_connection(struct connection *pconn)
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:760
bool can_conn_edit(const struct connection *pconn)
Definition connection.c:510
struct connection * conn_by_user(const char *user_name)
Definition connection.c:376
void flush_connection_send_buffer_all(struct connection *pc)
Definition connection.c:229
void conn_set_capability(struct connection *pconn, const char *capability)
Definition connection.c:658
void conn_reset_delta_state(struct connection *pc)
Definition connection.c:670
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
bool conn_controls_player(const struct connection *pconn)
Definition connection.c:742
const char * conn_description(const struct connection *pconn)
Definition connection.c:473
void conn_compression_freeze(struct connection *pconn)
Definition connection.c:691
enum cmdlevel conn_get_access(const struct connection *pconn)
Definition connection.c:772
@ AS_NOT_ESTABLISHED
Definition connection.h:98
@ AS_ESTABLISHED
Definition connection.h:102
bool conn_compression_thaw(struct connection *pconn)
Definition packets.c:194
#define conn_list_iterate(connlist, pconn)
Definition connection.h:113
#define conn_list_iterate_end
Definition connection.h:115
void send_diplomatic_meetings(struct connection *dest)
Definition diplhand.c:912
void edithand_send_initial_packets(struct conn_list *dest)
Definition edithand.c:113
#define MAX_LEN_NAME
Definition fc_types.h:66
#define Q_(String)
Definition fcintl.h:70
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_player_lost
const struct ft_color ftc_server
const struct ft_color ftc_editor
const struct ft_color ftc_any
struct civ_game game
Definition game.c:57
struct world wld
Definition game.c:58
void send_scenario_description(struct conn_list *dest)
Definition gamehand.c:962
void send_scenario_info(struct conn_list *dest)
Definition gamehand.c:948
void send_game_info(struct conn_list *dest)
Definition gamehand.c:905
const char * new_challenge_filename(struct connection *pc)
Definition gamehand.c:1094
#define fc_assert_msg(condition, message,...)
Definition log.h:181
#define fc_assert_ret(condition)
Definition log.h:191
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_normal(message,...)
Definition log.h:107
#define log_error(message,...)
Definition log.h:103
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
void maybe_automatic_meta_message(const char *automatic)
Definition meta.c:151
const char * default_meta_message_string(void)
Definition meta.c:90
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:490
@ META_INFO
Definition meta.h:26
void send_pending_events(struct connection *pconn, bool include_public)
Definition notify.c:753
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:238
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
void event_cache_add_for_all(const struct packet_chat_msg *packet)
Definition notify.c:619
#define MAX_LEN_MSG
Definition packets.h:43
int dsend_packet_connect_msg(struct connection *pc, const char *message)
void lsend_packet_conn_info(struct conn_list *dest, const struct packet_conn_info *packet)
int send_packet_server_info(struct connection *pc, const struct packet_server_info *packet)
int send_packet_chat_msg(struct connection *pc, const struct packet_chat_msg *packet)
int send_packet_set_topology(struct connection *pc, const struct packet_set_topology *packet)
int dsend_packet_start_phase(struct connection *pc, int phase)
int send_packet_server_join_reply(struct connection *pc, const struct packet_server_join_reply *packet)
bool is_valid_username(const char *name)
Definition player.c:1872
int player_count(void)
Definition player.c:808
int player_slot_count(void)
Definition player.c:411
int player_number(const struct player *pplayer)
Definition player.c:828
const char * player_name(const struct player *pplayer)
Definition player.c:886
struct player * player_by_user(const char *name)
Definition player.c:931
#define players_iterate_end
Definition player.h:535
#define players_iterate(_pplayer)
Definition player.h:530
#define ANON_USER_NAME
Definition player.h:48
#define set_as_human(plr)
Definition player.h:235
#define players_iterate_alive_end
Definition player.h:545
#define is_human(plr)
Definition player.h:233
#define players_iterate_alive(_pplayer)
Definition player.h:540
void server_player_set_name(struct player *pplayer, const char *name)
Definition plrhand.c:2097
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Definition plrhand.c:1723
int normal_player_count(void)
Definition plrhand.c:3034
struct player * player_by_user_delegated(const char *name)
Definition plrhand.c:3147
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1000
void send_delegation_info(const struct connection *pconn)
Definition plrhand.c:3104
void server_remove_player(struct player *pplayer)
Definition plrhand.c:1772
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Definition plrhand.c:1450
const char * player_delegation_get(const struct player *pplayer)
Definition plrhand.c:3067
void reset_all_start_commands(bool plrchange)
Definition plrhand.c:2553
void report_final_scores(struct conn_list *dest)
Definition report.c:1555
void send_current_history_report(struct conn_list *dest)
Definition report.c:298
void send_rulesets(struct conn_list *dest)
Definition ruleset.c:9573
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
void send_server_setting_control(struct connection *pconn)
Definition settings.c:5177
void send_server_settings(struct conn_list *dest)
Definition settings.c:5133
void send_server_access_level_settings(struct conn_list *dest, enum cmdlevel old_level, enum cmdlevel new_level)
Definition settings.c:5145
void remove_leading_trailing_spaces(char *s)
Definition shared.c:443
const char * aifill(int amount)
Definition srv_main.c:2395
bool game_was_started(void)
Definition srv_main.c:339
struct server_arguments srvarg
Definition srv_main.c:173
void check_for_full_turn_done(void)
Definition srv_main.c:2145
void send_all_info(struct conn_list *dest)
Definition srv_main.c:682
enum server_states server_state(void)
Definition srv_main.c:323
void notify_if_first_access_level_is_available(void)
Definition stdinhand.c:1449
bool conn_is_kicked(struct connection *pconn, int *time_remaining)
Definition stdinhand.c:6210
void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
Definition stdinhand.c:704
struct civ_game::@30::@34 server
char connectmsg[MAX_LEN_MSG]
Definition game.h:218
struct conn_list * glob_observers
Definition game.h:98
struct conn_list * est_connections
Definition game.h:97
struct packet_game_info info
Definition game.h:89
bool ip_hide
Definition game.h:173
struct conn_list * all_connections
Definition game.h:96
int max_players
Definition game.h:155
bool auto_ai_toggle
Definition game.h:129
bool turnblock
Definition game.h:196
int topology_id
Definition map_types.h:72
bool established
Definition connection.h:145
struct player * playing
Definition connection.h:156
struct connection::@57::@63::@64 delegation
enum cmdlevel access_level
Definition connection.h:182
struct conn_list * self
Definition connection.h:168
struct timer_list * ping_timers
Definition connection.h:210
bool is_closing
Definition connection.h:236
bool observer
Definition connection.h:152
char username[MAX_LEN_NAME]
Definition connection.h:169
struct connection::@57::@63 server
enum auth_status status
Definition connection.h:222
char capability[MAX_LEN_CAPSTR]
Definition connection.h:176
char addr[MAX_LEN_ADDR]
Definition connection.h:170
char password[MAX_LEN_PASSWORD]
Definition connection.h:223
enum cmdlevel granted_access_level
Definition connection.h:229
char capability[MAX_LEN_CAPSTR]
char addr[MAX_LEN_ADDR]
char username[MAX_LEN_NAME]
enum cmdlevel access_level
char username[MAX_LEN_NAME]
Definition player.h:252
bool is_connected
Definition player.h:296
bool was_created
Definition player.h:294
struct conn_list * connections
Definition player.h:298
struct nation_type * nation
Definition player.h:260
struct player::@69::@71 server
int user_turns
Definition player.h:256
char orig_username[MAX_LEN_NAME]
Definition player.h:347
bool unassigned_user
Definition player.h:253
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
int fc_gethostname(char *buf, size_t len)
Definition support.c:1016
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
void team_remove_player(struct player *pplayer)
Definition team.c:502
const char * freeciv_name_version(void)
Definition version.c:35
void send_running_votes(struct connection *pconn, bool only_team_votes)
Definition voting.c:810
void send_remove_team_votes(struct connection *pconn)
Definition voting.c:841
void cancel_connection_votes(struct connection *pconn)
Definition voting.c:691
void send_updated_vote_totals(struct conn_list *dest)
Definition voting.c:866