Create new command capability NONVIS. Give it to players in any state
except visitors (and STAT_UNUSED, but those must not exist). This
makes it possible to have commands available to anyone but visitors.
Command change fails when the player is a visitor. Simply make it
unavailable instead, by requiring NONVIS.
Make read unavailable to visitors, because it's useless: visitors
can't receive telegrams (typed_wu() fails).
Make census, commodity and sinfra unavailable to visitors. Visitors
don't normally have sectors.
Make map and nmap unavailable to visitors. Visitors don't have sectors,
so their maps are always empty.
Make them unavailable to new players (between add and newcap) and
players in sanctuary, too. This is consistent with all the other
commands to examine the environment. It also prevents people from
trying multiple unbroken countries in a blitz to find the one with the
nicest vicinity.
Make resource available to new players, for consistency with census
and commodity.
Make country, echo and financial available to anyone.
A player may execute a command when his player->nstat has all the bits
in the command's c_permit.
Normal player commands require bit(2). Command break requires bit(1),
and execute requires bit(5). Deity commands require both bit(2) and
bit(3). Works, because deities always have both bits set in nstat, as
they may execute normal player commands, too. But it's a bit
confusing. Change them to only require their own bit(3).
A player may execute a command when his player->nstat has all the bits
in the command's c_permit.
All commands require bit(0). All players always have it. Silly; get
rid of it.
Timeout during execute gets handled just like an EOF cookie: end the
batch file, resume reading normal commands. That's wrong, we need to
close the connection.
A real EOF is recorded in the player's connection's EOF indicator.
Let's use that for all "connection needs to be closed" conditions, so
they all work the same. Create io_set_eof() to provide access.
Make recvclient() set the player connection's EOF indicator on
timeout. This makes the timeout "stick". Record receipt of an EOF
cookie in new struct player member got_ctld. Also abort the command,
as before. This leaves further interpretation of the EOF cookie to
the command loops.
Make player_main() set the player connection's EOF indicator on
got_ctld. Player connection gets closed on on EOF cookie, as before.
Change execute() to break the batch command loop when got_ctld is set,
then reset it. Ends the batch file on EOF cookie, as before.
Change status() back to checking EOF and error indicators (partial
revert of commit 9c5854c8, v4.3.16), and drop struct player member
eof.
Commit e3cf1e32 (v4.3.27) created make_stale_if_command_arg() to
permit catching more potential yields on input. Unfortunately, the
implementation of navigate and march sub-commands 'r', 'l' and 's'
breaks it.
do_unit_move() reads units into a unit list at the beginning and at
each stop. It writes them back when they move or sweep. If a unit
changed in the file in between, the changes would get wiped out.
Therefore, do_unit_move() must not yield between stops.
do_unit_move() parses sub-commands into player->argp[], then supplies
defaults for missing arguments, so that code using them (radar(),
do_look(), sona(), mine(), landmine()) won't prompt for missing
arguments. Unclean and brittle. See also commit 28cc236e and commit
45106ab9.
Unfortunately, make_stale_if_command_arg() doesn't recognize the
difference between these defaulted arguments and parsed arguments, so
it makes objects stale, even though the defaulted arguments can't be
missing. If a move or sweep follows, it triggers a false positive
generation oops.
To fix, test "points into argument buffer" (only true for parsed
arguments) instead of "is in player->argp[]". Requires making the
argument buffer accessible: new struct player member argbuf[]. Use it
for parsing commands, in command(), execute(), do_unit_move(). Don't
use it in emp_config(), player_login(), move_ground(), because these
parse something else.
Why upgrade? I'm not a lawyer, but here's my take on the differences
to version 2:
* Software patents: better protection against abuse of patents to
prevent users from exercising the rights under the GPL. I doubt
we'll get hit with a patent suit, but it's a good move just on
general principles.
* License compatibility: compatible with more free licenses, i.e. can
"steal" more free software for use in Empire. I don't expect to steal
much, but it's nice to have the option.
* Definition of "source code": modernization of some details for today's
networked world, to make it easier to distribute the software. Not
really relevant to us now, as we normally distribute full source code.
* Tivoization: this is about putting GPL-licensed software in hardware,
then make the hardware refuse to run modified software. "Neat" trick
to effectively deny its users their rights under the GPL. Abuse was
"pioneered" by TiVo (popular digital video recorders). GPLv3 forbids
it. Unlikely to become a problem for us.
* Internationalization: more careful wording, to harden the license
outside the US. The lawyers tell us it better be done that way.
* License violations: friendlier way to deal with license violations.
This has come out of past experience enforcing the GPL.
* Additional permissions: Probably not relevant to us.
Also include myself in the list of principal authors.
A player thread may sleep on input or output, except:
(1) While it is executing a C_MOD command, it may only sleep on input.
(2) While it is being aborted by the update or shutdown, it may not
sleep at all.
To find out whether a player thread may sleep on input, code has to
check condition (2). It needs do to that in recvclient().
To find out whether it may sleep on output, it has to check both
conditions. It needs to do that in pr_player() and upr_player().
The code tracked condition (1) in global variable play_lock_wanted.
It checked condition (2) by examining struct player member command.
Replace all that by new struct player member may_sleep. Initialize it
in player_new(), update it in dispatch(), shutdwn() and update_run().
This makes the tests in recvclient(), pr_player() and upr_player()
obvious. play_wrlock_wanted() is now unused, remove it.
may_play_now() tells deities about hours restriction and game down
status. It runs at login and before and after each command. Getting
notified that often is annoying.
Avoid repetition by remembering notification in new player flags
PF_HOURS and PF_DOWN. Add a notification when hours restriction has
been lifted. Ensure the notification is printed before the prompt,
not before the command, by calling may_play_now() from command() only
for mortals. Safe, because may_play_now() always returns true for
deities anyway.
Replace daychange() and gettimeleft() by update_timeused_login(),
update_timeused() and enforce_minimum_session_time(). The new
code doesn't assume the day is always 24 hours long which can
occur when transitioning into or out of DST and such. Logging
in after more a multiple of 128 days now resets nat_timeused
properly.
Fix nat_timeused calculation on midnight rollover to include
the time since midnight.
struct natstr member nat_dayno and struct player member timeleft
are now unused, remove them.
This simplifies things. In particular, it gets rid of random rounding
in getcommand(), which created a variation in the nightly build
depending on whether the update starts before or after the deity logs
out.
Replace struct natstr member nat_minused by nat_timeused, and update
cou_ca[] accordingly (this affects xdump nat). Replace player member
minleft by timeleft, and getminleft() by gettimeleft(). Update
getcommand(), daychange(), player_main(), status() accordingly, taking
care not to change player output. Change edit country key 'u' to work
in seconds.
Commit 79407e68 (v4.3.11) changed recvclient() to keep failing after
receiving EOF from player. This was bad, because some places getting
input check player->aborted instead of recvclient() failure, and
player->aborted wasn't set on EOF. Bugs caused by this:
* comm_bomb(), ship_bomb(), plane_bomb(), land_bomb() went into an
infinite loop that eventually ate all memory.
* deli(), desi(), dist(), fly(), morale(), zdon(), att_prompt(),
ask_move_in() interpreted EOF as empty input instead of no more
input.
* cmd_sail_ship() dereferenced a null pointer.
Fix by setting player->aborted on EOF, too.
Reading input fails after EOF and while the current command is
aborted. Commands should detect that and fail. If a command neglects
to do that in a loop, the loop can become infinite. This is
especially bad after EOF, because then the client might not read
output anymore. Output gets buffered until memory runs out.
Mitigate such bugs by counting how many calls have failed in a row,
oopsing on the 256th, and sleeping one minute from the 256th on.
implemented correctly by asynchronous clients --- unless a client
waits for a prompt after sending the execute command and its argument,
it is prone to send more input before the C_EXECUTE arrives. That
input overtakes the contents of the script file. This is almost
certain to happen when the execute is in a script file. Disabling
that is probably more useful and certainly less painful than
documenting this mess. The client rejects nested execute since
servcmd.c rev. 1.42.
(EXEC): new.
(player_coms): Require it for execute.
(player_set_nstat): Set it in nstat.
(execute): Clear it in nstat.
player->ncomstat for command permissions. Side effect: status() no
longer notifies deities when they go broke or become solvent.
(dispatch): Don't distinguish between transiently and permanently
unavailable commands. Didn't really work anyway.
(player): Remove unused member ncomstat.
(player): New member eof.
(recvclient): Return -1 without receiving input when it is set. Set
it on receipt of "ctld\n".
(execute): Clear it after receiving the script.
other. Ensure headers in include/ can be included in any order
(except for econfig-spec.h, which is special). New header types.h to
help avoid inclusion cycles. Sort include directives. Remove some
superflous includes.
(copy_utf8_to_ascii_no_funny): New.
(flash, wall, prmptrd, uprmptrd, getcommand): Use them to filter
input.
(uprnf, pr_flash): Use them to filter output.
(prtoascii): No longer used, remove.
(player_commands, player_commands_index): Internal linkage.
(player): New member flags.
(PF_UTF8, NF_UTF8): New PF_UTF8 replaces NF_UTF8. Users changed.
(options_cmd): New.
(login_coms): New command `options'.
(toggle): Revert to the previous rev.
thread entrypoints:
(lwpSelect, shutdown_sequence): Parameters didn't match thread entry
point prototype.
(lwpEntryPoint): Arguments didn't match thread entry point prototype.
Change linkage of functions without prototype declaration to static
where possible.
Remove some superflous declarations, replace others by suitable
includes.