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