Annotation of dgamelaunch-openbsd/dgamelaunch.c, Revision 1.1
1.1 ! rubenllo 1: /* dgamelaunch.c
! 2: *
! 3: * (c)2001-4 M. Drew Streib <dtype@dtype.org>
! 4: * also parts (c) 2003-4 Joshua Kwan <joshk@triplehelix.org>,
! 5: * Brett Carrington <brettcar@segvio.org>,
! 6: * Jilles Tjoelker <jilles@stack.nl>
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify
! 9: * it under the terms of the GNU General Public License as published by
! 10: * the Free Software Foundation; either version 2 of the License, or
! 11: * (at your option) any later version.
! 12: *
! 13: * This program is distributed in the hope that it will be useful,
! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 16: * GNU General Public License for more details.
! 17: *
! 18: * You should have received a copy of the GNU General Public License
! 19: * along with this program; if not, write to the Free Software
! 20: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
! 21: */
! 22:
! 23: /*
! 24: * See this program in action at http://alt.org/nethack/
! 25: *
! 26: * This is a little wrapper for nethack (and soon other programs) that
! 27: * will allow them to be run from a telnetd session, chroot, shed privs,
! 28: * make a simple login, then play the game.
! 29: */
! 30:
! 31: #define _GNU_SOURCE
! 32:
! 33: #include "dgamelaunch.h"
! 34: #include "config.h"
! 35: #include "ttyplay.h"
! 36: #include "ttyrec.h"
! 37:
! 38: /* a request from the author: please leave some remnance of
! 39: * 'based on dgamelaunch version xxx' in any derivative works, or
! 40: * even keep the line the same altogether. I'm probably happy
! 41: * to make any changes you need. */
! 42:
! 43: /* ************************************************************* */
! 44:
! 45: /* program stuff */
! 46: #include <sys/types.h>
! 47: #include <sys/time.h>
! 48: #include <sys/wait.h>
! 49: #include <sys/ioctl.h> /* ttyrec */
! 50: #include <sys/stat.h>
! 51: #ifdef USE_RLIMIT
! 52: #include <sys/resource.h>
! 53: #endif
! 54:
! 55: #ifdef USE_SHMEM
! 56: #include <sys/ipc.h>
! 57: #include <sys/shm.h>
! 58: #endif
! 59:
! 60: #include <libgen.h>
! 61: #include <stdlib.h>
! 62: #include <curses.h>
! 63: #include <locale.h>
! 64:
! 65: #ifdef USE_SQLITE3
! 66: # include <sqlite3.h>
! 67: #endif
! 68:
! 69: #if defined(__FreeBSD__)
! 70: # include <libutil.h>
! 71: #elif defined(__NetBSD__)
! 72: # include <util.h>
! 73: #elif defined(__APPLE__)
! 74: # include <unistd.h>
! 75: #else
! 76: # include <crypt.h>
! 77: #endif
! 78:
! 79: #ifdef __linux__
! 80: # include <pty.h>
! 81: #endif
! 82:
! 83: #include <fcntl.h>
! 84: #include <pwd.h>
! 85: #include <grp.h>
! 86: #include <time.h>
! 87: #include <errno.h>
! 88: #include <dirent.h>
! 89: #include <string.h>
! 90: #include <signal.h>
! 91: #include <assert.h>
! 92: #include <ctype.h>
! 93: #include <unistd.h>
! 94: #include <termios.h>
! 95:
! 96: extern FILE* yyin;
! 97: extern int yyparse ();
! 98:
! 99: /* global variables */
! 100:
! 101: char * __progname;
! 102: int g_idle_alarm_enabled = 0;
! 103: int showplayers = 0;
! 104: int initplayer = 0;
! 105: void (*g_chain_winch)(int);
! 106:
! 107: #ifndef USE_SQLITE3
! 108: int f_num = 0;
! 109: struct dg_user **users = NULL;
! 110: #endif
! 111: struct dg_user *me = NULL;
! 112: struct dg_banner banner;
! 113:
! 114: static struct dg_watchcols default_watchcols[] = {
! 115: {SORTMODE_NONE, SORTMODE_NONE, 1, "", "%s)"},
! 116: {SORTMODE_USERNAME, SORTMODE_USERNAME, 4, "Username", "%-15s"},
! 117: {SORTMODE_GAMENUM, SORTMODE_GAMENUM, 21, "Game", "%-5s"},
! 118: {SORTMODE_WINDOWSIZE, SORTMODE_WINDOWSIZE, 28, " Size", "%s"},
! 119: {SORTMODE_STARTTIME, SORTMODE_STARTTIME, 37, "Start date & time", "%s"},
! 120: {SORTMODE_IDLETIME, SORTMODE_IDLETIME, 58, "Idle time", "%-10s"},
! 121: #ifdef USE_SHMEM
! 122: {SORTMODE_WATCHERS, SORTMODE_WATCHERS, 70, "Watchers", "%s"},
! 123: #endif
! 124: };
! 125:
! 126: int color_remap[16] = {
! 127: COLOR_PAIR(9) | A_NORMAL,
! 128: COLOR_PAIR(COLOR_BLUE) | A_NORMAL,
! 129: COLOR_PAIR(COLOR_GREEN) | A_NORMAL,
! 130: COLOR_PAIR(COLOR_CYAN) | A_NORMAL,
! 131: COLOR_PAIR(COLOR_RED) | A_NORMAL,
! 132: COLOR_PAIR(COLOR_MAGENTA) | A_NORMAL,
! 133: COLOR_PAIR(COLOR_YELLOW) | A_NORMAL,
! 134: COLOR_PAIR(COLOR_BLACK) | A_NORMAL,
! 135: COLOR_PAIR(10) | A_BOLD,
! 136: COLOR_PAIR(COLOR_BLUE) | A_BOLD,
! 137: COLOR_PAIR(COLOR_GREEN) | A_BOLD,
! 138: COLOR_PAIR(COLOR_CYAN) | A_BOLD,
! 139: COLOR_PAIR(COLOR_RED) | A_BOLD,
! 140: COLOR_PAIR(COLOR_MAGENTA) | A_BOLD,
! 141: COLOR_PAIR(COLOR_YELLOW) | A_BOLD,
! 142: COLOR_PAIR(COLOR_WHITE) | A_BOLD,
! 143: };
! 144:
! 145: static struct dg_watchcols *default_watchcols_list[DGL_MAXWATCHCOLS + 1];
! 146:
! 147: struct dg_user *
! 148: cpy_me(struct dg_user *me)
! 149: {
! 150: struct dg_user *tmp = malloc(sizeof(struct dg_user));
! 151:
! 152: if (tmp && me) {
! 153: #ifdef USE_SQLITE3
! 154: tmp->id = me->id;
! 155: #endif
! 156: if (me->username) tmp->username = strdup(me->username);
! 157: if (me->email) tmp->email = strdup(me->email);
! 158: if (me->env) tmp->env = strdup(me->env);
! 159: if (me->password) tmp->password = strdup(me->password);
! 160: tmp->flags = me->flags;
! 161: }
! 162: return tmp;
! 163: }
! 164:
! 165: #ifndef HAVE_SETENV
! 166: int
! 167: mysetenv (const char* name, const char* value, int overwrite)
! 168: {
! 169: int retval;
! 170: char *buf = NULL;
! 171:
! 172: if (getenv(name) == NULL || overwrite)
! 173: {
! 174: size_t len = strlen(name) + 1 + strlen(value) + 1; /* NAME=VALUE\0 */
! 175: buf = malloc(len);
! 176: snprintf(buf, len, "%s=%s", name, value);
! 177: retval = putenv(buf);
! 178: }
! 179: else
! 180: retval = -1;
! 181:
! 182: return retval;
! 183: }
! 184: #else /* use native setenv */
! 185: # define mysetenv setenv
! 186: #endif
! 187:
! 188: /* ************************************************************* */
! 189: /* for ttyrec */
! 190:
! 191: void
! 192: ttyrec_getpty ()
! 193: {
! 194: #ifdef HAVE_OPENPTY
! 195: if (openpty (&master, &slave, NULL, NULL, NULL) == -1) {
! 196: debug_write("cannot openpty");
! 197: graceful_exit (61);
! 198: }
! 199: #else
! 200: if ((master = open ("/dev/ptmx", O_RDWR)) < 0) {
! 201: debug_write("cannot open /dev/ptmx");
! 202: graceful_exit (62);
! 203: }
! 204: grantpt (master);
! 205: unlockpt (master);
! 206: if ((slave = open ((const char *) ptsname (master), O_RDWR)) < 0)
! 207: {
! 208: debug_write("cannot open master ptsname");
! 209: graceful_exit (65);
! 210: }
! 211: #endif
! 212: ioctl (slave, TIOCSWINSZ, (char *) &win);
! 213: tcsetattr(slave, TCSANOW, &tt);
! 214: }
! 215:
! 216: /* ************************************************************* */
! 217:
! 218: static int dgl_signal_blocked = 0;
! 219: static sigset_t dgl_signal_blockmask;
! 220: static sigset_t dgl_signal_oldmask;
! 221:
! 222: void
! 223: signals_block()
! 224: {
! 225: if (!dgl_signal_blocked) {
! 226: sigemptyset(&dgl_signal_blockmask);
! 227: sigaddset(&dgl_signal_blockmask, SIGHUP);
! 228: sigaddset(&dgl_signal_blockmask, SIGINT);
! 229: sigaddset(&dgl_signal_blockmask, SIGQUIT);
! 230: sigaddset(&dgl_signal_blockmask, SIGTERM);
! 231: sigprocmask(SIG_BLOCK, &dgl_signal_blockmask, &dgl_signal_oldmask);
! 232: dgl_signal_blocked = 1;
! 233: }
! 234: }
! 235:
! 236: void
! 237: signals_release()
! 238: {
! 239: if (dgl_signal_blocked) {
! 240: sigprocmask(SIG_SETMASK, &dgl_signal_oldmask, NULL);
! 241: dgl_signal_blocked = 0;
! 242: }
! 243: }
! 244:
! 245:
! 246: /* ************************************************************* */
! 247:
! 248: char *
! 249: get_mainmenu_name()
! 250: {
! 251: if (loggedin) {
! 252: if (me && (me->flags & DGLACCT_ADMIN)) return "mainmenu_admin";
! 253: return "mainmenu_user";
! 254: }
! 255: return "mainmenu_anon";
! 256: }
! 257:
! 258:
! 259: char*
! 260: gen_ttyrec_filename ()
! 261: {
! 262: time_t rawtime;
! 263: struct tm *ptm;
! 264: char *ttyrec_filename = calloc(100, sizeof(char));
! 265:
! 266: /* append time to filename */
! 267: time (&rawtime);
! 268: ptm = gmtime (&rawtime);
! 269: snprintf (ttyrec_filename, 100, "%04i-%02i-%02i.%02i:%02i:%02i.ttyrec",
! 270: ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
! 271: ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
! 272: return ttyrec_filename;
! 273: }
! 274:
! 275: /* ************************************************************* */
! 276:
! 277: char*
! 278: gen_inprogress_lock (int game, pid_t pid, char* ttyrec_filename)
! 279: {
! 280: char *lockfile = NULL, filebuf[80];
! 281: int fd;
! 282: size_t len, wrlen;
! 283: struct flock fl = { 0 };
! 284:
! 285: snprintf (filebuf, sizeof(filebuf), "%d\n%d\n%d\n",
! 286: pid, win.ws_row, win.ws_col);
! 287:
! 288: wrlen = strlen(filebuf);
! 289:
! 290: fl.l_type = F_WRLCK;
! 291: fl.l_whence = SEEK_SET;
! 292: fl.l_start = 0;
! 293: fl.l_len = 0;
! 294:
! 295: len = strlen(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL)) + strlen(me->username) + strlen(ttyrec_filename) + 13;
! 296: lockfile = calloc(len, sizeof(char));
! 297:
! 298: snprintf (lockfile, len, "%s%s:%s", dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL),
! 299: me->username, ttyrec_filename);
! 300:
! 301: fd = open (lockfile, O_WRONLY | O_CREAT, 0644);
! 302: if (fcntl (fd, F_SETLKW, &fl) == -1) {
! 303: debug_write("cannot fnctl inprogress-lock");
! 304: graceful_exit (68);
! 305: }
! 306:
! 307: if (write (fd, filebuf, wrlen) != wrlen) {
! 308: debug_write("inprogress-lock write");
! 309: graceful_exit(70);
! 310: }
! 311:
! 312: return lockfile;
! 313: }
! 314:
! 315: /* ************************************************************* */
! 316:
! 317: #ifdef USE_SHMEM
! 318: int hup_shm_idx = -1;
! 319: char *hup_shm_ttyrec_fn = NULL;
! 320: #endif
! 321:
! 322: void
! 323: catch_sighup (int signum)
! 324: {
! 325: if (child)
! 326: {
! 327: sleep (10);
! 328: kill (child, SIGHUP);
! 329: sleep (5);
! 330: }
! 331: #ifdef USE_SHMEM
! 332: signals_block();
! 333: if (hup_shm_idx != -1) {
! 334: struct dg_shm *shm_dg_data = NULL;
! 335: struct dg_shm_game *shm_dg_game = NULL;
! 336: shm_init(&shm_dg_data, &shm_dg_game);
! 337:
! 338: shm_sem_wait(shm_dg_data);
! 339: if (shm_dg_game[hup_shm_idx].in_use &&
! 340: !strcmp(shm_dg_game[hup_shm_idx].ttyrec_fn, hup_shm_ttyrec_fn) &&
! 341: (shm_dg_game[hup_shm_idx].nwatchers > 0)) {
! 342: shm_dg_game[hup_shm_idx].nwatchers--;
! 343: }
! 344: shm_sem_post(shm_dg_data);
! 345: hup_shm_idx = -1;
! 346: free(hup_shm_ttyrec_fn);
! 347: }
! 348: signals_release();
! 349: #endif
! 350: debug_write("catchup sighup");
! 351: graceful_exit (7);
! 352: }
! 353:
! 354: /* ************************************************************* */
! 355:
! 356: int
! 357: dgl_getch(void)
! 358: {
! 359: const int c = getch();
! 360: idle_alarm_reset();
! 361: return c;
! 362: }
! 363:
! 364: /* ************************************************************* */
! 365:
! 366: static void
! 367: dgl_idle_kill(int signal)
! 368: {
! 369: kill(0, SIGHUP);
! 370: }
! 371:
! 372: void
! 373: idle_alarm_set_enabled(int enabled)
! 374: {
! 375: signal(SIGALRM, SIG_IGN);
! 376: g_idle_alarm_enabled = enabled;
! 377: idle_alarm_reset();
! 378: if (enabled)
! 379: signal(SIGALRM, dgl_idle_kill);
! 380: }
! 381:
! 382: void
! 383: idle_alarm_reset(void)
! 384: {
! 385: if (g_idle_alarm_enabled && globalconfig.menu_max_idle_time > 0)
! 386: alarm(globalconfig.menu_max_idle_time);
! 387: }
! 388:
! 389: /* ************************************************************* */
! 390:
! 391:
! 392: char *
! 393: bannerstrmangle(char *buf, char *bufnew, int buflen, char *fromstr, char *tostr)
! 394: {
! 395: char *loc;
! 396: char *b = buf;
! 397:
! 398: memset (bufnew, 0, buflen);
! 399:
! 400: if (strstr(b, fromstr)) {
! 401: int i = 0;
! 402: while ((loc = strstr (b, fromstr)) != NULL) {
! 403: for (; i < buflen; i++) {
! 404: if (loc != b)
! 405: bufnew[i] = *(b++);
! 406: else {
! 407: strlcat (bufnew, tostr, buflen);
! 408: b += strlen(fromstr);
! 409: i += strlen(tostr);
! 410: break;
! 411: }
! 412:
! 413: if (strlen (b) == 0)
! 414: break;
! 415: }
! 416: }
! 417:
! 418: if (*b)
! 419: strlcat(bufnew, b, buflen);
! 420: } else strncpy(bufnew, buf, buflen);
! 421: return bufnew;
! 422: }
! 423:
! 424: void
! 425: banner_var_add(char *name, char *value, int special)
! 426: {
! 427: struct dg_banner_var *tmp = (struct dg_banner_var *)malloc(sizeof(struct dg_banner_var));
! 428:
! 429: if (!tmp) return;
! 430:
! 431: tmp->name = strdup(name);
! 432: tmp->value = strdup(value);
! 433: tmp->special = special;
! 434: tmp->next = globalconfig.banner_var_list;
! 435: globalconfig.banner_var_list = tmp;
! 436: }
! 437:
! 438: void
! 439: banner_var_free()
! 440: {
! 441: struct dg_banner_var *tmp;
! 442: struct dg_banner_var *bv = globalconfig.banner_var_list;
! 443: while (bv) {
! 444: tmp = bv->next;
! 445: free(bv->name);
! 446: free(bv->value);
! 447: free(bv);
! 448: bv = tmp;
! 449: }
! 450: globalconfig.banner_var_list = NULL;
! 451: }
! 452:
! 453: char *
! 454: banner_var_resolve(struct dg_banner_var *bv)
! 455: {
! 456: static char tmpbuf[DGL_BANNER_LINELEN+1];
! 457: time_t tstamp;
! 458: struct tm *ptm;
! 459: if (!bv) return NULL;
! 460: if (!bv->special) return bv->value;
! 461: time(&tstamp);
! 462: ptm = gmtime(&tstamp);
! 463: strftime(tmpbuf, DGL_BANNER_LINELEN, bv->value, ptm);
! 464: return tmpbuf;
! 465: }
! 466:
! 467: char *
! 468: banner_var_value(char *name)
! 469: {
! 470: struct dg_banner_var *bv = globalconfig.banner_var_list;
! 471: while (bv) {
! 472: if (!strcmp(bv->name, name)) return banner_var_resolve(bv);
! 473: bv = bv->next;
! 474: }
! 475: return NULL;
! 476: }
! 477:
! 478: void
! 479: freebanner(struct dg_banner *ban)
! 480: {
! 481: unsigned int l;
! 482: if (!ban) return;
! 483: l = ban->len;
! 484:
! 485: while (l > 0) {
! 486: l--;
! 487: free(ban->lines[l]);
! 488: }
! 489: free(ban->lines);
! 490: ban->len = 0;
! 491: ban->lines = NULL;
! 492: }
! 493:
! 494: void
! 495: banner_addline(struct dg_banner *ban, char *line)
! 496: {
! 497: size_t len = strlen(line);
! 498: if (!ban) return;
! 499: ban->len++;
! 500: ban->lines = realloc (ban->lines, sizeof (char *) * ban->len);
! 501: if (len >= DGL_BANNER_LINELEN) {
! 502: len = DGL_BANNER_LINELEN;
! 503: ban->lines[ban->len - 1] = malloc(len);
! 504: strncpy(ban->lines[ban->len - 1], line, len);
! 505: ban->lines[ban->len - 1][len-1] = '\0';
! 506: } else
! 507: ban->lines[ban->len - 1] = strdup(line);
! 508: }
! 509:
! 510: void
! 511: loadbanner (char *fname, struct dg_banner *ban)
! 512: {
! 513: FILE *bannerfile;
! 514: char buf[DGL_BANNER_LINELEN+1];
! 515: if (ban->len > 23) return;
! 516:
! 517: memset (buf, 0, DGL_BANNER_LINELEN);
! 518:
! 519: bannerfile = fopen (fname, "r");
! 520:
! 521: if (!bannerfile)
! 522: {
! 523: if (ban->len == 0)
! 524: banner_addline(ban, "### dgamelaunch " PACKAGE_VERSION " - network console game launcher");
! 525: snprintf(buf, DGL_BANNER_LINELEN, "### NOTE: administrator has not installed a %s file", fname);
! 526: banner_addline(ban, buf);
! 527: return;
! 528: }
! 529:
! 530: while (fgets (buf, DGL_BANNER_LINELEN, bannerfile) != NULL)
! 531: {
! 532: char bufnew[DGL_BANNER_LINELEN+1];
! 533: int slen;
! 534:
! 535: memset (bufnew, 0, DGL_BANNER_LINELEN);
! 536:
! 537: slen = strlen(buf);
! 538: if ((slen > 0) && (buf[slen-1] == '\n')) buf[slen-1] = '\0';
! 539:
! 540: strncpy(bufnew, buf, DGL_BANNER_LINELEN);
! 541: if (strstr(bufnew, "$INCLUDE(")) {
! 542: char *fn = bufnew + 9;
! 543: char *fn_end = strchr(fn, ')');
! 544: if (fn_end) {
! 545: *fn_end = '\0';
! 546: if (strcmp(fname, fn)) {
! 547: loadbanner(fn, ban);
! 548: }
! 549: }
! 550: } else {
! 551: char tmpbufnew[DGL_BANNER_LINELEN+1];
! 552: struct dg_banner_var *bv = globalconfig.banner_var_list;
! 553: while (bv) {
! 554: strncpy(bufnew, bannerstrmangle(bufnew, tmpbufnew, DGL_BANNER_LINELEN, bv->name, banner_var_resolve(bv)), DGL_BANNER_LINELEN);
! 555: bv = bv->next;
! 556: }
! 557: strncpy(bufnew, bannerstrmangle(bufnew, tmpbufnew, DGL_BANNER_LINELEN, "$VERSION", PACKAGE_STRING), DGL_BANNER_LINELEN);
! 558: if (me && loggedin) {
! 559: strncpy(bufnew, bannerstrmangle(bufnew, tmpbufnew, DGL_BANNER_LINELEN, "$USERNAME", me->username), DGL_BANNER_LINELEN);
! 560: } else {
! 561: strncpy(bufnew, bannerstrmangle(bufnew, tmpbufnew, DGL_BANNER_LINELEN, "$USERNAME", "[Anonymous]"), DGL_BANNER_LINELEN);
! 562: }
! 563: banner_addline(ban, bufnew);
! 564: }
! 565:
! 566: memset (buf, 0, DGL_BANNER_LINELEN);
! 567:
! 568: if (ban->len >= 24)
! 569: break;
! 570: }
! 571:
! 572: fclose (bannerfile);
! 573: }
! 574:
! 575: void
! 576: drawbanner (struct dg_banner *ban)
! 577: {
! 578: unsigned int i;
! 579: char *tmpch, *tmpch2, *splch;
! 580: int attr = 0, oattr = 0;
! 581:
! 582: if (!ban) return;
! 583:
! 584: for (i = 0; i < ban->len; i++) {
! 585: char *tmpbuf = strdup(ban->lines[i]);
! 586: char *tmpbuf2 = tmpbuf;
! 587: int ok = 0;
! 588: int x = 1;
! 589: do {
! 590: ok = 0;
! 591: if ((tmpch = strstr(tmpbuf2, "$ATTR("))) {
! 592: if ((tmpch2 = strstr(tmpch, ")"))) {
! 593: int spl = 0;
! 594: char *nxttmpch;
! 595: ok = 1;
! 596: oattr = attr;
! 597: attr = A_NORMAL;
! 598: *tmpch = *tmpch2 = '\0';
! 599: tmpch += 6;
! 600: nxttmpch = tmpch;
! 601: do {
! 602: spl = 0;
! 603: splch = strchr(tmpch, ';');
! 604: if (splch && *splch) {
! 605: spl = 1;
! 606: nxttmpch = splch;
! 607: *nxttmpch = '\0';
! 608: nxttmpch++;
! 609: }
! 610: if (tmpch && *tmpch) {
! 611: switch (*tmpch) {
! 612: default: break;
! 613: case '0': case '1': case '2': case '3': case '4':
! 614: case '5': case '6': case '7': case '8': case '9':
! 615: {
! 616: int num = atoi(tmpch);
! 617: if (num >= 0 && num <= 15)
! 618: attr |= color_remap[num];
! 619: }
! 620: break;
! 621: case 'b': attr |= A_BOLD; break;
! 622: case 's': attr |= A_STANDOUT; break;
! 623: case 'u': attr |= A_UNDERLINE; break;
! 624: case 'r': attr |= A_REVERSE; break;
! 625: case 'd': attr |= A_DIM; break;
! 626: }
! 627: } else attr = A_NORMAL;
! 628: tmpch = nxttmpch;
! 629: } while (spl);
! 630:
! 631: mvaddstr(1 + i, x, tmpbuf2);
! 632: if (oattr) attroff(oattr);
! 633: if (attr) attron(attr);
! 634: x += strlen(tmpbuf2);
! 635: tmpch2++;
! 636: tmpbuf2 = tmpch2;
! 637: } else
! 638: mvaddstr (1 + i, x, tmpbuf2);
! 639: } else
! 640: mvaddstr (1 + i, x, tmpbuf2);
! 641: } while (ok);
! 642: free(tmpbuf);
! 643: }
! 644: }
! 645:
! 646: void
! 647: shm_sem_wait(struct dg_shm *shm_dg_data)
! 648: {
! 649: #ifdef USE_SHMEM
! 650: if (sem_wait(&(shm_dg_data->dg_sem)) == -1) {
! 651: debug_write("sem_wait");
! 652: graceful_exit(77);
! 653: }
! 654: #endif
! 655: }
! 656:
! 657: void
! 658: shm_sem_post(struct dg_shm *shm_dg_data)
! 659: {
! 660: #ifdef USE_SHMEM
! 661: if (sem_post(&(shm_dg_data->dg_sem)) == -1) {
! 662: debug_write("sem_post");
! 663: graceful_exit(78);
! 664: }
! 665: #endif
! 666: }
! 667:
! 668: void
! 669: shm_update(struct dg_shm *shm_dg_data, struct dg_game **games, int len)
! 670: {
! 671: #ifdef USE_SHMEM
! 672: int di, i;
! 673: struct dg_shm_game *shm_dg_game = (struct dg_shm_game *)(shm_dg_data + sizeof(struct dg_shm));
! 674:
! 675: signals_block();
! 676: shm_sem_wait(shm_dg_data);
! 677:
! 678: for (di = 0; di < shm_dg_data->max_n_games; di++)
! 679: if (shm_dg_game[di].in_use) {
! 680: int delgame = 1;
! 681: for (i = 0; i < len; i++) {
! 682: if (!strcmp(games[i]->ttyrec_fn, shm_dg_game[di].ttyrec_fn)) {
! 683: delgame = 0;
! 684: games[i]->is_in_shm = 1;
! 685: games[i]->shm_idx = di;
! 686: games[i]->nwatchers = shm_dg_game[di].nwatchers;
! 687: break;
! 688: }
! 689: }
! 690: if (delgame) {
! 691: shm_dg_game[di].in_use = 0;
! 692: if (shm_dg_data->cur_n_games > 0) shm_dg_data->cur_n_games--;
! 693: }
! 694: }
! 695:
! 696: if (shm_dg_data->cur_n_games < shm_dg_data->max_n_games) {
! 697: for (i = 0; i < len; i++)
! 698: if (!games[i]->is_in_shm) {
! 699: for (di = 0; di < shm_dg_data->max_n_games; di++)
! 700: if (!shm_dg_game[di].in_use) {
! 701: shm_dg_game[di].in_use = 1;
! 702: shm_dg_game[di].nwatchers = 0;
! 703: games[i]->nwatchers = 0;
! 704: games[i]->is_in_shm = 1;
! 705: games[i]->shm_idx = di;
! 706: shm_dg_data->cur_n_games++;
! 707: strncpy(shm_dg_game[di].ttyrec_fn, games[i]->ttyrec_fn, 150);
! 708: break;
! 709: }
! 710: }
! 711: }
! 712:
! 713: shm_sem_post(shm_dg_data);
! 714: signals_release();
! 715: #endif
! 716: }
! 717:
! 718: void
! 719: shm_mk_keys(key_t *shm_key, key_t *shm_sem_key)
! 720: {
! 721: #ifdef USE_SHMEM
! 722: if ((*shm_key = ftok(globalconfig.passwd, 'R')) == -1) {
! 723: debug_write("ftok shm_key");
! 724: graceful_exit(71);
! 725: }
! 726: if ((*shm_sem_key = ftok(globalconfig.passwd, 'S')) == -1) {
! 727: debug_write("ftok shm_sem_key");
! 728: graceful_exit(72);
! 729: }
! 730: #endif
! 731: }
! 732:
! 733: #ifdef USE_SHMEM
! 734: int
! 735: shm_free()
! 736: {
! 737: key_t shm, sem;
! 738: int shm_id;
! 739: int shm_size = sizeof(struct dg_shm) + shm_n_games * sizeof(struct dg_shm_game);
! 740: shm_mk_keys(&shm, &sem);
! 741: if ((shm_id = shmget(shm, shm_size, 0644)) != -1) {
! 742: shmctl(shm_id, IPC_RMID, NULL);
! 743: return 0;
! 744: }
! 745: return 1;
! 746: }
! 747: #endif
! 748:
! 749: void
! 750: shm_init(struct dg_shm **shm_dg_data, struct dg_shm_game **shm_dg_game)
! 751: {
! 752: #ifdef USE_SHMEM
! 753: key_t shm_key;
! 754: key_t shm_sem_key;
! 755: int shm_id;
! 756: int shm_size;
! 757: void *shm_data = NULL;
! 758: int shm_data_existed = 0;
! 759:
! 760: shm_mk_keys(&shm_key, &shm_sem_key);
! 761:
! 762: /* max. shm_n_games simultaneous games recorded in the shared memory */
! 763: shm_size = sizeof(struct dg_shm) + shm_n_games * sizeof(struct dg_shm_game);
! 764:
! 765: /* connect to (and possibly create) the segment */
! 766: if ((shm_id = shmget(shm_key, shm_size, 0644 | IPC_CREAT | IPC_EXCL)) == -1) {
! 767: /* creation failed, so it already exists. attach to it */
! 768: shm_data_existed = 1;
! 769: if ((shm_id = shmget(shm_key, shm_size, 0644)) == -1) {
! 770: debug_write("shmget");
! 771: graceful_exit(73);
! 772: }
! 773: }
! 774:
! 775: /* attach to the segment to get a pointer to it: */
! 776: shm_data = shmat(shm_id, (void *)0, 0);
! 777: if (shm_data == (char *)(-1)) {
! 778: debug_write("shmat");
! 779: graceful_exit(74);
! 780: }
! 781: if (!shm_data) {
! 782: debug_write("shm_data == null");
! 783: graceful_exit(75);
! 784: }
! 785:
! 786: (*shm_dg_data) = (struct dg_shm *)shm_data;
! 787: (*shm_dg_game) = (struct dg_shm_game *)((*shm_dg_data) + sizeof(struct dg_shm));
! 788:
! 789: if (!shm_data_existed && shm_data) {
! 790: memset(*shm_dg_game, 0, shm_n_games*sizeof(struct dg_shm_game));
! 791: (*shm_dg_data)->max_n_games = shm_n_games;
! 792: (*shm_dg_data)->cur_n_games = 0;
! 793: if (sem_init(&((*shm_dg_data)->dg_sem), 1,1) == -1) {
! 794: debug_write("sem_init");
! 795: graceful_exit(76);
! 796: }
! 797: }
! 798: #endif /* USE_SHMEM */
! 799: }
! 800:
! 801: #ifdef USE_SHMEM
! 802: void
! 803: shm_dump()
! 804: {
! 805: struct dg_shm *shm_dg_data = NULL;
! 806: struct dg_shm_game *shm_dg_game = NULL;
! 807: int di, unused = -1;
! 808: shm_init(&shm_dg_data, &shm_dg_game);
! 809: shm_sem_wait(shm_dg_data);
! 810: for (di = 0; di < shm_dg_data->max_n_games; di++) {
! 811: if (shm_dg_game[di].in_use) {
! 812: if (unused != -1) {
! 813: if (unused != di-1)
! 814: fprintf(stderr, "%i-%i:\tunused\n", unused, di-1);
! 815: else
! 816: fprintf(stderr, "%i:\tunused\n", unused);
! 817: unused = -1;
! 818: }
! 819: fprintf(stderr, "%i:\t\"%s\"\twatchers:%li\n", di, shm_dg_game[di].ttyrec_fn, shm_dg_game[di].nwatchers);
! 820: } else {
! 821: if (unused == -1) unused = di;
! 822: }
! 823: }
! 824: if (unused != -1) {
! 825: if (unused != di-1)
! 826: fprintf(stderr, "%i-%i:\tunused\n", unused, di-1);
! 827: else
! 828: fprintf(stderr, "%i:\tunused\n", unused);
! 829: unused = -1;
! 830: }
! 831: shm_sem_post(shm_dg_data);
! 832: shmdt(shm_dg_data);
! 833: }
! 834: #endif
! 835:
! 836: static
! 837: struct dg_watchcols **
! 838: globalconfig_watch_columns()
! 839: {
! 840: if (globalconfig.n_watch_columns)
! 841: return globalconfig.watch_columns;
! 842:
! 843: if (!*default_watchcols_list) {
! 844: int i;
! 845: for (i = 0; i < ARRAY_SIZE(default_watchcols); ++i)
! 846: default_watchcols_list[i] = &default_watchcols[i];
! 847: }
! 848: return default_watchcols_list;
! 849: }
! 850:
! 851: static
! 852: int
! 853: watchcol_find_index(struct dg_watchcols **watchcols,
! 854: int sortmode)
! 855: {
! 856: int i;
! 857: for (i = 0; watchcols[i]; ++i)
! 858: if (watchcols[i]->sortmode == sortmode)
! 859: return i;
! 860: return -1;
! 861: }
! 862:
! 863: static
! 864: void
! 865: sortmode_increment(struct dg_watchcols **watchcols,
! 866: dg_sortmode *sortmode,
! 867: int direction)
! 868: {
! 869: int watch_column_index = watchcol_find_index(watchcols, *sortmode);
! 870: int n_watchcols;
! 871: int wrap_count = 0;
! 872: const dg_sortmode old_sortmode = *sortmode;
! 873:
! 874: for (n_watchcols = 0; watchcols[n_watchcols]; ++n_watchcols)
! 875: ;
! 876:
! 877: if (watch_column_index == -1 || !n_watchcols)
! 878: return;
! 879:
! 880: do {
! 881: watch_column_index += direction;
! 882:
! 883: if (watch_column_index < 0) {
! 884: watch_column_index = n_watchcols - 1;
! 885: ++wrap_count;
! 886: } else if (watch_column_index >= n_watchcols) {
! 887: watch_column_index = 0;
! 888: ++wrap_count;
! 889: }
! 890:
! 891: *sortmode = watchcols[watch_column_index]->sortmode;
! 892: } while (wrap_count < 2 && !*sortmode);
! 893:
! 894: if (!*sortmode)
! 895: *sortmode = old_sortmode;
! 896: }
! 897:
! 898: char *
! 899: get_timediff(time_t ctime, long seconds)
! 900: {
! 901: static char data[32];
! 902: long secs, mins, hours;
! 903:
! 904: secs = (ctime - seconds);
! 905:
! 906: if (showplayers) {
! 907: snprintf(data, 10, "%ld", secs);
! 908: return data;
! 909: }
! 910:
! 911: hours = (secs / 3600);
! 912: secs -= (hours * 3600);
! 913: mins = (secs / 60) % 60;
! 914: secs -= (mins*60);
! 915: if (hours)
! 916: snprintf(data, 10, "%ldh %ldm", hours, mins);
! 917: else if (mins)
! 918: snprintf(data, 10, "%ldm %lds", mins, secs);
! 919: else if (secs > 4)
! 920: snprintf(data, 30, "%lds", secs);
! 921: else
! 922: snprintf(data, 10, " ");
! 923: return data;
! 924: }
! 925:
! 926: static
! 927: void
! 928: game_get_column_data(struct dg_game *game,
! 929: char selectorchar,
! 930: time_t ctime, struct dg_shm_game *shm_dg_game,
! 931: char *data, int bufsz, int *hilite,
! 932: dg_sortmode which_data)
! 933: {
! 934: *data = 0;
! 935:
! 936: switch (which_data) {
! 937: default: break;
! 938: case SORTMODE_NONE:
! 939: data[0] = selectorchar; data[1] = '\0';
! 940: break;
! 941:
! 942: case SORTMODE_USERNAME:
! 943: snprintf(data, bufsz, "%s", game->name);
! 944: break;
! 945:
! 946: case SORTMODE_GAMENUM:
! 947: snprintf(data, bufsz, "%s",
! 948: myconfig[game->gamenum]->shortname);
! 949: break;
! 950:
! 951: case SORTMODE_WINDOWSIZE:
! 952: snprintf(data, bufsz, "%3dx%3d", game->ws_col, game->ws_row);
! 953: if (showplayers)
! 954: snprintf(data, bufsz, "%dx%d", game->ws_col, game->ws_row);
! 955: else
! 956: snprintf(data, bufsz, "%3dx%3d", game->ws_col, game->ws_row);
! 957: if ((game->ws_col > COLS || game->ws_row > LINES))
! 958: *hilite = CLR_RED;
! 959: break;
! 960:
! 961: case SORTMODE_STARTTIME:
! 962: snprintf(data, bufsz, "%s %s", game->date,
! 963: game->time);
! 964: break;
! 965:
! 966: case SORTMODE_DURATION:
! 967: {
! 968: /* TODO: populate_games() should put st_ctime into game struct */
! 969: struct tm timetm;
! 970: char tmptimebuf[32];
! 971: snprintf(tmptimebuf, 30, "%s %s", game->date, game->time);
! 972: tmptimebuf[31] = '\0';
! 973: strptime(tmptimebuf, "%Y-%m-%d %H:%M:%S", &timetm);
! 974: snprintf(data, 10, "%s", get_timediff(ctime, mktime(&timetm)));
! 975: }
! 976: break;
! 977:
! 978: case SORTMODE_IDLETIME:
! 979: snprintf(data, 10, "%s", get_timediff(ctime, game->idle_time));
! 980: break;
! 981:
! 982: case SORTMODE_EXTRA_INFO:
! 983: if (game->extra_info)
! 984: strlcpy(data, game->extra_info, bufsz);
! 985: break;
! 986:
! 987: #ifdef USE_SHMEM
! 988: case SORTMODE_WATCHERS:
! 989: snprintf(data, bufsz, "%li",
! 990: (game->is_in_shm ?
! 991: shm_dg_game[game->shm_idx].nwatchers : -1));
! 992: break;
! 993: #endif
! 994: }
! 995: data[bufsz - 1] = '\0';
! 996: }
! 997:
! 998: void
! 999: inprogressmenu (int gameid)
! 1000: {
! 1001: const char *selectorchars = "abcdefghijklmnoprstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ";
! 1002: int i, menuchoice, len = 20, offset = 0;
! 1003: static dg_sortmode sortmode = NUM_SORTMODES;
! 1004: struct dg_game **games = NULL;
! 1005: char ttyrecname[130], gametype[10], idletime[10];
! 1006: sigset_t oldmask, toblock;
! 1007: int idx = -1;
! 1008: int shm_idx = -1;
! 1009: int max_height = -1;
! 1010: int selected = -1;
! 1011:
! 1012: int resizex = -1;
! 1013: int resizey = -1;
! 1014:
! 1015: char *selectedgame = NULL;
! 1016:
! 1017: int abs_max_height;
! 1018: int top_banner_hei = 5;
! 1019: int btm_banner_hei = 3;
! 1020: int btm;
! 1021:
! 1022: int title_attr = A_STANDOUT;
! 1023: int selected_attr = A_BOLD;
! 1024:
! 1025: int require_enter = 0; /* TODO: make configurable */
! 1026:
! 1027: time_t ctime;
! 1028:
! 1029: struct dg_shm *shm_dg_data = NULL;
! 1030: struct dg_shm_game *shm_dg_game = NULL;
! 1031:
! 1032: struct dg_watchcols **watchcols = globalconfig_watch_columns();
! 1033: struct dg_watchcols **curr_watchcol;
! 1034:
! 1035: if (sortmode == NUM_SORTMODES)
! 1036: sortmode = globalconfig.sortmode;
! 1037:
! 1038: abs_max_height = strlen(selectorchars);
! 1039:
! 1040: shm_init(&shm_dg_data, &shm_dg_game);
! 1041:
! 1042: games = populate_games (gameid, &len, NULL); /* FIXME: should be 'me' instead of 'NULL' */
! 1043: shm_update(shm_dg_data, games, len);
! 1044: games = sort_games (games, len, sortmode);
! 1045:
! 1046: while (1)
! 1047: {
! 1048: term_resize_check();
! 1049: max_height = dgl_local_LINES - (top_banner_hei + btm_banner_hei) - 1;
! 1050: if (max_height < 2) {
! 1051: free_populated_games(games, len);
! 1052: return;
! 1053: }
! 1054: if (max_height > abs_max_height) max_height = abs_max_height;
! 1055:
! 1056: if (len == 0)
! 1057: offset = 0;
! 1058:
! 1059: erase ();
! 1060: drawbanner (&banner);
! 1061:
! 1062: if (len > 0) {
! 1063: while (offset >= len) { offset -= max_height; }
! 1064: if (offset < 0) offset = 0;
! 1065: mvaddstr (3, 1, "The following games are in progress:");
! 1066:
! 1067: for (curr_watchcol = watchcols; *curr_watchcol; ++curr_watchcol) {
! 1068: struct dg_watchcols *wcol = *curr_watchcol;
! 1069: char *col = wcol->colname;
! 1070: int x = wcol->x;
! 1071: while (*col == ' ') { x++; col++; }
! 1072: if (sortmode == wcol->sortmode) attron(title_attr);
! 1073: mvprintw(top_banner_hei, x, col);
! 1074: if (sortmode == wcol->sortmode) attroff(title_attr);
! 1075: }
! 1076: }
! 1077:
! 1078: signals_block();
! 1079: shm_sem_wait(shm_dg_data);
! 1080:
! 1081: (void) time(&ctime);
! 1082:
! 1083: for (i = 0; i < max_height; i++)
! 1084: {
! 1085: if (i + offset >= len)
! 1086: break;
! 1087:
! 1088: if (i + offset == selected) attron(selected_attr);
! 1089:
! 1090: for (curr_watchcol = watchcols; *curr_watchcol; ++curr_watchcol) {
! 1091: struct dg_watchcols *col = *curr_watchcol;
! 1092: char tmpbuf[80];
! 1093: int hilite = 0;
! 1094: game_get_column_data(games[i + offset],
! 1095: selectorchars[i],
! 1096: ctime, shm_dg_game,
! 1097: tmpbuf, sizeof tmpbuf, &hilite,
! 1098: (dg_sortmode)col->dat);
! 1099: if (hilite) attron(hilite);
! 1100: mvprintw(top_banner_hei + 1 + i, col->x, col->fmt, tmpbuf);
! 1101: if (hilite) {
! 1102: attron(CLR_NORMAL);
! 1103: hilite = 0;
! 1104: }
! 1105: }
! 1106:
! 1107: if (i + offset == selected) attroff(selected_attr);
! 1108:
! 1109: }
! 1110:
! 1111: shm_sem_post(shm_dg_data);
! 1112: signals_release();
! 1113:
! 1114: btm = dgl_local_LINES-btm_banner_hei-top_banner_hei;
! 1115: if (len <= max_height)
! 1116: btm = i+1;
! 1117:
! 1118: if (len > 0) {
! 1119: mvprintw ((btm+top_banner_hei), 1, "(%d-%d of %d)", offset + 1, offset + i, len);
! 1120: mvaddstr ((btm+2+top_banner_hei), 1, "Watch which game? ('?' for help) => ");
! 1121: } else {
! 1122: mvprintw(top_banner_hei,4,"Sorry, no games available for viewing.");
! 1123: mvaddstr((btm+2+top_banner_hei), 1, "Press 'q' to return, or '?' for help => ");
! 1124: }
! 1125:
! 1126: refresh ();
! 1127:
! 1128: switch ((menuchoice = dgl_getch ()))
! 1129: {
! 1130: case KEY_DOWN:
! 1131: selected++;
! 1132: if (selected >= len) selected = 0;
! 1133: while (selected < offset) offset -= max_height;
! 1134: while (selected >= offset+max_height) offset += max_height;
! 1135: break;
! 1136: case KEY_UP:
! 1137: if (selected != -1) {
! 1138: if (selected == 0) selected = len;
! 1139: selected--;
! 1140: } else selected = len-1;
! 1141: while (selected < offset) offset -= max_height;
! 1142: while (selected >= offset+max_height) offset += max_height;
! 1143: break;
! 1144: case '*':
! 1145: if (len > 0) {
! 1146: int cnt = 20;
! 1147: (void) time(&ctime);
! 1148: do {
! 1149: idx = random() % len;
! 1150: } while ((--cnt > 0) ||
! 1151: !((games[idx]->ws_col <= COLS) &&
! 1152: (games[idx]->ws_row <= LINES) &&
! 1153: ((ctime - games[idx]->idle_time) < 15)));
! 1154: selected = idx;
! 1155: goto watchgame;
! 1156: }
! 1157: break;
! 1158: case '?':
! 1159: (void) runmenuloop(dgl_find_menu("watchmenu_help"));
! 1160: break;
! 1161: case '/':
! 1162: {
! 1163: int match = -1;
! 1164: int firstmatch = -1;
! 1165: int nmatches = 0;
! 1166: char findname[DGL_PLAYERNAMELEN+1];
! 1167: if (len <= 0) break;
! 1168: findname[0] = '\0';
! 1169: mvprintw ((btm+2+top_banner_hei), 1, "Watch which player? => "); /* stupid... */
! 1170: mvaddstr ((btm+2+top_banner_hei), 1, "Watch which player? => ");
! 1171: if ((mygetnstr(findname, DGL_PLAYERNAMELEN, 1) == OK) && (strlen(findname) > 1)) {
! 1172: int mlen = strlen(findname);
! 1173: for (i = 0; i < len; i++)
! 1174: if (!strncasecmp(games[i]->name, findname, mlen)) {
! 1175: if (firstmatch == -1) firstmatch = i;
! 1176: match = i;
! 1177: nmatches++;
! 1178: }
! 1179: if (nmatches > 1)
! 1180: match = firstmatch;
! 1181: if (match > -1) {
! 1182: idx = match;
! 1183: selected = idx;
! 1184: goto watchgame;
! 1185: }
! 1186: }
! 1187: }
! 1188: break;
! 1189: case KEY_NPAGE:
! 1190: case '>':
! 1191: if ((offset + max_height) < len) offset += max_height;
! 1192: break;
! 1193: case KEY_PPAGE:
! 1194: case '<':
! 1195: if ((offset - max_height) < 0)
! 1196: offset = 0;
! 1197: else
! 1198: offset -= max_height;
! 1199: break;
! 1200:
! 1201: case ERR:
! 1202: case 'q': case 'Q':
! 1203: case '\x1b':
! 1204: goto leavewatchgame;
! 1205: case KEY_RIGHT:
! 1206: case '.':
! 1207: sortmode_increment(watchcols, &sortmode, 1);
! 1208: break;
! 1209: case KEY_LEFT:
! 1210: case ',':
! 1211: sortmode_increment(watchcols, &sortmode, -1);
! 1212: break;
! 1213:
! 1214: case 12: case 18: /* ^L, ^R */
! 1215: if (globalconfig.utf8esc) (void) write(1, "\033%G", 3);
! 1216: clear ();
! 1217: break;
! 1218:
! 1219: case 13:
! 1220: case 10:
! 1221: case KEY_ENTER:
! 1222: if (selected >= 0 && selected < len) {
! 1223: idx = selected;
! 1224: goto watchgame;
! 1225: }
! 1226: break;
! 1227:
! 1228: default:
! 1229: if (strchr(selectorchars, menuchoice) && (len > 0)) {
! 1230: int sidx = strchr(selectorchars, menuchoice) - selectorchars;
! 1231:
! 1232: if ((sidx > max_height) || (sidx >= len)) {
! 1233: selected = -1;
! 1234: break;
! 1235: }
! 1236:
! 1237: idx = sidx + offset;
! 1238: if (require_enter) {
! 1239: if (selected == idx) selected = -1;
! 1240: else selected = idx;
! 1241: break;
! 1242: } else selected = idx;
! 1243: watchgame:
! 1244: if (!(idx >= 0 && idx < len && games[idx] && games[idx]->name))
! 1245: goto leavewatchgame;
! 1246: /* valid choice has been made */
! 1247: chosen_name = strdup (games[idx]->name);
! 1248: snprintf (ttyrecname, 130, "%s",
! 1249: games[idx]->ttyrec_fn);
! 1250:
! 1251: clear ();
! 1252: refresh ();
! 1253: endwin ();
! 1254: if (globalconfig.utf8esc) (void) write(1, "\033%G", 3);
! 1255: #ifdef USE_SHMEM
! 1256: signals_block();
! 1257: if (games[idx]->is_in_shm) {
! 1258: shm_idx = games[idx]->shm_idx;
! 1259: shm_sem_wait(shm_dg_data);
! 1260: if (shm_dg_game[shm_idx].in_use &&
! 1261: !strcmp(shm_dg_game[shm_idx].ttyrec_fn, games[idx]->ttyrec_fn)) {
! 1262: shm_dg_game[shm_idx].nwatchers++;
! 1263: games[idx]->nwatchers++;
! 1264: }
! 1265: hup_shm_idx = shm_idx;
! 1266: hup_shm_ttyrec_fn = strdup(games[idx]->ttyrec_fn);
! 1267: shm_sem_post(shm_dg_data);
! 1268: }
! 1269: signals_release();
! 1270: #endif
! 1271: resizey = games[idx]->ws_row;
! 1272: resizex = games[idx]->ws_col;
! 1273: if (loggedin)
! 1274: setproctitle("%s [watching %s]", me->username, chosen_name);
! 1275: else
! 1276: setproctitle("<Anonymous> [watching %s]", chosen_name);
! 1277: ttyplay_main (ttyrecname, 1, resizex, resizey);
! 1278: if (loggedin)
! 1279: setproctitle("%s", me->username);
! 1280: else
! 1281: setproctitle("<Anonymous>");
! 1282: #ifdef USE_SHMEM
! 1283: signals_block();
! 1284: if (games[idx]->is_in_shm) {
! 1285: hup_shm_idx = -1;
! 1286: free(hup_shm_ttyrec_fn);
! 1287: shm_sem_wait(shm_dg_data);
! 1288: if (shm_dg_game[shm_idx].in_use &&
! 1289: !strcmp(shm_dg_game[shm_idx].ttyrec_fn, games[idx]->ttyrec_fn) &&
! 1290: (shm_dg_game[shm_idx].nwatchers > 0)) {
! 1291: shm_dg_game[shm_idx].nwatchers--;
! 1292: games[idx]->nwatchers--;
! 1293: }
! 1294: shm_sem_post(shm_dg_data);
! 1295: }
! 1296: signals_release();
! 1297: #endif
! 1298: initcurses ();
! 1299: redrawwin(stdscr);
! 1300: }
! 1301: }
! 1302:
! 1303: if (selected >= 0 && selected < len)
! 1304: selectedgame = strdup(games[selected]->name);
! 1305: games = populate_games (gameid, &len, NULL); /* FIXME: should be 'me' instead of 'NULL' */
! 1306: shm_update(shm_dg_data, games, len);
! 1307: games = sort_games (games, len, sortmode);
! 1308: if (selectedgame) {
! 1309: selected = -1;
! 1310: for (i = 0; i < len; i++)
! 1311: if (!strcmp(games[i]->name, selectedgame)) {
! 1312: selected = i;
! 1313: break;
! 1314: }
! 1315: free(selectedgame);
! 1316: selectedgame = NULL;
! 1317: }
! 1318: }
! 1319: leavewatchgame:
! 1320: free_populated_games(games, len);
! 1321: #ifdef USE_SHMEM
! 1322: shmdt(shm_dg_data);
! 1323: #endif
! 1324: }
! 1325:
! 1326: void
! 1327: inprogressdisplay (int gameid)
! 1328: {
! 1329: const char *selectorchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ";
! 1330: int i, len = 20;
! 1331: static dg_sortmode sortmode = NUM_SORTMODES;
! 1332: struct dg_game **games = NULL;
! 1333: int shm_idx = -1;
! 1334:
! 1335: time_t ctime;
! 1336:
! 1337: struct dg_shm *shm_dg_data = NULL;
! 1338: struct dg_shm_game *shm_dg_game = NULL;
! 1339:
! 1340: struct dg_watchcols **watchcols = globalconfig_watch_columns();
! 1341: struct dg_watchcols **curr_watchcol;
! 1342:
! 1343: if (sortmode == NUM_SORTMODES)
! 1344: sortmode = globalconfig.sortmode;
! 1345:
! 1346: shm_init(&shm_dg_data, &shm_dg_game);
! 1347:
! 1348: games = populate_games (gameid, &len, NULL); /* FIXME: should be 'me' instead of 'NULL' */
! 1349: shm_update(shm_dg_data, games, len);
! 1350: games = sort_games (games, len, sortmode);
! 1351:
! 1352: signals_block();
! 1353: shm_sem_wait(shm_dg_data);
! 1354:
! 1355: (void) time(&ctime);
! 1356:
! 1357: for (i = 0; i < 100; i++) {
! 1358: if (i >= len)
! 1359: break;
! 1360:
! 1361: for (curr_watchcol = watchcols; *curr_watchcol; ++curr_watchcol) {
! 1362: struct dg_watchcols *col = *curr_watchcol;
! 1363: if ((dg_sortmode)col->dat == SORTMODE_NONE)
! 1364: continue;
! 1365: char tmpbuf[80];
! 1366: int hilite = 0;
! 1367: game_get_column_data(games[i],
! 1368: selectorchars[i],
! 1369: ctime, shm_dg_game,
! 1370: tmpbuf, sizeof tmpbuf, &hilite, (dg_sortmode)col->dat);
! 1371: fprintf(stdout, "%s#", tmpbuf); /* format in col->fmt */
! 1372: }
! 1373: fprintf(stdout, "\n");
! 1374: }
! 1375:
! 1376: shm_sem_post(shm_dg_data);
! 1377: signals_release();
! 1378:
! 1379: free_populated_games(games, len);
! 1380:
! 1381: #ifdef USE_SHMEM
! 1382: shmdt(shm_dg_data);
! 1383: #endif
! 1384: }
! 1385:
! 1386: /* ************************************************************* */
! 1387:
! 1388: /*
! 1389: * Check email address, returns 1 if valid, 0 otherwise.
! 1390: * Doesn't recognize addresses with parts in double-quotes.
! 1391: * Addresses with a colon in them are always rejected.
! 1392: */
! 1393: int
! 1394: check_email (char *s)
! 1395: {
! 1396: char *atomchars = "!#$%&'*+-/=?^_`{|}~" "0123456789"
! 1397: "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
! 1398: int f;
! 1399:
! 1400: if (*s == '@')
! 1401: return 0;
! 1402:
! 1403: while (*s != '\0' && *s != '@')
! 1404: {
! 1405: if (strchr(atomchars, *s) == NULL)
! 1406: return 0;
! 1407: s++;
! 1408: if (*s == '.')
! 1409: s++;
! 1410: }
! 1411:
! 1412: if (*s == '\0')
! 1413: return 0;
! 1414: s++;
! 1415:
! 1416: f = 0;
! 1417: while (*s != '\0')
! 1418: {
! 1419: if (strchr(atomchars, *s) == NULL)
! 1420: return 0;
! 1421: s++;
! 1422: if (*s == '.')
! 1423: s++, f = 1;
! 1424: }
! 1425:
! 1426: return f;
! 1427: }
! 1428:
! 1429: void
! 1430: change_email ()
! 1431: {
! 1432: char buf[81];
! 1433:
! 1434: clear();
! 1435:
! 1436: if (me->flags & DGLACCT_EMAIL_LOCK) {
! 1437: drawbanner(&banner);
! 1438: mvprintw(5, 1, "Sorry, you cannot change the email.--More--");
! 1439: dgl_getch();
! 1440: return;
! 1441: }
! 1442:
! 1443: for (;;)
! 1444: {
! 1445: drawbanner(&banner);
! 1446:
! 1447: mvprintw(3, 1, "Your current email is: %s", me->email);
! 1448: mvaddstr(4, 1, "Please enter a new one (max 80 chars; blank line aborts)");
! 1449: mvaddstr(6, 1, "=> ");
! 1450:
! 1451: if (mygetnstr (buf, 80, 1) != OK)
! 1452: return;
! 1453:
! 1454: if (*buf == '\0')
! 1455: return;
! 1456: else if (!strcmp(me->email, buf))
! 1457: {
! 1458: clear();
! 1459: mvaddstr (8, 1, "That's the same one as before. Try again?");
! 1460: move(1,1);
! 1461: }
! 1462: else if (check_email (buf))
! 1463: {
! 1464: mvprintw (8, 1, "Changing email address to '%s'. Confirm (y/n): ", buf);
! 1465: if (dgl_getch() == 'y')
! 1466: {
! 1467: free(me->email);
! 1468: me->email = strdup(buf);
! 1469: writefile(0);
! 1470: return;
! 1471: }
! 1472: else
! 1473: {
! 1474: mvaddstr(9, 1, "No changes made. Press any key to continue...");
! 1475: dgl_getch();
! 1476: return;
! 1477: }
! 1478: }
! 1479: else
! 1480: {
! 1481: clear();
! 1482: mvaddstr (8, 1, "That doesn't look like an email address to me.");
! 1483: move(1,1);
! 1484: }
! 1485: }
! 1486: }
! 1487:
! 1488: int
! 1489: changepw (int dowrite)
! 1490: {
! 1491: char buf[DGL_PASSWDLEN+1];
! 1492: int error = 2;
! 1493:
! 1494: /* A precondition is that struct `me' exists because we can be not-yet-logged-in. */
! 1495: if (!me) {
! 1496: debug_write("no 'me' in changepw");
! 1497: graceful_exit (122); /* Die. */
! 1498: }
! 1499:
! 1500: if (me->flags & DGLACCT_PASSWD_LOCK) {
! 1501: clear();
! 1502: drawbanner(&banner);
! 1503: mvprintw(5, 1, "Sorry, you cannot change the password.--More--");
! 1504: dgl_getch();
! 1505: return 0;
! 1506: }
! 1507:
! 1508: while (error)
! 1509: {
! 1510: char repeatbuf[DGL_PASSWDLEN+1];
! 1511: clear ();
! 1512:
! 1513: drawbanner (&banner);
! 1514:
! 1515: mvprintw (5, 1,
! 1516: "Please enter a%s password. Remember that this is sent over the net",
! 1517: loggedin ? " new" : "");
! 1518: mvaddstr (6, 1,
! 1519: "in plaintext, so make it something new and expect it to be relatively");
! 1520: mvaddstr (7, 1, "insecure.");
! 1521: mvprintw (8, 1,
! 1522: "%i character max. No ':' characters. Blank line to abort.", DGL_PASSWDLEN);
! 1523: mvaddstr (10, 1, "=> ");
! 1524:
! 1525: if (error == 1)
! 1526: {
! 1527: mvaddstr (15, 1, "Sorry, the passwords don't match. Try again.");
! 1528: move (10, 4);
! 1529: }
! 1530:
! 1531: refresh ();
! 1532:
! 1533: if (mygetnstr (buf, DGL_PASSWDLEN, 0) != OK)
! 1534: return 0;
! 1535:
! 1536: if (*buf == '\0')
! 1537: return 0;
! 1538:
! 1539: if (strchr (buf, ':') != NULL) {
! 1540: debug_write("cannot have ':' in passwd");
! 1541: graceful_exit (112);
! 1542: }
! 1543:
! 1544: mvaddstr (12, 1, "And again:");
! 1545: mvaddstr (13, 1, "=> ");
! 1546:
! 1547: if (mygetnstr (repeatbuf, DGL_PASSWDLEN, 0) != OK)
! 1548: return 0;
! 1549:
! 1550: if (!strcmp (buf, repeatbuf))
! 1551: error = 0;
! 1552: else
! 1553: error = 1;
! 1554: }
! 1555:
! 1556: free(me->password);
! 1557: me->password = strdup (crypt (buf, buf));
! 1558:
! 1559: if (dowrite)
! 1560: writefile (0);
! 1561:
! 1562: return 1;
! 1563: }
! 1564:
! 1565: /* ************************************************************* */
! 1566:
! 1567: void
! 1568: wall_email(char *from, char *msg)
! 1569: {
! 1570: int len, i;
! 1571: struct dg_game **games = NULL;
! 1572: char spool_fn[1024+1];
! 1573: FILE *user_spool = NULL;
! 1574: struct flock fl = { 0 };
! 1575:
! 1576: fl.l_type = F_WRLCK;
! 1577: fl.l_whence = SEEK_SET;
! 1578: fl.l_start = 0;
! 1579: fl.l_len = 0;
! 1580:
! 1581: if (!from || !msg) return;
! 1582:
! 1583: if (strlen(from) < 1) {
! 1584: fprintf(stderr, "Error: wall: 'from' username is too short!\n");
! 1585: debug_write("wall: 'from' username too short");
! 1586: graceful_exit(121);
! 1587: }
! 1588:
! 1589: if (strlen(msg) >= DGL_MAILMSGLEN) {
! 1590: fprintf(stderr, "Error: wall: message too long!\n");
! 1591: debug_write("wall: message too long");
! 1592: graceful_exit(120);
! 1593: }
! 1594:
! 1595: games = populate_games(-1, &len, me);
! 1596:
! 1597: if (len == 0) {
! 1598: fprintf(stderr, "Error: wall: no one's logged in!\n");
! 1599: debug_write("wall: no people playing");
! 1600: graceful_exit(118);
! 1601: }
! 1602:
! 1603: for (i = 0; i < len; i++) {
! 1604: int game = games[i]->gamenum;
! 1605: int fnamelen;
! 1606: if (strlen(myconfig[game]->spool) < 1) continue;
! 1607:
! 1608: snprintf (spool_fn, 1024, "%s/%s", myconfig[game]->spool, games[i]->name);
! 1609:
! 1610: if ((user_spool = fopen (spool_fn, "a")) == NULL) continue;
! 1611:
! 1612: while (fcntl(fileno(user_spool), F_SETLK, &fl) == -1) {
! 1613: if (errno != EAGAIN) continue;
! 1614: sleep (1);
! 1615: }
! 1616: fprintf(user_spool, "%s:%s\n", from, msg);
! 1617: fclose(user_spool);
! 1618: }
! 1619: free_populated_games(games, len);
! 1620: }
! 1621:
! 1622: void
! 1623: domailuser (char *username)
! 1624: {
! 1625: unsigned int len, i;
! 1626: char *spool_fn, message[DGL_MAILMSGLEN+1];
! 1627: FILE *user_spool = NULL;
! 1628: time_t now;
! 1629: int mail_empty = 1;
! 1630: int game;
! 1631: struct flock fl = { 0 };
! 1632:
! 1633: fl.l_type = F_WRLCK;
! 1634: fl.l_whence = SEEK_SET;
! 1635: fl.l_start = 0;
! 1636: fl.l_len = 0;
! 1637:
! 1638: assert (loggedin);
! 1639:
! 1640: game = 0; /*TODO: find_curr_player_game(username) */
! 1641:
! 1642: if (strlen(myconfig[game]->spool) < 1) return;
! 1643:
! 1644: len = strlen(myconfig[game]->spool) + strlen (username) + 1;
! 1645: spool_fn = malloc (len + 1);
! 1646: time (&now);
! 1647: snprintf (spool_fn, len + 1, "%s/%s", myconfig[game]->spool, username);
! 1648:
! 1649: /* print the enter your message line */
! 1650: clear ();
! 1651: drawbanner (&banner);
! 1652: mvprintw (5, 1,
! 1653: "Enter your message here. It is to be one line only and %i characters or less.",
! 1654: DGL_MAILMSGLEN);
! 1655: mvaddstr (7, 1, "=> ");
! 1656:
! 1657: if (mygetnstr (message, DGL_MAILMSGLEN, 1) != OK)
! 1658: return;
! 1659:
! 1660: for (i = 0; i < strlen (message); i++)
! 1661: {
! 1662: if (message[i] != ' ' && message[i] != '\n' && message[i] != '\t')
! 1663: mail_empty = 0;
! 1664: }
! 1665:
! 1666: if (mail_empty)
! 1667: {
! 1668: mvaddstr (9, 1, "This scroll appears to be blank.");
! 1669: mvaddstr (10, 1, "(Aborting your message.)");
! 1670: mvaddstr (12, 1, "--More--");
! 1671: dgl_getch ();
! 1672: return;
! 1673: }
! 1674:
! 1675: if ((user_spool = fopen (spool_fn, "a")) == NULL)
! 1676: {
! 1677: mvaddstr (9, 1,
! 1678: "You fall into the water! You sink like a rock.");
! 1679: mvprintw (10, 1,
! 1680: "(Couldn't open %s'%c spool file. Aborting.)",
! 1681: username, (username[strlen (username) - 1] != 's') ? 's' : 0);
! 1682: mvaddstr (12, 1, "--More--");
! 1683: dgl_getch ();
! 1684: return;
! 1685: }
! 1686:
! 1687: mvaddstr (9, 1, "Sending your scroll...");
! 1688: refresh ();
! 1689:
! 1690: /* Getting a lock on the mailspool... */
! 1691: while (fcntl (fileno (user_spool), F_SETLK, &fl) == -1)
! 1692: {
! 1693: if (errno != EAGAIN)
! 1694: {
! 1695: mvaddstr (10, 1,
! 1696: "(Received a weird error from fcntl. Aborting.)");
! 1697: mvaddstr (12, 1, "--More--");
! 1698: dgl_getch ();
! 1699: return;
! 1700: }
! 1701: sleep (1);
! 1702: }
! 1703:
! 1704: fprintf (user_spool, "%s:%s\n", me->username, message);
! 1705:
! 1706: /*
! 1707: * Don't unlock the file ourselves, this way it will be done automatically
! 1708: * after all data has been written. (Using file locking with stdio is icky.)
! 1709: */
! 1710:
! 1711: fclose (user_spool);
! 1712:
! 1713: mvaddstr (9, 1, "Scroll delivered! ");
! 1714: move(9, 19); /* Pedantry! */
! 1715: refresh ();
! 1716: sleep (2);
! 1717:
! 1718: return;
! 1719: }
! 1720:
! 1721:
! 1722: /* ************************************************************* */
! 1723:
! 1724: void
! 1725: freefile ()
! 1726: {
! 1727: #ifndef USE_SQLITE3
! 1728: int i;
! 1729:
! 1730: /* free existing mem, clear existing entries */
! 1731: for (i = 0; i < f_num; i++)
! 1732: {
! 1733: if (users[i] != me)
! 1734: {
! 1735: free (users[i]->password);
! 1736: free (users[i]->username);
! 1737: free (users[i]->email);
! 1738: free (users[i]->env);
! 1739: free (users[i]);
! 1740: }
! 1741: }
! 1742:
! 1743: if (users)
! 1744: free (users);
! 1745:
! 1746: users = NULL;
! 1747: f_num = 0;
! 1748: #endif
! 1749: }
! 1750:
! 1751: /* ************************************************************* */
! 1752:
! 1753: void
! 1754: initcurses ()
! 1755: {
! 1756: printf("\033[2J");
! 1757: if (newterm(NULL, stdout, stdin) == NULL) {
! 1758: if (!globalconfig.defterm || (newterm(globalconfig.defterm, stdout, stdin) == NULL)) {
! 1759: debug_write("cannot create newterm");
! 1760: graceful_exit(60);
! 1761: }
! 1762: mysetenv("TERM", globalconfig.defterm, 1);
! 1763: }
! 1764: cbreak ();
! 1765: noecho ();
! 1766: nonl ();
! 1767: intrflush (stdscr, FALSE);
! 1768: keypad (stdscr, TRUE);
! 1769: #ifdef USE_NCURSES_COLOR
! 1770: start_color();
! 1771: use_default_colors();
! 1772:
! 1773: init_pair(COLOR_BLACK, COLOR_WHITE, COLOR_BLACK);
! 1774: init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
! 1775: init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
! 1776: init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
! 1777: init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
! 1778: init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
! 1779: init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
! 1780: init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
! 1781: init_pair(9, 0, COLOR_BLACK);
! 1782: init_pair(10, COLOR_BLACK, COLOR_BLACK);
! 1783: init_pair(11, -1, -1);
! 1784:
! 1785: if (globalconfig.utf8esc) (void) write(1, "\033%G", 3);
! 1786: #endif
! 1787: clear();
! 1788: refresh();
! 1789: }
! 1790:
! 1791: /* ************************************************************* */
! 1792:
! 1793: void
! 1794: autologin (char* user, char *pass)
! 1795: {
! 1796: struct dg_user *tmp;
! 1797: tmp = userexist(user, 0);
! 1798: if (tmp) {
! 1799: me = cpy_me(tmp);
! 1800: if ((passwordgood(pass) || initplayer == 1) && !(me->flags & DGLACCT_LOGIN_LOCK)) {
! 1801: loggedin = 1;
! 1802: setproctitle ("%s", me->username);
! 1803: dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_LOGIN], 0, me);
! 1804: }
! 1805: }
! 1806: }
! 1807:
! 1808: void
! 1809: loginprompt (int from_ttyplay)
! 1810: {
! 1811: char user_buf[DGL_PLAYERNAMELEN+1], pw_buf[DGL_PASSWDLEN+2];
! 1812: int error = 2;
! 1813:
! 1814: loggedin = 0;
! 1815:
! 1816: while (error)
! 1817: {
! 1818: clear ();
! 1819:
! 1820: drawbanner (&banner);
! 1821:
! 1822: if (from_ttyplay == 1)
! 1823: mvaddstr (4, 1, "This operation requires you to be logged in.");
! 1824:
! 1825: mvaddstr (5, 1,
! 1826: "Please enter your username. (blank entry aborts)");
! 1827: mvaddstr (7, 1, "=> ");
! 1828:
! 1829: if (error == 1)
! 1830: {
! 1831: mvaddstr (9, 1, "There was a problem with your last entry.");
! 1832: move (7, 4);
! 1833: }
! 1834:
! 1835: refresh ();
! 1836:
! 1837: if (mygetnstr (user_buf, DGL_PLAYERNAMELEN, 1) != OK)
! 1838: return;
! 1839:
! 1840: if (*user_buf == '\0')
! 1841: return;
! 1842:
! 1843: error = 1;
! 1844:
! 1845: {
! 1846: struct dg_user *tmpme;
! 1847: if ((tmpme = userexist(user_buf, 0))) {
! 1848: me = cpy_me(tmpme);
! 1849: error = 0;
! 1850: }
! 1851: }
! 1852: }
! 1853:
! 1854: clear ();
! 1855:
! 1856: drawbanner (&banner);
! 1857:
! 1858: mvaddstr (5, 1, "Please enter your password.");
! 1859: mvaddstr (7, 1, "=> ");
! 1860:
! 1861: refresh ();
! 1862:
! 1863: if (mygetnstr (pw_buf, DGL_PASSWDLEN, 0) != OK)
! 1864: return;
! 1865:
! 1866: if (passwordgood (pw_buf))
! 1867: {
! 1868: if (me->flags & DGLACCT_LOGIN_LOCK) {
! 1869: clear ();
! 1870: mvprintw(5, 1, "Sorry, that account has been banned.--More--");
! 1871: dgl_getch();
! 1872: return;
! 1873: }
! 1874:
! 1875: loggedin = 1;
! 1876: if (from_ttyplay)
! 1877: setproctitle("%s [watching %s]", me->username, chosen_name);
! 1878: else
! 1879: setproctitle("%s", me->username);
! 1880: dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_LOGIN], 0, me);
! 1881: }
! 1882: else
! 1883: {
! 1884: me = NULL;
! 1885: if (from_ttyplay == 1)
! 1886: {
! 1887: mvaddstr(9, 1, "Login failed. Returning to game.");
! 1888: refresh();
! 1889: sleep(2);
! 1890: }
! 1891: }
! 1892: }
! 1893:
! 1894: /* ************************************************************* */
! 1895:
! 1896: void
! 1897: newuser ()
! 1898: {
! 1899: char buf[1024], dirname[100];
! 1900: int error = 2;
! 1901: unsigned int i;
! 1902:
! 1903: loggedin = 0;
! 1904:
! 1905: #ifndef USE_SQLITE3
! 1906: if (f_num >= globalconfig.max)
! 1907: {
! 1908: clear ();
! 1909:
! 1910: drawbanner (&banner);
! 1911:
! 1912: mvaddstr (5, 1, "Sorry, too many users have registered now.");
! 1913: mvaddstr (6, 1, "You might email the server administrator.");
! 1914: mvaddstr (7, 1, "Press return to return to the menu. ");
! 1915: dgl_getch ();
! 1916:
! 1917: return;
! 1918: }
! 1919: #endif
! 1920:
! 1921: if (me)
! 1922: free (me);
! 1923:
! 1924: me = calloc (1, sizeof (struct dg_user));
! 1925:
! 1926: while (error)
! 1927: {
! 1928: clear ();
! 1929:
! 1930: sprintf(buf, "%i character max.", globalconfig.max_newnick_len);
! 1931:
! 1932: drawbanner (&banner);
! 1933:
! 1934: mvaddstr (5, 1, "Welcome new user. Please enter a username.");
! 1935: mvaddstr (6, 1,
! 1936: "Only characters and numbers are allowed, with no spaces.");
! 1937: mvaddstr (7, 1, buf);
! 1938: mvaddstr (9, 1, "=> ");
! 1939:
! 1940: if (error == 1)
! 1941: {
! 1942: mvaddstr (11, 1, "There was a problem with your last entry.");
! 1943: move (9, 4);
! 1944: }
! 1945:
! 1946: refresh ();
! 1947:
! 1948: if (mygetnstr (buf, globalconfig.max_newnick_len, 1) != OK)
! 1949: buf[0] = 0;
! 1950:
! 1951: if (*buf == '\0') {
! 1952: free(me);
! 1953: me = NULL;
! 1954: return;
! 1955: }
! 1956:
! 1957: if (!userexist(buf, 1)) {
! 1958: error = 0;
! 1959: } else
! 1960: error = 1;
! 1961:
! 1962: for (i = 0; i < strlen (buf); i++)
! 1963: {
! 1964: if (!isalnum((int)buf[i]))
! 1965: error = 1;
! 1966: }
! 1967:
! 1968: if (strlen (buf) < 2)
! 1969: error = 1;
! 1970:
! 1971: if (strlen (buf) == 0)
! 1972: {
! 1973: free(me);
! 1974: me = NULL;
! 1975: return;
! 1976: }
! 1977: }
! 1978:
! 1979: me->username = strdup (buf);
! 1980:
! 1981: /* password step */
! 1982:
! 1983: clear ();
! 1984:
! 1985: if (!changepw (0)) /* Calling changepw instead to prompt twice. */
! 1986: {
! 1987: free(me->username);
! 1988: free(me);
! 1989: me = NULL;
! 1990: return;
! 1991: }
! 1992:
! 1993: /* email step */
! 1994:
! 1995: error = 2;
! 1996: while (error != 0)
! 1997: {
! 1998: clear ();
! 1999:
! 2000: drawbanner (&banner);
! 2001:
! 2002: mvaddstr (5, 1, "Please enter your email address.");
! 2003: mvaddstr (6, 1, "This is sent _nowhere_ but will be used if you ask"
! 2004: " the sysadmin for lost");
! 2005: mvaddstr (7, 1, "password help. Please use a correct one. It only"
! 2006: " benefits you.");
! 2007: mvaddstr (8, 1, "80 character max. No ':' characters. Blank line"
! 2008: " aborts.");
! 2009: mvaddstr (10, 1, "=> ");
! 2010:
! 2011: if (error == 1)
! 2012: {
! 2013: mvaddstr (12, 1, "There was a problem with your last entry.");
! 2014: move (10, 4);
! 2015: }
! 2016:
! 2017: refresh ();
! 2018: if (mygetnstr (buf, 80, 1) != OK)
! 2019: buf[0] = 0;
! 2020:
! 2021: if (check_email (buf))
! 2022: error = 0;
! 2023: else
! 2024: error = 1;
! 2025:
! 2026: if (*buf == '\0')
! 2027: {
! 2028: free (me->username);
! 2029: free (me->password);
! 2030: free (me);
! 2031: me = NULL;
! 2032: return;
! 2033: }
! 2034: }
! 2035:
! 2036: me->email = strdup (buf);
! 2037: me->env = calloc (1, 1);
! 2038: me->flags = 0;
! 2039:
! 2040: loggedin = 1;
! 2041:
! 2042: setproctitle ("%s", me->username);
! 2043:
! 2044: dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_REGISTER], 0, me);
! 2045:
! 2046: writefile (1);
! 2047: }
! 2048:
! 2049: /* ************************************************************* */
! 2050:
! 2051: int
! 2052: passwordgood (char *cpw)
! 2053: {
! 2054: char *crypted;
! 2055: assert (me != NULL);
! 2056:
! 2057: crypted = crypt (cpw, cpw);
! 2058: if (crypted == NULL)
! 2059: return 0;
! 2060: if (!strncmp (crypted, me->password, DGL_PASSWDLEN))
! 2061: return 1;
! 2062: if (!strncmp (cpw, me->password, DGL_PASSWDLEN))
! 2063: return 1;
! 2064:
! 2065: return 0;
! 2066: }
! 2067:
! 2068: /* ************************************************************* */
! 2069:
! 2070: int
! 2071: readfile (int nolock)
! 2072: {
! 2073: #ifndef USE_SQLITE3
! 2074: FILE *fp = NULL, *fpl = NULL;
! 2075: char buf[1200];
! 2076: struct flock fl = { 0 };
! 2077:
! 2078: fl.l_type = F_RDLCK;
! 2079: fl.l_whence = SEEK_SET;
! 2080: fl.l_start = 0;
! 2081: fl.l_len = 0;
! 2082:
! 2083: memset (buf, 0, 1024);
! 2084:
! 2085: /* read new stuff */
! 2086:
! 2087: if (!nolock)
! 2088: {
! 2089: fpl = fopen (globalconfig.lockfile, "r");
! 2090: if (!fpl) {
! 2091: debug_write("cannot fopen lockfile");
! 2092: graceful_exit (106);
! 2093: }
! 2094: if (fcntl (fileno (fpl), F_SETLKW, &fl) == -1) {
! 2095: debug_write("cannot fcntl lockfile");
! 2096: graceful_exit (95);
! 2097: }
! 2098: }
! 2099:
! 2100: fp = fopen (globalconfig.passwd, "r");
! 2101: if (!fp) {
! 2102: debug_write("cannot fopen passwd file");
! 2103: graceful_exit (106);
! 2104: }
! 2105:
! 2106: /* once per name in the file */
! 2107: while (fgets (buf, 1200, fp))
! 2108: {
! 2109: char *b = buf, *n = buf;
! 2110:
! 2111: users = realloc (users, sizeof (struct dg_user *) * (f_num + 1));
! 2112: users[f_num] = malloc (sizeof (struct dg_user));
! 2113: users[f_num]->username = (char *) calloc (DGL_PLAYERNAMELEN+2, sizeof (char));
! 2114: users[f_num]->email = (char *) calloc (82, sizeof (char));
! 2115: users[f_num]->password = (char *) calloc (DGL_PASSWDLEN+2, sizeof (char));
! 2116: users[f_num]->env = (char *) calloc (1026, sizeof (char));
! 2117:
! 2118: /* name field, must be valid */
! 2119: while (*b != ':')
! 2120: {
! 2121: if (!isalnum((int)*b))
! 2122: return 1;
! 2123: users[f_num]->username[(b - n)] = *b;
! 2124: b++;
! 2125: if ((b - n) >= DGL_PLAYERNAMELEN) {
! 2126: debug_write("name field too long");
! 2127: graceful_exit (100);
! 2128: }
! 2129: }
! 2130:
! 2131: /* advance to next field */
! 2132: n = b + 1;
! 2133: b = n;
! 2134:
! 2135: /* email field */
! 2136: while (*b != ':')
! 2137: {
! 2138: users[f_num]->email[(b - n)] = *b;
! 2139: b++;
! 2140: if ((b - n) > 80) {
! 2141: debug_write("email field too long");
! 2142: graceful_exit (101);
! 2143: }
! 2144: }
! 2145:
! 2146: /* advance to next field */
! 2147: n = b + 1;
! 2148: b = n;
! 2149:
! 2150: /* pw field */
! 2151: while (*b != ':')
! 2152: {
! 2153: users[f_num]->password[(b - n)] = *b;
! 2154: b++;
! 2155: if ((b - n) >= DGL_PASSWDLEN) {
! 2156: debug_write("passwd field too long");
! 2157: graceful_exit (102);
! 2158: }
! 2159: }
! 2160:
! 2161: /* advance to next field */
! 2162: n = b + 1;
! 2163: b = n;
! 2164:
! 2165: /* env field */
! 2166: while ((*b != '\n') && (*b != 0) && (*b != EOF))
! 2167: {
! 2168: users[f_num]->env[(b - n)] = *b;
! 2169: b++;
! 2170: if ((b - n) >= 1024) {
! 2171: debug_write("env field too long");
! 2172: graceful_exit (103);
! 2173: }
! 2174: }
! 2175:
! 2176: f_num++;
! 2177: /* prevent a buffer overrun here */
! 2178: if (f_num > globalconfig.max)
! 2179: {
! 2180: fprintf(stderr,"ERROR: number of users in database exceeds maximum. Exiting.\n");
! 2181: debug_write("too many users in database");
! 2182: graceful_exit (109);
! 2183: }
! 2184: }
! 2185:
! 2186: if (!nolock)
! 2187: fclose (fpl);
! 2188: fclose (fp);
! 2189: #endif
! 2190: return 0;
! 2191: }
! 2192:
! 2193: /* ************************************************************* */
! 2194:
! 2195: #ifndef USE_SQLITE3
! 2196: struct dg_user *userexist_tmp_me = NULL;
! 2197:
! 2198: struct dg_user *
! 2199: userexist (char *cname, int isnew)
! 2200: {
! 2201: int i;
! 2202:
! 2203: if (userexist_tmp_me) {
! 2204: free(userexist_tmp_me->username);
! 2205: free(userexist_tmp_me->email);
! 2206: free(userexist_tmp_me->env);
! 2207: free(userexist_tmp_me->password);
! 2208: free(userexist_tmp_me);
! 2209: userexist_tmp_me = NULL;
! 2210: }
! 2211:
! 2212: for (i = 0; i < f_num; i++)
! 2213: {
! 2214: if (!strncasecmp (cname, users[i]->username, (isnew ? globalconfig.max_newnick_len : DGL_PLAYERNAMELEN))) {
! 2215: userexist_tmp_me = cpy_me(users[i]);
! 2216: return userexist_tmp_me;
! 2217: }
! 2218: }
! 2219:
! 2220: return NULL;
! 2221: }
! 2222: #else
! 2223:
! 2224: struct dg_user *userexist_tmp_me = NULL;
! 2225:
! 2226: static int
! 2227: userexist_callback(void *NotUsed, int argc, char **argv, char **colname)
! 2228: {
! 2229: int i;
! 2230: NotUsed = NULL;
! 2231:
! 2232: userexist_tmp_me = malloc(sizeof(struct dg_user));
! 2233:
! 2234: for (i = 0; i < argc; i++) {
! 2235: if (!strcmp(colname[i], "username"))
! 2236: userexist_tmp_me->username = strdup(argv[i]);
! 2237: else if (!strcmp(colname[i], "email"))
! 2238: userexist_tmp_me->email = strdup(argv[i]);
! 2239: else if (!strcmp(colname[i], "env"))
! 2240: userexist_tmp_me->env = strdup(argv[i]);
! 2241: else if (!strcmp(colname[i], "password"))
! 2242: userexist_tmp_me->password = strdup(argv[i]);
! 2243: else if (!strcmp(colname[i], "flags"))
! 2244: userexist_tmp_me->flags = atoi(argv[i]);
! 2245: else if (!strcmp(colname[i], "id"))
! 2246: userexist_tmp_me->id = atoi(argv[i]);
! 2247: }
! 2248: return 0;
! 2249: }
! 2250:
! 2251: struct dg_user *
! 2252: userexist (char *cname, int isnew)
! 2253: {
! 2254: sqlite3 *db;
! 2255: char *errmsg = NULL;
! 2256: int ret, retry = 10;
! 2257:
! 2258: char *qbuf;
! 2259:
! 2260: char tmpbuf[DGL_PLAYERNAMELEN+2];
! 2261:
! 2262: memset(tmpbuf, 0, DGL_PLAYERNAMELEN+2);
! 2263: strncpy(tmpbuf, cname, (isnew ? globalconfig.max_newnick_len : DGL_PLAYERNAMELEN));
! 2264:
! 2265: /* Check that the nick doesn't interfere with already registered nicks */
! 2266: if (isnew && (strlen(cname) >= globalconfig.max_newnick_len))
! 2267: strcat(tmpbuf, "%");
! 2268:
! 2269: qbuf = sqlite3_mprintf("select * from dglusers where username = '%q' collate nocase limit 1", tmpbuf);
! 2270:
! 2271: ret = sqlite3_open(globalconfig.passwd, &db);
! 2272: if (ret) {
! 2273: sqlite3_close(db);
! 2274: debug_write("sqlite3_open failed");
! 2275: graceful_exit(96);
! 2276: }
! 2277:
! 2278: if (userexist_tmp_me) {
! 2279: free(userexist_tmp_me->username);
! 2280: free(userexist_tmp_me->email);
! 2281: free(userexist_tmp_me->env);
! 2282: free(userexist_tmp_me->password);
! 2283: free(userexist_tmp_me);
! 2284: userexist_tmp_me = NULL;
! 2285: }
! 2286:
! 2287: sqlite3_busy_timeout(db, 10000);
! 2288: ret = sqlite3_exec(db, qbuf, userexist_callback, 0, &errmsg);
! 2289:
! 2290: sqlite3_free(qbuf);
! 2291:
! 2292: if (ret != SQLITE_OK) {
! 2293: sqlite3_close(db);
! 2294: debug_write("sqlite3_exec failed");
! 2295: graceful_exit(108);
! 2296: }
! 2297: sqlite3_close(db);
! 2298:
! 2299: return userexist_tmp_me;
! 2300: }
! 2301: #endif
! 2302:
! 2303: /* ************************************************************* */
! 2304:
! 2305: void
! 2306: write_canned_rcfile (int game, char *target)
! 2307: {
! 2308: FILE *canned, *newfile;
! 2309: char buf[1024], *rfn;
! 2310: size_t bytes, len;
! 2311:
! 2312: len = strlen(myconfig[game]->rcfile) + 2;
! 2313: rfn = malloc(len);
! 2314: snprintf (rfn, len, "/%s", myconfig[game]->rcfile);
! 2315:
! 2316: if (!(newfile = fopen (target, "w")))
! 2317: {
! 2318: bail:
! 2319: mvaddstr (13, 1,
! 2320: "You don't know how to write that! You write \"%s was here\" and the scroll disappears.");
! 2321: mvaddstr (14, 1,
! 2322: "(Sorry, but I couldn't open one of the config files. This is a bug.)");
! 2323: return;
! 2324: }
! 2325:
! 2326: if (!(canned = fopen (rfn, "r")))
! 2327: goto bail;
! 2328:
! 2329: free(rfn);
! 2330:
! 2331: while ((bytes = fread (buf, 1, 1024, canned)) > 0)
! 2332: {
! 2333: if (fwrite (buf, 1, bytes, newfile) != bytes)
! 2334: {
! 2335: if (ferror (newfile))
! 2336: {
! 2337: mvaddstr (13, 1, "Your hand slips while engraving.");
! 2338: mvaddstr (14, 1,
! 2339: "(Encountered a problem writing the new file. This is a bug.)");
! 2340: fclose (canned);
! 2341: fclose (newfile);
! 2342: return;
! 2343: }
! 2344: }
! 2345: }
! 2346:
! 2347: fclose (canned);
! 2348: fclose (newfile);
! 2349: chmod (target, default_fmode);
! 2350: }
! 2351:
! 2352:
! 2353:
! 2354: /* ************************************************************* */
! 2355:
! 2356: #ifndef USE_SQLITE3
! 2357: void
! 2358: writefile (int requirenew)
! 2359: {
! 2360: FILE *fp, *fpl;
! 2361: int i = 0;
! 2362: int my_done = 0;
! 2363: struct flock fl = { 0 };
! 2364:
! 2365: fl.l_type = F_WRLCK;
! 2366: fl.l_whence = SEEK_SET;
! 2367: fl.l_start = 0;
! 2368: fl.l_len = 0;
! 2369:
! 2370: signals_block();
! 2371:
! 2372: fpl = fopen (globalconfig.lockfile, "r+");
! 2373: if (!fpl)
! 2374: {
! 2375: signals_release();
! 2376: debug_write("writefile locking failed");
! 2377: graceful_exit (115);
! 2378: }
! 2379: if (fcntl (fileno (fpl), F_SETLK, &fl))
! 2380: {
! 2381: signals_release();
! 2382: debug_write("writefile fcntl failed");
! 2383: graceful_exit (107);
! 2384: }
! 2385:
! 2386: fl.l_type = F_UNLCK;
! 2387:
! 2388: freefile ();
! 2389: readfile (1);
! 2390:
! 2391: fp = fopen (globalconfig.passwd, "w");
! 2392: if (!fp)
! 2393: {
! 2394: signals_release();
! 2395: debug_write("passwd file fopen failed");
! 2396: graceful_exit (99);
! 2397: }
! 2398:
! 2399: for (i = 0; i < f_num; i++)
! 2400: {
! 2401: if (loggedin && !strncmp (me->username, users[i]->username, DGL_PLAYERNAMELEN))
! 2402: {
! 2403: if (requirenew)
! 2404: {
! 2405: /* this is if someone managed to register at the same time
! 2406: * as someone else. just die. */
! 2407: fclose(fp);
! 2408: fclose(fpl);
! 2409: signals_release();
! 2410: debug_write("two users registering at the same time");
! 2411: graceful_exit (111);
! 2412: }
! 2413: fprintf (fp, "%s:%s:%s:%s\n", me->username, me->email, me->password,
! 2414: me->env);
! 2415: my_done = 1;
! 2416: }
! 2417: else
! 2418: {
! 2419: fprintf (fp, "%s:%s:%s:%s\n", users[i]->username, users[i]->email,
! 2420: users[i]->password, users[i]->env);
! 2421: }
! 2422: }
! 2423: if (loggedin && !my_done)
! 2424: { /* new entry */
! 2425: if (f_num < globalconfig.max)
! 2426: fprintf (fp, "%s:%s:%s:%s\n", me->username, me->email, me->password,
! 2427: me->env);
! 2428: else /* Oops, someone else registered the last available slot first */
! 2429: {
! 2430: fclose(fp);
! 2431: fclose(fpl);
! 2432: signals_release();
! 2433: debug_write("too many users in passwd db already");
! 2434: graceful_exit (116);
! 2435: }
! 2436: }
! 2437:
! 2438: fclose (fp);
! 2439: fclose (fpl);
! 2440:
! 2441: signals_release();
! 2442: }
! 2443: #else
! 2444: void
! 2445: writefile (int requirenew)
! 2446: {
! 2447: sqlite3 *db;
! 2448: char *errmsg = NULL;
! 2449: int ret, retry = 10;
! 2450:
! 2451: char *qbuf;
! 2452:
! 2453: if (requirenew) {
! 2454: qbuf = sqlite3_mprintf("insert into dglusers (username, email, env, password, flags) values ('%q', '%q', '%q', '%q', %li)", me->username, me->email, me->env, me->password, me->flags);
! 2455: } else {
! 2456: qbuf = sqlite3_mprintf("update dglusers set username='%q', email='%q', env='%q', password='%q', flags=%li where id=%i", me->username, me->email, me->env, me->password, me->flags, me->id);
! 2457: }
! 2458:
! 2459: ret = sqlite3_open(globalconfig.passwd, &db);
! 2460: if (ret) {
! 2461: sqlite3_close(db);
! 2462: debug_write("writefile sqlite3_open failed");
! 2463: graceful_exit(97);
! 2464: }
! 2465:
! 2466: sqlite3_busy_timeout(db, 10000);
! 2467: ret = sqlite3_exec(db, qbuf, NULL, NULL, &errmsg);
! 2468:
! 2469: sqlite3_free(qbuf);
! 2470:
! 2471: if (ret != SQLITE_OK) {
! 2472: sqlite3_close(db);
! 2473: debug_write("writefile sqlite3_exec failed");
! 2474: graceful_exit(98);
! 2475: }
! 2476: sqlite3_close(db);
! 2477: }
! 2478: #endif
! 2479:
! 2480: /* ************************************************************* */
! 2481:
! 2482: int
! 2483: purge_stale_locks (int game)
! 2484: {
! 2485: DIR *pdir;
! 2486: struct dirent *dent;
! 2487: char* dir;
! 2488: size_t len;
! 2489: short firsttime = 1;
! 2490:
! 2491: dir = strdup(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL));
! 2492:
! 2493: if (!(pdir = opendir (dir))) {
! 2494: debug_write("purge_stale_locks dir open failed");
! 2495: graceful_exit (200);
! 2496: }
! 2497:
! 2498: free(dir);
! 2499:
! 2500: while ((dent = readdir (pdir)) != NULL)
! 2501: {
! 2502: FILE *ipfile;
! 2503: char *colon, *fn;
! 2504: char buf[16];
! 2505: pid_t pid;
! 2506: size_t len;
! 2507: int seconds = 0;
! 2508:
! 2509: if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
! 2510: continue;
! 2511:
! 2512: colon = strchr (dent->d_name, ':');
! 2513: /* should never happen */
! 2514: if (!colon) {
! 2515: debug_write("purge_stale_locks !colon");
! 2516: graceful_exit (201);
! 2517: }
! 2518: if (colon - dent->d_name != strlen(me->username))
! 2519: continue;
! 2520: if (strncmp (dent->d_name, me->username, colon - dent->d_name))
! 2521: continue;
! 2522:
! 2523: len = strlen (dent->d_name) + strlen(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL)) + 1;
! 2524: fn = malloc (len);
! 2525:
! 2526: snprintf (fn, len, "%s%s", dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL), dent->d_name);
! 2527:
! 2528: if (!(ipfile = fopen (fn, "r"))) {
! 2529: debug_write("purge_stale_locks fopen inprogressdir fail");
! 2530: graceful_exit (202);
! 2531: }
! 2532:
! 2533: if (fgets (buf, 16, ipfile) == NULL) {
! 2534: debug_write("purge_stale_locks fgets ipfile fail");
! 2535: graceful_exit (203);
! 2536: }
! 2537:
! 2538: fclose (ipfile);
! 2539:
! 2540: if (firsttime)
! 2541: {
! 2542: clear ();
! 2543: drawbanner (&banner);
! 2544:
! 2545: #define HUP_WAIT 10 /* seconds before HUPPING */
! 2546: mvprintw (3, 1,
! 2547: "There are some stale %s processes, will recover in %d seconds.",
! 2548: myconfig[game]->game_name, HUP_WAIT);
! 2549: mvaddstr (4, 1,
! 2550: "Press a key NOW if you don't want this to happen!");
! 2551:
! 2552: move (3, 51 + strlen(myconfig[game]->game_name)); /* pedantry */
! 2553: halfdelay(10);
! 2554:
! 2555: for (seconds = HUP_WAIT - 1; seconds >= 0; seconds--)
! 2556: {
! 2557: if (dgl_getch() != ERR)
! 2558: {
! 2559: nocbreak(); /* leave half-delay */
! 2560: cbreak();
! 2561: return 0;
! 2562: }
! 2563: mvprintw (3, 50 + strlen(myconfig[game]->game_name), "%d%s", seconds, (seconds > 9) ? "" : " ");
! 2564: }
! 2565:
! 2566: nocbreak();
! 2567: cbreak();
! 2568:
! 2569: firsttime = 0;
! 2570: }
! 2571:
! 2572: clear ();
! 2573: refresh ();
! 2574:
! 2575: pid = atoi (buf);
! 2576:
! 2577: kill (pid, SIGHUP);
! 2578:
! 2579: errno = 0;
! 2580:
! 2581: /* Wait for it to stop running */
! 2582: seconds = 0;
! 2583: while (kill (pid, 0) == 0)
! 2584: {
! 2585: seconds++;
! 2586: sleep (1);
! 2587: if (seconds == 10)
! 2588: {
! 2589: mvprintw (3, 1,
! 2590: "Couldn't terminate one of your stale %s processes gracefully.", myconfig[game]->game_name);
! 2591: mvaddstr (4, 1, "Force its termination? [yn] ");
! 2592: if (tolower (dgl_getch ()) == 'y')
! 2593: {
! 2594: kill (pid, SIGTERM);
! 2595: break;
! 2596: }
! 2597: else
! 2598: {
! 2599: endwin ();
! 2600: fprintf (stderr, "Sorry, no %s for you now, please "
! 2601: "contact the admin.\n", myconfig[game]->game_name);
! 2602: debug_write("could not terminate stale processes");
! 2603: graceful_exit (1);
! 2604: }
! 2605: }
! 2606: }
! 2607:
! 2608: /* Don't remove the lock file until the process is dead. */
! 2609: unlink (fn);
! 2610: free (fn);
! 2611: }
! 2612:
! 2613: closedir (pdir);
! 2614: return 1;
! 2615: }
! 2616:
! 2617:
! 2618: int
! 2619: runmenuloop(struct dg_menu *menu)
! 2620: {
! 2621: struct dg_banner ban;
! 2622: struct dg_menuoption *tmpopt;
! 2623: int userchoice = 0;
! 2624: int doclear = 1;
! 2625:
! 2626: if (!menu) return 1;
! 2627:
! 2628: ban.lines = NULL;
! 2629: ban.len = 0;
! 2630:
! 2631: loadbanner(menu->banner_fn, &ban);
! 2632: while (1) {
! 2633: term_resize_check();
! 2634: if (doclear) {
! 2635: doclear = 0;
! 2636: if (globalconfig.utf8esc) (void) write(1, "\033%G", 3);
! 2637: clear();
! 2638: }
! 2639: drawbanner(&ban);
! 2640: if (menu->cursor_x >= 0 && menu->cursor_y >= 0)
! 2641: mvprintw(menu->cursor_y, menu->cursor_x, "");
! 2642: refresh();
! 2643: userchoice = dgl_getch();
! 2644: if (userchoice == ERR) {
! 2645: freebanner(&ban);
! 2646: return 1;
! 2647: }
! 2648: tmpopt = menu->options;
! 2649: while (tmpopt) {
! 2650: if (strchr(tmpopt->keys, userchoice)) {
! 2651: dgl_exec_cmdqueue(tmpopt->cmdqueue, selected_game, me);
! 2652: doclear = 1;
! 2653: break;
! 2654: } else {
! 2655: tmpopt = tmpopt->next;
! 2656: }
! 2657: }
! 2658:
! 2659: if (return_from_submenu) {
! 2660: freebanner(&ban);
! 2661: return_from_submenu = 0;
! 2662: return 0;
! 2663: }
! 2664:
! 2665: if (check_retard(0)) {
! 2666: freebanner(&ban);
! 2667: debug_write("retard");
! 2668: graceful_exit(119);
! 2669: }
! 2670: }
! 2671: }
! 2672:
! 2673: int
! 2674: main (int argc, char** argv)
! 2675: {
! 2676: /* for chroot and program execution */
! 2677: char atrcfilename[81], *p, *auth = NULL;
! 2678: unsigned int len;
! 2679: int c, i;
! 2680: int userchoice;
! 2681: char *tmp;
! 2682: char *wall_email_str = NULL;
! 2683: #ifdef USE_RLIMIT
! 2684: struct rlimit lim;
! 2685: #endif
! 2686:
! 2687: #ifndef HAVE_SETPROCTITLE
! 2688: /* save argc, argv */
! 2689: char** saved_argv;
! 2690: int saved_argc;
! 2691:
! 2692: saved_argc = argc;
! 2693:
! 2694: saved_argv = malloc(sizeof(char**) * (argc + 1));
! 2695: for (i = 0; i < argc; i++)
! 2696: saved_argv[i] = strdup(argv[i]);
! 2697: saved_argv[i] = '\0';
! 2698:
! 2699: compat_init_setproctitle(argc, argv);
! 2700: argv = saved_argv;
! 2701: #endif
! 2702:
! 2703: p = getenv("DGLAUTH");
! 2704:
! 2705: /* Linux telnetd allows importing the USER envvar via telnet,
! 2706: * while FreeBSD does not. FreeBSD, on the other hand, does allow
! 2707: * the LOGNAME envvar. Check USER first, then LOGNAME.
! 2708: */
! 2709: if (p == NULL) {
! 2710: p = getenv("USER");
! 2711: }
! 2712:
! 2713: if (p == NULL) {
! 2714: p = getenv("LOGNAME");
! 2715: }
! 2716:
! 2717: if (p && *p != '\0')
! 2718: auth = strdup(p);
! 2719: /* else auth is still NULL */
! 2720:
! 2721: /* just to be sure */
! 2722: unsetenv("DGLAUTH"); unsetenv("USER"); unsetenv("LOGNAME");
! 2723:
! 2724: __progname = basename(strdup(argv[0]));
! 2725:
! 2726: while ((c = getopt(argc, argv, "csqh:pi:aeW:SD")) != -1)
! 2727: {
! 2728: /* Stop processing arguments at -c, so that user-provided
! 2729: * commands (via ssh for example) to the dgamelaunch login
! 2730: * shell are ignored.
! 2731: */
! 2732: if (c == 'c') break;
! 2733: switch (c)
! 2734: {
! 2735: case 's':
! 2736: showplayers = 1; break;
! 2737:
! 2738: case 'q':
! 2739: silent = 1; break;
! 2740:
! 2741: case 'i':
! 2742: if (optarg && *optarg != '\0') {
! 2743: if (p && *p != '\0')
! 2744: *p = '\0';
! 2745:
! 2746: p = strdup(optarg);
! 2747: initplayer = 1;
! 2748:
! 2749: if (auth && *auth != '\0')
! 2750: *auth = '\0';
! 2751: }
! 2752: break;
! 2753:
! 2754: case 'W':
! 2755: wall_email_str = strdup(optarg);
! 2756: break;
! 2757:
! 2758: case 'S': /* Free the shared memory block */
! 2759: #ifdef USE_SHMEM
! 2760: if (shm_free()) {
! 2761: if (!silent) fprintf(stderr, "nonexistent shmem block.\n");
! 2762: } else {
! 2763: if (!silent) fprintf(stderr, "shmem block freed.\n");
! 2764: }
! 2765: #else
! 2766: if (!silent) fprintf(stderr, "warning: dgamelaunch was compiled without shmem.\n");
! 2767: #endif
! 2768: graceful_exit(0);
! 2769: break;
! 2770:
! 2771: case 'D': /* dump the shared memory block data */
! 2772: #ifdef USE_SHMEM
! 2773: shm_dump();
! 2774: #else
! 2775: if (!silent) fprintf(stderr, "warning: dgamelaunch was compiled without shmem.\n");
! 2776: #endif
! 2777: graceful_exit(0);
! 2778: break;
! 2779:
! 2780: default:
! 2781: break; /*ignore */
! 2782: }
! 2783: }
! 2784:
! 2785: while (optind < argc)
! 2786: {
! 2787: size_t len = strlen(argv[optind]);
! 2788: memset(argv[optind++], 0, len);
! 2789: }
! 2790: setproctitle("<Anonymous>");
! 2791:
! 2792: srand(time(0));
! 2793:
! 2794: create_config();
! 2795:
! 2796: /* signal handlers */
! 2797: signal (SIGHUP, catch_sighup);
! 2798: signal (SIGINT, catch_sighup);
! 2799: signal (SIGQUIT, catch_sighup);
! 2800: signal (SIGTERM, catch_sighup);
! 2801:
! 2802: (void) tcgetattr (0, &tt);
! 2803:
! 2804: if (!globalconfig.flowctrl) {
! 2805: tt.c_iflag &= ~(IXON | IXOFF | IXANY); /* Disable XON/XOFF */
! 2806: (void) tcsetattr(0, TCSANOW, &tt);
! 2807: }
! 2808:
! 2809: if (-1 == ioctl (0, TIOCGWINSZ, (char *) &win) || win.ws_row < 4 ||
! 2810: win.ws_col < 4) /* Rudimentary validity check */
! 2811: {
! 2812: win.ws_row = 24;
! 2813: win.ws_col = 80;
! 2814: win.ws_xpixel = win.ws_col * 8;
! 2815: win.ws_ypixel = win.ws_row * 8;
! 2816: }
! 2817:
! 2818: /* get master tty just before chroot (lives in /dev) */
! 2819: ttyrec_getpty ();
! 2820:
! 2821: #ifdef USE_RLIMIT
! 2822: #ifdef USE_RLIMIT_CORE
! 2823: /* enable and set core dump size */
! 2824: if (!getrlimit(RLIMIT_CORE, &lim)) {
! 2825: lim.rlim_cur = USE_RLIMIT_CORE;
! 2826: setrlimit(RLIMIT_CORE, &lim);
! 2827: }
! 2828: #endif
! 2829: #ifdef USE_RLIMIT_AS
! 2830: /* set maximum memory usage */
! 2831: if (!getrlimit(RLIMIT_AS, &lim)) {
! 2832: lim.rlim_cur = USE_RLIMIT_AS;
! 2833: setrlimit(RLIMIT_AS, &lim);
! 2834: }
! 2835: #endif
! 2836: #endif
! 2837:
! 2838: if (geteuid () != globalconfig.shed_uid)
! 2839: {
! 2840: /* chroot */
! 2841: if (chroot (globalconfig.chroot))
! 2842: {
! 2843: perror ("cannot change root directory");
! 2844: graceful_exit (2);
! 2845: }
! 2846:
! 2847: if (chdir ("/"))
! 2848: {
! 2849: perror ("cannot chdir to root directory");
! 2850: graceful_exit (3);
! 2851: }
! 2852:
! 2853: /* shed privs. this is done immediately after chroot. */
! 2854: if (setgroups (1, &globalconfig.shed_gid) == -1)
! 2855: {
! 2856: perror ("setgroups");
! 2857: graceful_exit (4);
! 2858: }
! 2859:
! 2860: if (setgid (globalconfig.shed_gid) == -1)
! 2861: {
! 2862: perror ("setgid");
! 2863: graceful_exit (5);
! 2864: }
! 2865:
! 2866: if (setuid (globalconfig.shed_uid) == -1)
! 2867: {
! 2868: perror ("setuid");
! 2869: graceful_exit (6);
! 2870: }
! 2871: }
! 2872:
! 2873: if (globalconfig.locale) {
! 2874: setlocale(LC_CTYPE, globalconfig.locale);
! 2875: }
! 2876:
! 2877: if (showplayers) {
! 2878: inprogressdisplay(-1);
! 2879: graceful_exit (0);
! 2880: }
! 2881:
! 2882: if (wall_email_str) {
! 2883: char *emailfrom = wall_email_str;
! 2884: char *emailmsg = strchr(wall_email_str, ':');
! 2885: if (!emailmsg) {
! 2886: debug_write("wall: no mail msg");
! 2887: graceful_exit(117);
! 2888: }
! 2889: *emailmsg = '\0';
! 2890: emailmsg++;
! 2891: if (emailmsg)
! 2892: wall_email(emailfrom, emailmsg);
! 2893: graceful_exit(0);
! 2894: }
! 2895:
! 2896: banner.len = 0;
! 2897: banner.lines = NULL;
! 2898: loadbanner(globalconfig.banner, &banner);
! 2899:
! 2900: dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_DGLSTART], 0, NULL);
! 2901:
! 2902: if (initplayer) {
! 2903: char *user, *pass;
! 2904:
! 2905: user = strdup(p);
! 2906: pass = strdup(p);
! 2907:
! 2908: autologin(user, pass);
! 2909:
! 2910: if (loggedin) {
! 2911: dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_REGISTER], 0, me);
! 2912: fprintf(stdout, "Setup of %s succeeded.\n", me->username);
! 2913: graceful_exit(0);
! 2914: }
! 2915: else {
! 2916: fprintf(stdout, "Setup of %s failed.\n", p);
! 2917: graceful_exit(10);
! 2918: }
! 2919: }
! 2920:
! 2921: /* simple login routine, uses ncurses */
! 2922: if (readfile (0)) {
! 2923: debug_write("log in fail");
! 2924: graceful_exit (110);
! 2925: }
! 2926:
! 2927: if (auth)
! 2928: {
! 2929: char *user, *pass, *p;
! 2930:
! 2931: p = strchr(auth, ':');
! 2932:
! 2933: if (p)
! 2934: {
! 2935: pass = p + 1;
! 2936:
! 2937: if (*pass != '\0')
! 2938: {
! 2939: *p = '\0';
! 2940: user = auth;
! 2941: autologin(user, pass);
! 2942: }
! 2943: }
! 2944: }
! 2945:
! 2946: initcurses ();
! 2947:
! 2948: g_chain_winch = signal(SIGWINCH, sigwinch_func);
! 2949:
! 2950: term_resize_check();
! 2951:
! 2952: idle_alarm_set_enabled(1);
! 2953:
! 2954: while (1) {
! 2955: if (runmenuloop(dgl_find_menu(get_mainmenu_name())))
! 2956: break;
! 2957: }
! 2958:
! 2959: idle_alarm_set_enabled(0);
! 2960:
! 2961: /* NOW we can safely kill this */
! 2962: freefile ();
! 2963:
! 2964: if (me)
! 2965: free (me);
! 2966:
! 2967: freebanner(&banner);
! 2968: banner_var_free();
! 2969: graceful_exit (20);
! 2970:
! 2971: return 1;
! 2972: }
CVSweb