]> git.pond.sub.org Git - empserver/blob - src/client/main.c
[_WIN32,WIN32]: Remove the define WIN32.
[empserver] / src / client / main.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  *  main.c: client main function
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Steve McClure, 1998
33  *     Ron Koenderink, 2004-2005
34  *     Markus Armbruster, 2005
35  */
36
37 #include <config.h>
38
39 #include <errno.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #ifdef _WIN32
45 #include <windows.h>
46 #include <conio.h>
47 #include <io.h>
48 #else
49 #include <pwd.h>
50 #include <unistd.h>
51 #endif
52
53 #include "ioqueue.h"
54 #include "misc.h"
55 #include "proto.h"
56 #include "tags.h"
57
58 #ifdef _WIN32
59 HANDLE hStdIn;
60 #endif
61
62 #define RETRY   3
63
64 int eight_bit_clean;
65 int sock;
66
67 static volatile sig_atomic_t interrupt;
68 static void intr(int sig);
69 static int handleintr(int);
70
71 int
72 main(int ac, char **av)
73 {
74 #ifdef _WIN32
75     WORD wVersionRequested;
76     WSADATA WsaData;
77     int err;
78     fd_set readfds;
79     struct timeval tm;
80     DWORD stdinmode;
81     SECURITY_ATTRIBUTES security;
82     int bRedirected = 0;
83     char unamebuf[128];
84 #else
85     struct sigaction sa;
86     fd_set mask;
87     fd_set savemask;
88     int retry = 0;
89 #endif
90     struct ioqueue server;
91     char *argv[128];
92     int i, j;
93     char *ptr;
94     char *auxout_fname;
95     FILE *auxout_fp;
96     int n;
97     char *cname;
98     char *pname;
99     char *uname;
100     char *host;
101     char *port;
102     int send_kill = 0;
103     int utf8 = 0;
104
105 #ifdef _WIN32
106     /*
107      * stdout is unbuffered under Windows if connected to a character
108      * device, and putchar() screws up when printing multibyte strings
109      * bytewise to an unbuffered stream.  Switch stdout to line-
110      * buffered mode.  Unfortunately, ISO C allows implementations to
111      * screw that up, and of course Windows does.  Manual flushing
112      * after each prompt is required.
113      */
114     setvbuf(stdout, NULL, _IOLBF, 4096);
115     wVersionRequested = MAKEWORD(2, 0);
116     err = WSAStartup(wVersionRequested, &WsaData);
117     if (err != 0) {
118         printf("WSAStartup Failed, error code %d\n", err);
119         return FALSE;
120     }
121 #else
122     FD_ZERO(&mask);
123     FD_ZERO(&savemask);
124 #endif
125     memset(argv, 0, sizeof(argv));
126     saveargv(ac, av, argv);
127     auxout_fname = NULL;
128     auxout_fp = NULL;
129     for (i = j = 1; i < ac; ++i) {
130         ptr = argv[i];
131         if (strcmp(ptr, "-2") == 0) {
132             if (i + 1 >= ac) {
133                 fprintf(stderr, "-2: Missing filename!\n");
134                 exit(1);
135             }
136             auxout_fname = argv[i + 1];
137             ++i;
138             continue;
139         } else if (strcmp(ptr, "-k") == 0) {
140             send_kill = 1;
141             continue;
142         } else if (strcmp(ptr, "-u") == 0) {
143             utf8 = eight_bit_clean = 1;
144             continue;
145         }
146         argv[j] = argv[i];
147         ++j;
148     }
149     ac = j;
150     if (auxout_fname && (auxout_fp = fopen(auxout_fname, "a")) == NULL) {
151         fprintf(stderr, "Unable to open %s for append\n", auxout_fname);
152         exit(1);
153     }
154     getsose();
155     port = getenv("EMPIREPORT");
156     if (!port)
157         port = empireport;
158     host = getenv("EMPIREHOST");
159     if (!host)
160         host = empirehost;
161     sock = tcp_connect(host, port);
162     cname = getenv("COUNTRY");
163     if (ac > 1)
164         cname = argv[1];
165     pname = getenv("PLAYER");
166     if (ac > 2)
167         pname = argv[2];
168     uname = getenv("LOGNAME");
169     if (uname == NULL) {
170 #ifndef _WIN32
171         struct passwd *pwd;
172
173         pwd = getpwuid(getuid());
174         if (pwd == NULL) {
175             fprintf(stderr, "You don't exist.  Go away\n");
176             exit(1);
177         }
178         uname = pwd->pw_name;
179 #else
180         DWORD unamesize;
181
182         unamesize = sizeof(unamebuf);
183         if (GetUserName(unamebuf, &unamesize)) {
184             uname = unamebuf;
185             if ((unamesize <= 0 ) || (strlen(uname) <= 0))
186                 uname = "nobody";
187         } else
188             uname = "nobody";
189 #endif
190     }
191     if (!login(sock, uname, cname, pname, send_kill, utf8)) {
192 #ifdef _WIN32
193         closesocket(sock);
194 #else
195         close(sock);
196 #endif
197         exit(1);
198     }
199     ioq_init(&server, 2048);
200     io_init();
201 #ifndef _WIN32
202     FD_ZERO(&mask);
203     FD_SET(0, &savemask);
204     FD_SET(sock, &savemask);
205     sigemptyset(&sa.sa_mask);
206     sa.sa_flags = 0;
207     sa.sa_handler = intr;
208     sigaction(SIGINT, &sa, NULL);
209     sa.sa_handler = SIG_IGN;
210     sigaction(SIGPIPE, &sa, NULL);
211     while (FD_ISSET(sock, &savemask)) {
212         mask = savemask;
213         n = select(sock + 1, &mask, NULL, NULL, NULL);
214         if (interrupt) {
215             if (!handleintr(sock))
216                 break;
217             errno = 0;
218         }
219         if (n <= 0) {
220             if (errno == EINTR) {
221                 perror("select");
222                 (void)close(sock);
223                 FD_CLR(sock, &savemask);
224             }
225         } else {
226             if (FD_ISSET(0, &mask)) {
227                 if (!termio(0, sock, auxout_fp)) {
228                     if (retry++ >= RETRY) {
229                         FD_CLR(0, &savemask);
230                     }
231                 } else {
232                     retry = 0;
233                 }
234             }
235             if (FD_ISSET(sock, &mask)) {
236                 if (!serverio(sock, &server))
237                     FD_CLR(sock, &savemask);
238                 else
239                     servercmd(&server, auxout_fp);
240             }
241         }
242     }
243 #else  /* _WIN32 */
244     signal(SIGINT, intr);
245
246     bRedirected = 0;
247     tm.tv_sec = 0;
248     tm.tv_usec = 1000;
249
250     if (!isatty(fileno(stdin)))
251         bRedirected = 1;
252     else {
253         security.nLength = sizeof(SECURITY_ATTRIBUTES);
254         security.lpSecurityDescriptor = NULL;
255         security.bInheritHandle = TRUE;
256         hStdIn = CreateFile("CONIN$",
257                             GENERIC_READ | GENERIC_WRITE,
258                             FILE_SHARE_READ | FILE_SHARE_WRITE,
259                             &security, OPEN_EXISTING, (DWORD) NULL, NULL);
260         
261         if (hStdIn == INVALID_HANDLE_VALUE) {
262             printf("Error getting hStdIn.\n");
263             fflush(stdout);
264             exit(-3);
265         }
266         
267         err = GetConsoleMode(hStdIn, &stdinmode);
268         if (!err) {
269             printf("Error getting console mode.\n");
270             fflush(stdout);
271             exit(-4);
272         } else {
273             stdinmode |= ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT;
274             err = SetConsoleMode(hStdIn, stdinmode);
275             if (!err) {
276                 printf("Error setting console mode.\n");
277                 fflush(stdout);
278                 exit(-5);
279             }
280         }
281     }
282     while (1) {
283         FD_ZERO(&readfds);
284         FD_SET(sock, &readfds);
285         n = select(sock + 1, &readfds, NULL, NULL, &tm);
286         if (interrupt) {
287             if (!handleintr(sock))
288                 break;
289             errno = 0;
290         }
291         if (n < 0) {
292             if (errno == EINTR) {
293                 errno = WSAGetLastError();
294                 perror("select");
295                 (void)closesocket(sock);
296                 break;
297             }
298         } else {
299             if (bRedirected == 1) {
300                 if (!termio(0, sock, auxout_fp))
301                     bRedirected = -1;
302             } else if (bRedirected == 0) {
303                 if (WaitForSingleObject(hStdIn, 10) != WAIT_TIMEOUT) {
304                     termio(-1, sock, auxout_fp);
305                     FlushConsoleInputBuffer(hStdIn);
306                 }
307             }
308             if (FD_ISSET(sock, &readfds)) {
309                 if (!serverio(sock, &server))
310                     break;
311                 else
312                     servercmd(&server, auxout_fp);
313             }
314         }
315     }
316     if (bRedirected == 0)
317         CloseHandle(hStdIn);
318 #endif /* _WIN32 */
319     ioq_drain(&server);
320 #ifdef _WIN32
321     (void)closesocket(sock);
322 #else
323     (void)close(sock);
324 #endif
325     return 0;                   /* Shut the compiler up */
326 }
327
328 static void
329 intr(int sig)
330 {
331     interrupt = 1;
332 #ifdef _WIN32
333     signal(SIGINT, intr);
334 #endif
335 }
336
337 static int
338 handleintr(int s)
339 {
340     if (interrupt) {
341         /* tacky, but it works */
342 #if !defined(_WIN32)
343         if (write(s, "\naborted\n", 1 + 7 + 1) <= 0)
344 #else
345         if (send(s, "\naborted\n", 1 + 7 + 1, 0) <= 0)
346 #endif
347             return 0;
348         interrupt = 0;
349     }
350     return 1;
351 }