]> git.pond.sub.org Git - empserver/blob - src/lib/player/player.c
Journal login before changing the player thread's name
[empserver] / src / lib / player / player.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  player.c: Main command loop for a player
28  *
29  *  Known contributors to this file:
30  *     Steve McClure, 2000
31  *     Markus Armbruster, 2004-2012
32  *     Ron Koenderink, 2004-2009
33  */
34
35 #include <config.h>
36
37 #include "empio.h"
38 #include "empthread.h"
39 #include "file.h"
40 #include "misc.h"
41 #include "nat.h"
42 #include "optlist.h"
43 #include "player.h"
44 #include "prototypes.h"
45
46
47 static int command(void);
48 static int status(void);
49
50 struct player *player;
51
52 void
53 player_main(struct player *p)
54 {
55     struct natstr *natp;
56     char buf[128];
57
58     player = p;
59     time(&player->curup);
60     update_timeused_login(player->curup);
61     show_motd();
62     if (init_nats() < 0) {
63         pr("Server confused, try again later\n");
64         return;
65     }
66     natp = getnatp(player->cnum);
67     if (!may_play_now(natp, player->curup))
68         return;
69     if (natp->nat_stat != STAT_VIS
70         && natp->nat_last_login
71         && (strcmp(natp->nat_hostaddr, player->hostaddr)
72             || strcmp(natp->nat_userid, player->userid))) {
73         pr("Last connection from: %s", ctime(&natp->nat_last_login));
74         pr("                  to: %s",
75            natp->nat_last_login <= natp->nat_last_logout
76            ? ctime(&natp->nat_last_logout) : "?");
77         pr("                  by: %s@%s\n",
78            natp->nat_userid,
79            *natp->nat_hostname ? natp->nat_hostname : natp->nat_hostaddr);
80     }
81     strcpy(natp->nat_userid, player->userid);
82     strcpy(natp->nat_hostname, player->hostname);
83     strcpy(natp->nat_hostaddr, player->hostaddr);
84     natp->nat_last_login = player->curup;
85     putnat(natp);
86     if (natp->nat_flags & NF_INFORM && natp->nat_tgms > 0) {
87         if (natp->nat_tgms == 1)
88             pr("You have a new telegram waiting ...\n");
89         else
90             pr("You have %s new telegrams waiting ...\n",
91                numstr(buf, natp->nat_tgms));
92         natp->nat_tgms = 0;
93     }
94
95     while (status() && command()) {
96         if (player->got_ctld)
97             io_set_eof(player->iop);
98         player->aborted = 0;
99         empth_yield();
100     }
101     /* #*# I put the following line in to prevent server crash -KHS */
102     natp = getnatp(player->cnum);
103     time(&natp->nat_last_logout);
104     putnat(natp);
105     update_timeused(natp->nat_last_logout);
106     enforce_minimum_session_time();
107     pr("Bye-bye\n");
108 }
109
110 static int
111 command(void)
112 {
113     struct natstr *natp = getnatp(player->cnum);
114     char *redir;                /* UTF-8 */
115     time_t now;
116
117     prprompt(natp->nat_timeused / 60, natp->nat_btu);
118     if (getcommand(player->combuf) < 0)
119         return player->aborted;
120
121     now = time(NULL);
122     update_timeused(now);
123     if (!player->god && !may_play_now(natp, now))
124         return 0;
125
126     if (parse(player->combuf, player->argbuf, player->argp,
127               player->comtail, &player->condarg, &redir) < 0) {
128         pr("See \"info Syntax\"?\n");
129     } else {
130         if (dispatch(player->combuf, redir) < 0)
131             pr("Try \"list of commands\" or \"info\"\n");
132     }
133     return 1;
134 }
135
136 static int
137 status(void)
138 {
139     struct natstr *natp;
140     int old_nstat;
141     char buf[128];
142
143     natp = getnatp(player->cnum);
144     if (player->dolcost > 100.0)
145         pr("That just cost you $%.2f\n", player->dolcost);
146     else if (player->dolcost < -100.0)
147         pr("You just made $%.2f\n", -player->dolcost);
148     if (player->dolcost != 0.0) {
149         /*
150          * Hackish work around for a race condition in the nightly
151          * build's regression tests: sometimes the update starts right
152          * after the force command yields, sometimes a bit later.  If
153          * it is late, we use one random number here, for the bye,
154          * and throwing off the random sequence.
155          */
156         natp->nat_money -= roundavg(player->dolcost);
157         player->dolcost = 0.0;
158     }
159
160     old_nstat = player->nstat;
161     player_set_nstat(player, natp);
162     if ((old_nstat & MONEY) && !(player->nstat & MONEY))
163         pr("You are now broke; industries are on strike.\n");
164     if (!(old_nstat & MONEY) && (player->nstat & MONEY))
165         pr("You are no longer broke!\n");
166
167     time(&player->curup);
168     update_timeused(player->curup);
169     if (io_error(player->iop) || io_eof(player->iop)
170         || !may_play_now(natp, player->curup))
171         return 0;
172
173     if (player->btused) {
174         natp->nat_btu -= player->btused;
175         player->btused = 0;
176     }
177     if (natp->nat_tgms > 0) {
178         if (!(natp->nat_flags & NF_INFORM)) {
179             if (natp->nat_tgms == 1)
180                 pr("You have a new telegram waiting ...\n");
181             else
182                 pr("You have %s new telegrams waiting ...\n",
183                    numstr(buf, natp->nat_tgms));
184             natp->nat_tgms = 0;
185         }
186     }
187     if (natp->nat_ann > 0) {
188         if (natp->nat_ann == 1)
189             pr("You have a new announcement waiting ...\n");
190         else
191             pr("You have %s new announcements waiting ...\n",
192                numstr(buf, natp->nat_ann));
193         natp->nat_ann = 0;
194     }
195     if (natp->nat_stat == STAT_ACTIVE && (player->nstat & CAP) == 0)
196         pr("You lost your capital... better designate one (see info capital)\n");
197     putnat(natp);
198     return 1;
199 }
200
201 /*
202  * Make all objects stale if ARG is one of the player's command arguments.
203  * See ef_make_stale() for what "making stale" means.
204  * Useful for functions that prompt for missing arguments.
205  * These can yield the processor, so we'd like to call ef_make_stale()
206  * there.  Except that leads to false positives when the caller passes
207  * an argument that is never null, and relies on the fact that the
208  * function doesn't yield then.  We can't know that in general.  But
209  * we do know in the common special case of command arguments.
210  */
211 void
212 make_stale_if_command_arg(char *arg)
213 {
214     if (player->argbuf <= arg
215         && arg <= player->argbuf + sizeof(player->argbuf))
216         ef_make_stale();
217 }
218
219 /*
220  * XXX This whole mess should be redone; execute block should
221  * start with "exec start", and should end with "exec end".
222  * We'll wait until 1.2 I guess.
223  */
224 int
225 execute(void)
226 {
227     char buf[1024];             /* UTF-8 */
228     int failed;
229     char *p;                    /* UTF-8 */
230     char *redir;                /* UTF-8 */
231
232     failed = 0;
233
234     p = player->comtail[1];
235     if (!p)
236         p = ugetstring("File? ", buf);
237     if (p == NULL || *p == '\0')
238         return RET_SYN;
239     prexec(p);
240
241     while (!failed && status() && !player->got_ctld) {
242         player->nstat &= ~EXEC;
243         if (getcommand(player->combuf) < 0)
244             break;
245         if (parse(player->combuf, player->argbuf, player->argp,
246                   player->comtail, &player->condarg, &redir) < 0) {
247             failed = 1;
248             continue;
249         }
250         pr("\nExecute : ");
251         uprnf(player->combuf);
252         pr("\n");
253         if (redir) {
254             pr("Execute : redirection not supported\n");
255             failed = 1;
256         } else if (dispatch(player->combuf, NULL) < 0)
257             failed = 1;
258         /* player->aborted not reset; makes next getcommand() fail */
259         empth_yield();
260     }
261     if (failed) {
262         while (recvclient(buf, sizeof(buf)) >= 0) ;
263     }
264
265     pr("Execute : %s\n", failed ? "aborted" : "terminated");
266     player->got_ctld = 0;
267     return RET_OK;
268 }
269
270 int
271 show_motd(void)
272 {
273     show_first_tel(motdfil);
274     return RET_OK;
275 }
276
277 int
278 quit(void)
279 {
280     io_set_eof(player->iop);
281     return RET_OK;
282 }
283
284 char *
285 praddr(struct player *p)
286 {
287     return prbuf("%s@%s", p->userid,
288                  *p->hostname ? p->hostname : p->hostaddr);
289 }