[BACK]Return to ttyrec.c CVS log [TXT][DIR] Up to [contributed] / dgamelaunch-openbsd

Annotation of dgamelaunch-openbsd/ttyrec.c, Revision 1.1.1.1

1.1       rubenllo    1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  */
                     33:
                     34: /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
                     35:  * - added Native Language Support
                     36:  */
                     37:
                     38: /* 2000-12-27 Satoru Takabayashi <satoru@namazu.org>
                     39:  * - modify `script' to create `ttyrec'.
                     40:  */
                     41:
                     42: /*
                     43:  * script
                     44:  */
                     45:
                     46: #include "dgamelaunch.h"
                     47: #include "config.h"
                     48:
                     49: #include <sys/types.h>
                     50: #include <sys/stat.h>
                     51: #include <sys/ioctl.h>
                     52: #include <sys/time.h>
                     53: #include <sys/wait.h>
                     54: #include <fcntl.h>
                     55:
                     56: #include <termios.h>
                     57: #include <time.h>
                     58: #include <signal.h>
                     59: #include <stdio.h>
                     60: #include <unistd.h>
                     61: #include <string.h>
                     62: #ifndef NOSTREAMS
                     63: # include <stropts.h>
                     64: #endif
                     65: #include <stdlib.h>
                     66: #include <stdint.h>
                     67:
                     68: #include "ttyrec.h"
                     69: #include "io.h"
                     70:
                     71: #ifndef XCASE
                     72: # define XCASE 0
                     73: #endif
                     74: static void query_encoding(int game, char *username);
                     75:
                     76: int slave;
                     77: pid_t dgl_parent;
                     78: pid_t child, subchild;
                     79: pid_t input_child;
                     80: char* ipfile = NULL;
                     81:
                     82: volatile int wait_for_menu = 0;
                     83:
                     84: FILE *fscript;
                     85: int master;
                     86:
                     87: struct termios tt;
                     88: struct winsize win;
                     89:
                     90: char last_ttyrec[512] = { '\0' };
                     91:
                     92: int ancient_encoding = 0;
                     93:
                     94: void
                     95: ttyrec_id(int game, char *username, char *ttyrec_filename)
                     96: {
                     97:     int i;
                     98:     time_t tstamp;
                     99:     Header h;
                    100:     char *buf = (char *)malloc(1024);
                    101:     char tmpbuf[256];
                    102:     char *server_id = banner_var_value("$SERVERID");
                    103:     if (!buf) return;
                    104:
                    105:     tstamp = time(NULL);
                    106:
                    107: #define dCLRSCR "\033[2J"
                    108: #define dCRLF   "\r\n"
                    109:     snprintf(buf, 1024,
                    110:             dCLRSCR "\033[1;1H" dCRLF
                    111:             "Player: %s" dCRLF
                    112:             "Game: %s" dCRLF
                    113:             "Server: %s" dCRLF
                    114:             "Filename: %s" dCRLF
                    115:             "Time: (%lu) %s" dCRLF
                    116:             dCLRSCR,
                    117:             username,
                    118:             myconfig[game]->game_name,
                    119:            (server_id ? server_id : "Unknown"),
                    120:             ttyrec_filename,
                    121:             tstamp, ctime(&tstamp)
                    122:             );
                    123: #undef dCLRSCR
                    124: #undef dCRLF
                    125:     h.len = strlen(buf);
                    126:     gettimeofday (&h.tv, NULL);
                    127:
                    128:     (void) write_header(fscript, &h);
                    129:     (void) fwrite(buf, 1, h.len, fscript);
                    130:
                    131:     free(buf);
                    132: }
                    133:
                    134: int
                    135: ttyrec_main (int game, char *username, char *ttyrec_path, char* ttyrec_filename)
                    136: {
                    137:   char dirname[100];
                    138:
                    139:   /* Note our PID to let children kill the main dgl process for idling */
                    140:   dgl_parent = getpid();
                    141:   child = subchild = input_child = 0;
                    142:
                    143:   if (!ttyrec_path) {
                    144:       child = fork();
                    145:       if (child < 0) {
                    146:          perror ("fork");
                    147:          fail ();
                    148:       }
                    149:       if (child == 0) {
                    150:          execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
                    151:       } else {
                    152:          int status;
                    153:          (void) wait(&status);
                    154:       }
                    155:       return 0;
                    156:   }
                    157:
                    158:   if (ttyrec_path[strlen(ttyrec_path)-1] == '/')
                    159:       snprintf (dirname, 100, "%s%s", ttyrec_path, ttyrec_filename);
                    160:   else
                    161:       snprintf (dirname, 100, "%s/%s", ttyrec_path, ttyrec_filename);
                    162:   ancient_encoding = myconfig[game]->encoding;
                    163:   if (ancient_encoding == -1)
                    164:       query_encoding(game, username);
                    165:
                    166:   snprintf(last_ttyrec, 512, "%s", dirname);
                    167:
                    168:   atexit(&remove_ipfile);
                    169:   if ((fscript = fopen (dirname, "w")) == NULL)
                    170:     {
                    171:       perror (dirname);
                    172:       fail ();
                    173:     }
                    174:   setbuf (fscript, NULL);
                    175:
                    176:   fixtty ();
                    177:
                    178:   (void) signal (SIGCHLD, finish);
                    179:   child = fork ();
                    180:   if (child < 0)
                    181:     {
                    182:       perror ("fork");
                    183:       fail ();
                    184:     }
                    185:   if (child == 0)
                    186:     {
                    187:       subchild = child = fork ();
                    188:       if (child < 0)
                    189:         {
                    190:           perror ("fork");
                    191:           fail ();
                    192:         }
                    193:       if (child)
                    194:         {
                    195:           close (slave);
                    196:           ipfile = gen_inprogress_lock (game, child, ttyrec_filename);
                    197:          ttyrec_id(game, username, ttyrec_filename);
                    198:           dooutput (myconfig[game]->max_idle_time);
                    199:         }
                    200:       else
                    201:          doshell (game, username);
                    202:     }
                    203:
                    204:   (void) fclose (fscript);
                    205:
                    206:   wait_for_menu = 1;
                    207:   input_child = fork();
                    208:   if (input_child < 0)
                    209:   {
                    210:       perror ("fork2");
                    211:       fail ();
                    212:   }
                    213:   if (!input_child)
                    214:       doinput ();
                    215:   else
                    216:   {
                    217:       while (wait_for_menu)
                    218:          sleep(1);
                    219:   }
                    220:
                    221:   remove_ipfile();
                    222:   child = 0;
                    223:
                    224:   return 0;
                    225: }
                    226:
                    227: void
                    228: doinput ()
                    229: {
                    230:   register int cc;
                    231:   char ibuf[BUFSIZ];
                    232:
                    233:   while ((cc = read (0, ibuf, BUFSIZ)) > 0)
                    234:     (void) write (master, ibuf, cc);
                    235:   done ();
                    236: }
                    237:
                    238: void
                    239: finish (int sig)
                    240: {
                    241:   int status;
                    242:   register int pid;
                    243:   register int die = 0;
                    244:
                    245:   (void)sig; /* unused */
                    246:
                    247:   while ((pid = wait3 (&status, WNOHANG, 0)) > 0)
                    248:   {
                    249:     if (pid == child)
                    250:       die = 1;
                    251:   }
                    252:
                    253:   if (die)
                    254:   {
                    255:       if (input_child)
                    256:       {
                    257:          // Need to kill the child that's writing input to pty.
                    258:          kill(input_child, SIGTERM);
                    259:          while ((pid = wait3(&status, WNOHANG, 0)) > 0);
                    260:       }
                    261:       else
                    262:          done ();
                    263:   }
                    264:   wait_for_menu = 0;
                    265: }
                    266:
                    267: void
                    268: game_idle_kill(int signal)
                    269: {
                    270:     kill(child, SIGHUP);
                    271:     kill(dgl_parent, SIGHUP);
                    272: }
                    273:
                    274: static unsigned short charset_vt100[128] =
                    275: {
                    276:     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
                    277:     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
                    278:     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
                    279:     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
                    280:     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
                    281:     0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
                    282:     0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
                    283:     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
                    284:     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
                    285:     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
                    286:     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
                    287:     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
                    288: #if 0
                    289:     0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
                    290:     0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0xf800,
                    291:     0xf801, 0x2500, 0xf803, 0xf804, 0x251c, 0x2524, 0x2534, 0x252c,
                    292:     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
                    293: #endif
                    294:     0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
                    295:     0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
                    296:     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
                    297:     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020,
                    298: };
                    299:
                    300: static unsigned short charset_cp437[256] =
                    301: {
                    302:     // Real IBM charset has no control codes, but they are needed by
                    303:     // terminals.
                    304:     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
                    305:     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
                    306:     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
                    307:     0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
                    308: #if 0
                    309:     0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
                    310:     0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
                    311:     0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
                    312:     0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
                    313: #endif
                    314:     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
                    315:     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
                    316:     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
                    317:     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
                    318:     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
                    319:     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
                    320:     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
                    321:     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
                    322:     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
                    323:     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
                    324:     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
                    325:     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
                    326:     0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
                    327:     0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
                    328:     0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
                    329:     0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
                    330:     0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
                    331:     0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
                    332:     0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
                    333:     0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
                    334:     0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
                    335:     0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
                    336:     0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
                    337:     0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
                    338:     0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
                    339:     0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
                    340:     0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
                    341:     0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
                    342: };
                    343:
                    344: // there must be at least 4 bytes free, NOT CHECKED!
                    345: static int wctoutf8(char *d, uint32_t s)
                    346: {
                    347:     if (s < 0x80)
                    348:     {
                    349:         d[0] = s;
                    350:         return 1;
                    351:     }
                    352:     if (s < 0x800)
                    353:     {
                    354:         d[0] = ( s >>  6)         | 0xc0;
                    355:         d[1] = ( s        & 0x3f) | 0x80;
                    356:         return 2;
                    357:     }
                    358:     if (s < 0x10000)
                    359:     {
                    360:         d[0] = ( s >> 12)         | 0xe0;
                    361:         d[1] = ((s >>  6) & 0x3f) | 0x80;
                    362:         d[2] = ( s        & 0x3f) | 0x80;
                    363:         return 3;
                    364:     }
                    365:     if (s < 0x110000)
                    366:     {
                    367:         d[0] = ( s >> 18)         | 0xf0;
                    368:         d[1] = ((s >> 12) & 0x3f) | 0x80;
                    369:         d[2] = ((s >>  6) & 0x3f) | 0x80;
                    370:         d[3] = ( s        & 0x3f) | 0x80;
                    371:         return 4;
                    372:     }
                    373:     // Invalid char marker (U+FFFD).
                    374:     d[0] = 0xef;
                    375:     d[1] = 0xbf;
                    376:     d[2] = 0xbd;
                    377:     return 3;
                    378: }
                    379:
                    380: void
                    381: dooutput (int max_idle_time)
                    382: {
                    383:   int cc, i, len;
                    384:   time_t tvec, time ();
                    385:   char obuf[BUFSIZ], ubuf[BUFSIZ*4+2], *ctime (), *out;
                    386:   int galt = 0; // vt100 G switch
                    387:
                    388:   setbuf (stdout, NULL);
                    389:   (void) close (0);
                    390:   tvec = time ((time_t *) NULL);
                    391:   /* Set up SIGALRM handler to kill idle games */
                    392:   signal(SIGALRM, game_idle_kill);
                    393:   for (;;)
                    394:     {
                    395:       Header h;
                    396:
                    397:       cc = read (master, obuf, BUFSIZ);
                    398:       if (cc <= 0)
                    399:         break;
                    400:
                    401:       if (max_idle_time)
                    402:           alarm(max_idle_time);
                    403:
                    404:       switch (ancient_encoding)
                    405:       {
                    406:       case 0:  // UTF-8
                    407:       default:
                    408:           h.len = cc;
                    409:           gettimeofday (&h.tv, NULL);
                    410:           (void) write (1, obuf, cc);
                    411:           (void) write_header (fscript, &h);
                    412:           (void) fwrite (obuf, 1, cc, fscript);
                    413:           break;
                    414:       case 1:  // IBM
                    415:           out = ubuf;
                    416:           // Old Crawl emits useless toggles of vt100 mode, even though it
                    417:           // never uses them in this mode.  And they break stuff...
                    418:           for (i = 0; i < cc; i++)
                    419:           {
                    420:               if (galt == 2) // ignore "ESC ( 0", "ESC ( B" and anything such
                    421:               {
                    422:                   galt = 0;
                    423:                   continue;
                    424:               }
                    425:               else if (galt == 1)
                    426:                   if (obuf[i] == '(')
                    427:                   {
                    428:                       galt = 2;
                    429:                       continue;
                    430:                   }
                    431:                   else
                    432:                   {
                    433:                       galt = 0; // false alarm, emit ESC and continue
                    434:                       *out ++ = 27;
                    435:                   }
                    436:               else if (obuf[i] == 27)
                    437:                   {
                    438:                       galt = 1;
                    439:                       continue;
                    440:                   }
                    441:               else if (obuf[i] == 14 || obuf[i] == 15)
                    442:                   continue;
                    443:               out += wctoutf8(out, charset_cp437[(unsigned char)obuf[i]]);
                    444:           }
                    445:           h.len = len = out - ubuf;
                    446:           gettimeofday(&h.tv, NULL);
                    447:           write(1, ubuf, len);
                    448:           write_header(fscript, &h);
                    449:           fwrite(ubuf, 1, len, fscript);
                    450:           break;
                    451:       case 2:  // DEC
                    452:           out = ubuf;
                    453:           for (i = 0; i < cc; i++)
                    454:           {
                    455:               if (obuf[i] == 14)
                    456:                   galt = 1;
                    457:               else if (obuf[i] == 15)
                    458:                   galt = 0;
                    459:               else if (obuf[i] & 0x80) // strictly 7-bit
                    460:                   out += wctoutf8(out, 0xFFFD); // or we could assume some other charset
                    461:               else if (galt)
                    462:                   out += wctoutf8(out, charset_vt100[(int)obuf[i]]);
                    463:               else
                    464:                   *out++ = obuf[i];
                    465:           }
                    466:           h.len = len = out - ubuf;
                    467:           gettimeofday(&h.tv, NULL);
                    468:           write(1, ubuf, len);
                    469:           write_header(fscript, &h);
                    470:           fwrite(ubuf, 1, len, fscript);
                    471:           break;
                    472:       }
                    473:     }
                    474:   done ();
                    475: }
                    476:
                    477: void
                    478: doshell (int game, char *username)
                    479: {
                    480:   getslave ();
                    481:   (void) close (master);
                    482:   (void) fclose (fscript);
                    483:   (void) dup2 (slave, 0);
                    484:   (void) dup2 (slave, 1);
                    485:   (void) dup2 (slave, 2);
                    486:   (void) close (slave);
                    487:
                    488:   /*
                    489:   if (myconfig[game]->mkdir)
                    490:       (void) mkdir(myconfig[game]->mkdir, 0755);
                    491:
                    492:   if (myconfig[game]->chdir)
                    493:       (void) chdir(myconfig[game]->chdir);
                    494:   */
                    495:
                    496:   execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
                    497:
                    498:   fail ();
                    499: }
                    500:
                    501: void
                    502: fixtty ()
                    503: {
                    504:   struct termios rtt;
                    505:
                    506:   rtt = tt;
                    507:   rtt.c_iflag = 0;
                    508:   rtt.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
                    509:   rtt.c_oflag = OPOST;
                    510:   rtt.c_cc[VINTR] = _POSIX_VDISABLE;
                    511:   rtt.c_cc[VQUIT] = _POSIX_VDISABLE;
                    512:   rtt.c_cc[VERASE] = _POSIX_VDISABLE;
                    513:   rtt.c_cc[VKILL] = _POSIX_VDISABLE;
                    514:   rtt.c_cc[VEOF] = 1;
                    515:   rtt.c_cc[VEOL] = 0;
                    516:   rtt.c_cc[VMIN] = 1;
                    517:   rtt.c_cc[VTIME] = 0;
                    518:   (void) tcsetattr (0, TCSAFLUSH, &rtt);
                    519: }
                    520:
                    521: void
                    522: fail ()
                    523: {
                    524:
                    525:   (void) kill (0, SIGTERM);
                    526:   done ();
                    527: }
                    528:
                    529: void
                    530: done ()
                    531: {
                    532:   time_t tvec, time ();
                    533:   char *ctime ();
                    534:
                    535:   if (subchild)
                    536:     {
                    537:       tvec = time ((time_t *) NULL);
                    538:       (void) fclose (fscript);
                    539:       (void) close (master);
                    540:     }
                    541:   else
                    542:     {
                    543:       (void) tcsetattr (0, TCSAFLUSH, &tt);
                    544:     }
                    545:
                    546:   remove_ipfile();
                    547:   graceful_exit (0);
                    548: }
                    549:
                    550: void
                    551: getslave ()
                    552: {
                    553:   (void) setsid ();
                    554:   /* grantpt( master);
                    555:      unlockpt(master);
                    556:      if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
                    557:      perror((const char *)ptsname(master));
                    558:      fail();
                    559:      perror("open(fd, O_RDWR)");
                    560:      fail();
                    561:      } */
                    562: #ifndef NOSTREAMS
                    563:   if (isastream (slave))
                    564:     {
                    565:       if (ioctl (slave, I_PUSH, "ptem") < 0)
                    566:         {
                    567:           perror ("ioctl(fd, I_PUSH, ptem)");
                    568:           fail ();
                    569:         }
                    570:       if (ioctl (slave, I_PUSH, "ldterm") < 0)
                    571:         {
                    572:           perror ("ioctl(fd, I_PUSH, ldterm)");
                    573:           fail ();
                    574:         }
                    575: #ifndef _HPUX_SOURCE
                    576:       if (ioctl (slave, I_PUSH, "ttcompat") < 0)
                    577:         {
                    578:           perror ("ioctl(fd, I_PUSH, ttcompat)");
                    579:           fail ();
                    580:         }
                    581: #endif
                    582:     }
                    583: #endif /* !NOSTREAMS */
                    584:   (void) ioctl (0, TIOCGWINSZ, (char *) &win);
                    585: }
                    586:
                    587: void
                    588: remove_ipfile (void)
                    589: {
                    590:     if (ipfile != NULL) {
                    591:        unlink (ipfile);
                    592:        free(ipfile);
                    593:        ipfile = NULL;
                    594:     }
                    595:     signal(SIGALRM, SIG_IGN);
                    596: }
                    597:
                    598: int encoding_by_name(const char *enc)
                    599: {
                    600:     if (!strcasecmp(enc, "UTF-8") || !strcasecmp(enc, "UNICODE"))
                    601:         return 0;
                    602:     if (!strcasecmp(enc, "IBM") || !strcasecmp(enc, "CP437"))
                    603:         return 1;
                    604:     if (!strcasecmp(enc, "DEC"))
                    605:         return 2;
                    606:     if (!strcasecmp(enc, "ASCII"))
                    607:         return 1; // what to do with invalid chars?
                    608:     return -1;
                    609: }
                    610:
                    611: static void call_print_charset(char *exe, char **args)
                    612: {
                    613:     char **args2, **a;
                    614:     int nargs = 0;
                    615:     for (args2 = args; *args2; args2++)
                    616:         nargs++;
                    617:     args2 = calloc(nargs + 1, sizeof(char*));
                    618:     for (a = args2; *args; args++)
                    619:         *a++ = *args;
                    620:
                    621:     *a++ = "--print-charset";
                    622:     *a = 0;
                    623:     execvp(exe, args2);
                    624: }
                    625:
                    626: static void query_encoding(int game, char *username)
                    627: {
                    628:     int son;
                    629:     int p[2];
                    630:     int null;
                    631:     struct timeval  tv;
                    632:     fd_set          se;
                    633:     char buf[128];
                    634:
                    635:     if (pipe(p))
                    636:         perror("pipe");
                    637:     switch(son = fork())
                    638:     {
                    639:     case -1:
                    640:         perror("fork");
                    641:         fail();
                    642:     case 0:
                    643:         null = open("/dev/null", O_RDONLY);
                    644:         if (null != -1)
                    645:             dup2(null, 0), close(null);
                    646:         else
                    647:         {
                    648:             fprintf(stderr, "Error: can't open /dev/null\n");
                    649:             // non-fatal, but if the child opens some other file, it might
                    650:             // get confused
                    651:             close(0);
                    652:         }
                    653:         dup2(p[1], 1);
                    654:         close(p[1]);
                    655:         close(p[0]);
                    656:         call_print_charset(myconfig[game]->game_path, myconfig[game]->bin_args);
                    657:         exit(1);
                    658:     }
                    659:     close(p[1]);
                    660:
                    661:     FD_ZERO(&se);
                    662:     FD_SET(p[0],&se);
                    663:     tv.tv_sec = 60; // FIXME: a huge delay, in case there's a db rebuild
                    664:     tv.tv_usec = 0;
                    665:     if (select(p[0]+1,&se,NULL,NULL,&tv) != 1)
                    666:     {
                    667:         fprintf(stderr, "Error: can't obtain charset info.\nPress any key...\n");
                    668:         read(0, buf, 1);
                    669:         close(p[0]); // SIGPIPE
                    670:         kill(son, SIGTERM); // and SIGTERM for a good measure
                    671:         waitpid(son, 0, 0);
                    672:         ancient_encoding = 0;
                    673:         return;
                    674:     }
                    675:
                    676:     // Sending _one_ short message over a pipe is atomic on all systems I know.
                    677:     // Don't assume this on about any other file descriptor.
                    678:     read(p[0], buf, sizeof(buf)-1);
                    679:     buf[sizeof(buf)-1] = 0;
                    680:     close(p[0]);
                    681:     kill(son, SIGTERM);
                    682:     waitpid(son, 0, 0);
                    683:     if (strchr(buf, '\n'))
                    684:         *strchr(buf, '\n') = 0;
                    685:     ancient_encoding = encoding_by_name(buf);
                    686:     if (ancient_encoding == -1)
                    687:     {
                    688:         fprintf(stderr, "Error: unknown encoding \"%s\"\nPress any key...\n", buf);
                    689:         read(0, buf, 1);
                    690:     }
                    691: }

CVSweb