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