]> git.pond.sub.org Git - empserver/blob - src/client/servcmd.c
Update known contributors comment.
[empserver] / src / client / servcmd.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, 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  */
35
36 #include <config.h>
37
38 #include "misc.h"
39 #include "proto.h"
40 #include "queue.h"
41 #include "ioqueue.h"
42 #include "tags.h"
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <fcntl.h>
49 #if !defined(_WIN32)
50 #include <unistd.h>
51 #else
52 #include <io.h>
53 #endif
54
55 char num_teles[64];
56 static char the_prompt[1024];
57 static int mode;
58 static int nbtu;
59 static int nmin;
60 FILE *redir_fp;
61 FILE *pipe_fp;
62 int exec_fd;
63
64 static void prompt(FILE *auxfi);
65 static void doredir(char *p);
66 static void dopipe(char *p);
67 static void doexecute(char *p, FILE *auxfi);
68 static void output(int code, char *buf, FILE *auxfi, int eol);
69 static void screen(char *buf);
70
71 void
72 servercmd(struct ioqueue *ioq, FILE *auxfi)
73 {
74     char buf[1024];
75     char *p;
76     static int code = -1;
77     int eol;
78
79     while (ioq_gets(ioq, buf, sizeof(buf), &eol)) {
80         p = buf;
81         if (code == -1) {
82             if (isalpha(*buf))
83                 code = 10 + (*buf - 'a');
84             else
85                 code = *buf - '0';
86             while (*p && !isspace(*p))
87                 p++;
88             *p++ = 0;
89         }
90         /*
91          * FIXME
92          * C_REDIR, C_PIPE, and C_EXECUTE will not
93          * work with filename longer than one buffer
94          */
95         switch (code) {
96         case C_PROMPT:
97             if (sscanf(p, "%d %d", &nmin, &nbtu) != 2) {
98                 fprintf(stderr, "prompt: bad server prompt %s\n", p);
99             }
100             mode = code;
101             sprintf(the_prompt, "[%d:%d] Command : ", nmin, nbtu);
102             prompt(auxfi);
103             break;
104         case C_REDIR:
105             if (eol)
106                 p[strlen(p) - 1] = '\0';
107             doredir(p);
108             break;
109         case C_PIPE:
110             if (eol)
111                 p[strlen(p) - 1] = '\0';
112             dopipe(p);
113             break;
114         case C_FLUSH:
115             mode = code;
116             if (eol)
117                 p[strlen(p) - 1] = '\0';
118             sprintf(the_prompt, "%s", p);
119             prompt(auxfi);
120             break;
121         case C_EXECUTE:
122             if (eol)
123                 p[strlen(p) - 1] = '\0';
124             doexecute(p, auxfi);
125             break;
126         case C_INFORM:
127             if (eol)
128                 p[strlen(p) - 1] = '\0';
129             if (*p) {
130                 p[strlen(p) - 1] = '\0';
131                 sprintf(num_teles, "(%s) ", p + 1);
132                 if (!redir_fp && !pipe_fp && !exec_fd) {
133                     putchar('\07');
134                     prompt(NULL);
135                 }
136             } else
137                 *num_teles = '\0';
138             break;
139         default:
140             output(code, p, auxfi, eol);
141             break;
142         }
143         if (eol)
144             code = -1;
145     }
146 }
147
148 static void
149 prompt(FILE *auxfi)
150 {
151     if (mode == C_PROMPT) {
152         if (redir_fp) {
153             (void)fclose(redir_fp);
154             redir_fp = NULL;
155         } else if (pipe_fp) {
156             (void)pclose(pipe_fp);
157             pipe_fp = NULL;
158         } else if (exec_fd > 0) {
159             close(exec_fd);
160             close(0);
161             exec_fd = -1;
162             open("/dev/tty", O_RDONLY, 0);
163         }
164     }
165     if (mode == C_PROMPT)
166         printf("\n");
167     printf("%s%s", num_teles, the_prompt);
168     (void)fflush(stdout);
169     if (auxfi) {
170         fprintf(auxfi, "\n%s%s", num_teles, the_prompt);
171         (void)fflush(auxfi);
172     }
173 }
174
175 /*
176  * opens redir_fp if successful
177  */
178 static void
179 doredir(char *p)
180 {
181     char *how;
182     char *name;
183     char *tag;
184     int mode;
185     int fd;
186
187     if (redir_fp) {
188         (void)fclose(redir_fp);
189         redir_fp = NULL;
190     }
191     how = p++;
192     if (*p && ((*p == '>') || (*p == '!')))
193         p++;
194     tag = gettag(p);
195     while (*p && isspace(*p))
196         p++;
197     name = p;
198     while (*p && !isspace(*p))
199         p++;
200     *p = 0;
201     if (tag == NULL) {
202         fprintf(stderr, "WARNING!  Server redirected output to file %s\n",
203                 name);
204         return;
205     }
206     mode = O_WRONLY | O_CREAT;
207     if (how[1] == '>')
208         mode |= O_APPEND;
209     else if (how[1] == '!')
210         mode |= O_TRUNC;
211     else
212         mode |= O_EXCL;
213     if (*name == 0) {
214         fprintf(stderr, "Null file name after redirect\n");
215         free(tag);
216         return;
217     }
218     if ((fd = open(name, mode, 0600)) < 0) {
219         fprintf(stderr, "Redirect open failed\n");
220         perror(name);
221     } else {
222         redir_fp = fdopen(fd, "w");
223     }
224     free(tag);
225 }
226
227 /*
228  * opens "pipe_fp" if successful
229  */
230 static void
231 dopipe(char *p)
232 {
233     char *tag;
234
235     if (*p == '|')
236         p++;
237     tag = gettag(p);
238     while (*p && isspace(*p))
239         p++;
240     if (tag == NULL) {
241         fprintf(stderr, "WARNING!  Server attempted to run: %s\n", p);
242         return;
243     }
244     if (*p == 0) {
245         fprintf(stderr, "Null program name after redirect\n");
246         free(tag);
247         return;
248     }
249     if ((pipe_fp = popen(p, "w")) == NULL) {
250         fprintf(stderr, "Pipe open failed\n");
251         perror(p);
252     }
253     free(tag);
254 }
255
256 static void
257 doexecute(char *p, FILE *auxfi)
258 {
259     int fd;
260     char *tag;
261
262     tag = gettag(p);
263     while (*p && isspace(*p))
264         p++;
265     if (tag == NULL) {
266         fprintf(stderr,
267                 "WARNING!  Server attempted unauthorized read of file %s\n",
268                 p);
269         return;
270     }
271     if (p == NULL) {
272         fprintf(stderr, "Null file to execute\n");
273         free(tag);
274         return;
275     }
276     if ((fd = open(p, O_RDONLY, 0)) < 0) {
277         fprintf(stderr, "Can't open execute file\n");
278         perror(p);
279         free(tag);
280         return;
281     }
282     /* copies 4k at a time to the socket */
283     while (termio(fd, sock, auxfi))     /*do copy */
284         ;
285     /* Some platforms don't send the eof (cntl-D) at the end of
286        copying a file.  If emp_client hangs at the end of an
287        execute, include the following line and notify wolfpack
288        of the platform you are using.
289        sendeof(sock);
290      */
291     close(fd);
292     free(tag);
293 }
294
295 static void
296 output(int code, char *buf, FILE *auxfi, int eol)
297 {
298     switch (code) {
299     case C_NOECHO:
300         /* not implemented; serve doesn't send it */
301         break;
302     case C_ABORT:
303         printf("Aborted\n");
304         if (auxfi)
305             fprintf(auxfi, "Aborted\n");
306         break;
307     case C_CMDERR:
308     case C_BADCMD:
309         printf("Error; ");
310         if (auxfi)
311             fprintf(auxfi, "Error; ");
312         break;
313     case C_EXIT:
314         printf("Exit: ");
315         if (auxfi)
316             fprintf(auxfi, "Exit: ");
317         break;
318     case C_FLASH:
319         printf("\n");
320         break;
321     default:
322         break;
323     }
324     if (auxfi) {
325         fprintf(auxfi, "%s", buf);
326     }
327
328     if (redir_fp)
329         fprintf(redir_fp, "%s", buf);
330     else if (pipe_fp)
331         fprintf(pipe_fp, "%s", buf);
332     else {
333         screen(buf);
334     }
335 }
336
337 static void
338 screen(char *buf)
339 {
340     char c;
341
342     while ((c = *buf++)) {
343         if (eight_bit_clean) {
344             if (c == 14)
345                 putso();
346             else if (c == 15)
347                 putse();
348             else
349                 putchar(c);
350         } else if (c & 0x80) {
351             putso();
352             putchar(c & 0x7f);
353             putse();
354         } else
355             putchar(c);
356     }
357 }