]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
client: Improve the client's messages
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2015, 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  *  servercmd.c: Change the state depending on the command from the server.
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1989
31  *     Steve McClure, 1998
32  *     Ron Koenderink, 2005
33  *     Markus Armbruster, 2005-2015
34  */
35
36 #include <config.h>
37
38 #include <assert.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include "misc.h"
45 #include "proto.h"
46 #include "secure.h"
47
48 int eight_bit_clean;
49 FILE *auxfp;
50 int restricted;
51
52 static FILE *redir_fp;
53 static int redir_is_pipe;
54 static int executing;
55 static size_t input_to_forget;
56
57 static void prompt(int, char *, char *);
58 static void doredir(char *p);
59 static void dopipe(char *p);
60 static int doexecute(char *p);
61
62 void
63 servercmd(int code, char *arg, int len)
64 {
65     static int nmin, nbtu, fd;
66     static char the_prompt[1024];
67     static char teles[64];
68
69     switch (code) {
70     case C_PROMPT:
71         if (sscanf(arg, "%d %d", &nmin, &nbtu) != 2) {
72             fprintf(stderr, "Warning: server sent malformed prompt %s",
73                     arg);
74         }
75         snprintf(the_prompt, sizeof(the_prompt), "[%d:%d] Command : ",
76                  nmin, nbtu);
77         if (redir_fp) {
78             if (redir_is_pipe)
79                 (void)pclose(redir_fp);
80             else
81                 (void)fclose(redir_fp);
82             redir_fp = NULL;
83         }
84         if (input_to_forget) {
85             forget_input(input_to_forget);
86             input_to_forget = 0;
87         }
88         prompt(code, the_prompt, teles);
89         executing = 0;
90         break;
91     case C_FLUSH:
92         snprintf(the_prompt, sizeof(the_prompt), "%.*s", len - 1, arg);
93         prompt(code, the_prompt, teles);
94         break;
95     case C_EXECUTE:
96         fd = doexecute(arg);
97         if (fd < 0)
98             send_eof++;
99         else {
100             input_fd = fd;
101             executing = 1;
102         }
103         break;
104     case C_EXIT:
105         printf("Exit: %s", arg);
106         if (auxfp)
107             fprintf(auxfp, "Exit: %s", arg);
108         break;
109     case C_FLASH:
110         printf("\n%s", arg);
111         if (auxfp)
112             fprintf(auxfp, "\n%s", arg);
113         break;
114     case C_INFORM:
115         if (arg[0] != '\n') {
116             snprintf(teles, sizeof(teles), "(%.*s) ", len - 1, arg);
117             if (!redir_fp) {
118                 putchar('\07');
119                 prompt(code, the_prompt, teles);
120             }
121         } else
122             teles[0] = 0;
123         break;
124     case C_PIPE:
125         dopipe(arg);
126         break;
127     case C_REDIR:
128         doredir(arg);
129         break;
130     default:
131         assert(0);
132         break;
133     }
134 }
135
136 static void
137 prompt(int code, char *prompt, char *teles)
138 {
139     char *nl;
140
141     nl = code == C_PROMPT || code == C_INFORM ? "\n" : "";
142     printf("%s%s%s", nl, teles, prompt);
143     fflush(stdout);
144     if (auxfp) {
145         fprintf(auxfp, "%s%s%s", nl, teles, prompt);
146         fflush(auxfp);
147     }
148 }
149
150 static char *
151 fname(char *s)
152 {
153     char *beg, *end;
154
155     for (beg = s; isspace(*(unsigned char *)beg); beg++) ;
156     for (end = beg; !isspace(*(unsigned char *)end); end++) ;
157     *end = 0;
158     return beg;
159 }
160
161 static int
162 redir_authorized(char *arg, char *attempt, int expected)
163 {
164     size_t seen = seen_input(arg);
165
166     if (!expected) {
167         fprintf(stderr, "Warning: dropped conflicting %s %s",
168                 attempt, arg);
169         return 0;
170     }
171
172     if (!seen || (input_to_forget && input_to_forget != seen)) {
173         fprintf(stderr, "Warning: server attempted to %s %s",
174                 attempt, arg);
175         return 0;
176     }
177     input_to_forget = seen;
178
179     if (restricted) {
180         fprintf(stderr, "Can't %s in restricted mode\n", attempt);
181         return 0;
182     }
183
184     if (executing) {
185         fprintf(stderr, "Can't %s in a batch file\n", attempt);
186         return 0;
187     }
188     return 1;
189 }
190
191 static void
192 doredir(char *p)
193 {
194     int mode;
195     int fd;
196
197     if (!redir_authorized(p, "redirect to file", !redir_fp))
198         return;
199     if (*p++ != '>') {
200         fprintf(stderr, "Warning: dropped weird redirection %s", p);
201         return;
202     }
203
204     mode = O_WRONLY | O_CREAT;
205     if (*p == '>') {
206         mode |= O_APPEND;
207         p++;
208     } else if (*p == '!') {
209         mode |= O_TRUNC;
210         p++;
211     } else
212         mode |= O_EXCL;
213
214     p = fname(p);
215     if (*p == 0) {
216         fprintf(stderr, "Redirection lacks a file name\n");
217         return;
218     }
219
220     redir_is_pipe = 0;
221     fd = open(p, mode, 0666);
222     redir_fp = fd < 0 ? NULL : fdopen(fd, "w");
223     if (!redir_fp) {
224         fprintf(stderr, "Can't redirect to %s: %s\n",
225                 p, strerror(errno));
226     }
227 }
228
229 static void
230 dopipe(char *p)
231 {
232     if (!redir_authorized(p, "pipe to shell command", !redir_fp))
233         return;
234     if (*p++ != '|') {
235         fprintf(stderr, "Warning: dropped weird pipe %s", p);
236         return;
237     }
238
239     for (; *p && isspace(*p); p++) ;
240     if (*p == 0) {
241         fprintf(stderr, "Redirection lacks a command\n");
242         return;
243     }
244
245     /* strip newline */
246     p[strlen(p) - 1] = 0;
247
248     redir_is_pipe = 1;
249     errno = 0;
250     if ((redir_fp = popen(p, "w")) == NULL) {
251         fprintf(stderr, "Can't redirect to pipe %s%s%s\n",
252                 p, errno ? ": " : "", errno ? strerror(errno) : "");
253     }
254 }
255
256 static int
257 doexecute(char *p)
258 {
259     int fd;
260
261     if (!redir_authorized(p, "execute batch file", 1))
262         return -1;
263
264     p = fname(p);
265     if (*p == 0) {
266         fprintf(stderr, "Need a file to execute\n");
267         return -1;
268     }
269
270     if ((fd = open(p, O_RDONLY)) < 0) {
271         fprintf(stderr, "Can't open batch file %s: %s\n",
272                 p, strerror(errno));
273         return -1;
274     }
275
276     return fd;
277 }
278
279 void
280 outch(char c)
281 {
282     if (auxfp)
283         putc(c, auxfp);
284     if (redir_fp)
285         putc(c, redir_fp);
286     else if (eight_bit_clean) {
287         if (c == 14)
288             putso();
289         else if (c == 15)
290             putse();
291         else
292             putchar(c);
293     } else if (c & 0x80) {
294         putso();
295         putchar(c & 0x7f);
296         putse();
297     } else
298         putchar(c);
299 }