Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

init.c 26.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/******************************************************************************
INIT.C       Initialization procedure.

    Copyright 1993 - 2000 Paul J. Sidorsky

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License, version 2, as
    published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
Deucе's avatar
Deucе committed
17
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880

This module contains the initialization and startup code for TOP.
******************************************************************************/

#include "top.h"

/* these are completely arbitrary and occasionally stupid ToDo */
#ifdef __unix__
#define MAXDRIVE	2
#define MAXEXT		16
#endif

/* DEBUG mode variable.  This isn't in GLOBAL.C because it mostly pertains
   to initialization. */
FILE *debuglog = NULL; /* Name of the debug log. */
/* DEBUG mode function prototypes. */
void wdl(char *msg);
void _USERENTRY closedebuglog(void);

/* init() - Initializes files, variables, and the door kit.
   Parameters:  argc - Number of command line arguments.
                argv - String array of command line arguments.
   Returns:  Nothing.
*/
void init(XINT argc, char *argv[])
{
/* Temporary node number, result code, task to perform. */
XINT tnod = -1, res, todo = 0;
unsigned char valcode[11]; /* Validation code for RegKey. */
char drive[MAXDRIVE]; /* Drive where TOP.EXE is located. */
char dir[MAX_PATH]; /* Directory where TOP.EXE is located. */
char file[MAX_PATH]; /* Base file name of TOP executable (usually TOP). */
char ext[MAXEXT]; /* Extension of TOP executable (usually .EXE) */
#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__unix__)
unsigned char shchk; /* Share check flag. */
#endif

/* This function is quite long and could probably be broken up into
   subfunctions for managability. */

#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__unix__)
/* Check for SHARE support under DOS. */
asm {
    mov ax,01000h
    int 0x2F
    mov shchk, al
    }

/* 0xFF is returned if SHARE is installed. */
if (shchk != 0xFF)
    {
    printf("\nSHARE compatibility not found!\r\nPlease check to make sure "
           "that SHARE.EXE is loaded or that your operating\nenvironment's "
           "SHARE compatibility is turned on.\n");
    exit(207);
    }
#endif

/* Check for extended command line parameters. */
if (argc >= 3)
    {
    /* Debug mode. */
    if (!stricmp(argv[2], "DEBUG"))
        {
        /* Open the debug log. */
        debuglog = fopen("topdebug.log", "at");
        atexit(closedebuglog);
        wdl("--------------------------------------------");
        }
#ifdef __WIN32__
    /* Comm handle under Win95. */
    if (!strnicmp(argv[2], "/HANDLE:", 8))
        {
        od_control.od_open_handle = strtol(&argv[2][8], NULL, 10);
        }
#endif
    }

#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__unix__)
#ifdef FORTIFY
/* Enable Fortify memory checker under DOS in debug mode. */
if (debuglog == NULL)
	{
    Fortify_Disable();
    }
#endif
#endif

/* Initialize the random number generator.  Random numbers are currently
   not used, but were used by the poker and other game modules in past. */
#ifndef __unix__
randomize();
#endif

/* Initialize the polling timer. */
lastpoll = myclock();

/* Initialize the validation code for RegKey.  This is done on a character-
   by-character basis to make the code less obvious to potential hackers
   looking on from a hex editor. */
// * Deleted *

/* Initialize door kit registration information. */
#ifdef __OS2__
// * Deleted *
#else
// * Deleted *
#endif

/* Set program name in the door kit. */
#if defined(__OS2__)
sprintf(od_control.od_prog_name, "TOP/2 v%s", ver);
#elif defined(__WIN32__)
sprintf(od_control.od_prog_name, "TOP/95 v%s", ver);
/* Additional information for Win95 About dialog. */
strcpy(od_control.od_prog_copyright,
       "Copyright 1993 - 1998 ISMWare");
strcpy(od_control.od_prog_version,
       "32-bit Windows 95/NT Version");
#else
sprintf(od_control.od_prog_name, "TOP v%s", ver);
#endif

/* General door kit settings. */
od_control.od_nocopyright = TRUE;
od_control.od_always_clear = TRUE;
#ifdef __OS2__
od_control.od_no_messages = TRUE;
#endif

/* Door kit inbound comm buffer size.  The larger size makes TOP handle
   screen dumps from users (which can occur often in a chat door) better. */
od_control.od_in_buf_size = 8192;

/* Clear the user's record number. */
user_rec_num = -1;

/* Clear the node type flags. */
localmode = 0; lanmode = 0;

/* Door kit appearance. */
od_control.mps = NO_MPS;
od_control.default_personality = PER_RA;

wdl("First variable init completed");

#ifdef __OS2__
/* Handle additional OS/2 command line parameters. */
ProcessCmdLine(argc, argv);
#endif

/* Handle extra TOP tasks. */
if (argc >= 2)
    {
    /* Cheap-ass user deletor and security editor. */
    if (!stricmp(argv[1], "EDIT"))
        {
        todo = 1;
        tnod = 1;
        localmode = 1;
        }
    /* User file packer. */
    if (!stricmp(argv[1], "PACK"))
        {
        todo = 2;
        tnod = 1;
        localmode = 1;
        }
    }

/* Get the node number from the TASK envirionment variable. */
if (getenv("TASK") != NULL)
    {
    tnod = atoi(getenv("TASK"));
    }

/* Get the node number from the command line if it's there. */
if (argc >= 2 && !todo)
    {
    tnod = atoi(argv[1]);
    }

/* Set the final node number. */
if (tnod > 0)
    {
    od_control.od_node = tnod;
    }

/* Set the default node as 1 if none has been found or specified. */
if (od_control.od_node == 0)
    {
    od_control.od_node = 1;
    }

/* We need to force this setting early as it's used by one of the file
   opening routines. */
cfg.maxretries = 1;
//cfg.maxmsglen = 255;

wdl("Command line processing completed");

/* Initialize node configuration data and word splitter buffers.  The node
   configuration loader requires the node configuration data buffer
   (obviously) and the word splitter, so these get allocated before everything
   else.*/
nodecfg = malloc(sizeof(TOP_nodecfg_typ));
word_str = malloc(256);
word_pos = calloc(128, sizeof(XINT));
word_len = calloc(128, sizeof(XINT));
wordret = malloc(256);
if (nodecfg == NULL || word_str == NULL || word_pos == NULL ||
    word_len == NULL || wordret == NULL)
    {
    printf("\nNot enough memory to load Node Configuration!\n");
    exit(202);
    }

/* Find out where TOP.EXE is. */
#ifdef __unix__
_splitpath(argv[0], drive, dir, file, ext);
#else
fnsplit(argv[0], drive, dir, file, ext);
#endif
sprintf(word_str, "%s%s", drive, dir);
verifypath(word_str);

/* Load the node configuration.  This is done first because a lot of
   information from the node configuration is needed to initialize the
   door kit. */
if (!loadnodecfg(word_str))
    {
    printf("\nCan't load Node Configuration for node %i!\n",
           od_control.od_node);
    exit(100);
    }

/* Kludge forces for local and lan nodes.  As the note suggests this should
   be handled more eloquently. */
if (nodecfg->type == NODE_LOCAL) // Won't eventually need this....
    {
    localmode = 1;
    }
if (nodecfg->type == NODE_LAN)
    {
    lanmode = 1;
    }

wdl("Node configuration read properly");

/* Under LAN or Local modes, there is no need for a drop file, carrier
   detection, or time limit. */
if (localmode || lanmode)
    {
    od_control.od_disable = DIS_INFOFILE | DIS_CARRIERDETECT | DIS_TIMEOUT;
    }

/* If one is configured, set the drop file path.  This can include the
   filename under OpenDoors specifications although it usually doesn't. */
if (nodecfg->dropfilepath[0])
    {
    strcpy(od_control.info_path, nodecfg->dropfilepath);
    }

/* Setup the configuration file processor.  Although the built-in OpenDoors
   configuration options aren't even mentioned, this seemed like the best
   place to handle the configuration information since the processing is
   built into OD. */
od_control.od_config_file = INCLUDE_CONFIG_FILE;
od_control.od_config_filename = nodecfg->cfgfile;
od_control.od_config_function = processcfg;

/* Copy communication information from the node configuration to OD. */
od_control.od_com_method = nodecfg->fossil ? COM_FOSSIL : COM_INTERNAL;
od_control.port = nodecfg->port - 1;
od_control.baud = nodecfg->speed;
od_control.od_com_address = nodecfg->portaddress;
od_control.od_com_irq = nodecfg->portirq;
od_control.od_com_no_fifo = !nodecfg->usefifo;
od_control.od_com_fifo_trigger = nodecfg->fifotrigger;
od_control.od_com_rx_buf = nodecfg->rxbufsize;
od_control.od_com_tx_buf = nodecfg->txbufsize;

wdl("OpenDoors pre-init completed");

/* Fire up OpenDoors. */
od_init();

/* Initialize the kernel timer and our custom kernel function. */
time(&lastkertime);
od_control.od_ker_exec = top_kernel;

/* Initialize a temporary user name and location under local/LAN modes so
   the status line doesn't look terrible. */
if (localmode || lanmode)
    {
    strcpy(od_control.user_name, "Unknown User");
    strcpy(od_control.user_location, "Unknown");
    }

/* Initlialize the log file.  OpenDoors' built-in logging is used. */
strcpy(od_control.od_logfile_name, nodecfg->logfile);
od_log_open();

wdl("OpenDoors init completed");

/* Initialize some door kit variables. */
od_control.od_inactivity = cfg.inactivetime;
od_control.od_clear_on_exit = FALSE;

/* For some reason long ago I thought memory handlers were needed before
   shelling to DOS and that swapping may have been crashing it.  This
   was later discovered to not only be false, but that the handlers were
   actually preventing shelling from working themselves. */
/*od_control.od_cbefore_shell = preshell;
od_control.od_cafter_shell = postshell;
od_control.od_swapping_disable = TRUE;*/

/* Override OpenDoors' rather unusual (IMO) default errorlevels.  I don't
   know many other programs (and especially doors) that return 10 on a
   normal exit! */
od_control.od_errorlevel[0] = TRUE;   /* Turn on custom errorlevels */
od_control.od_errorlevel[1] = 255;    /* Critical */
od_control.od_errorlevel[2] = 1;      /* DCD loss */
od_control.od_errorlevel[3] = 5;      /* Alt-H    */
od_control.od_errorlevel[4] = 2;      /* Time Up  */
od_control.od_errorlevel[5] = 3;      /* Inactive */
od_control.od_errorlevel[6] = 4;      /* Alt-D    */
od_control.od_errorlevel[7] = 0;      /* Normal   */

/* In case OpenDoors tried to reset the node number, we want to force it
   back to the one the user told us to use, if any. */
if (tnod > 0)
    {
    od_control.od_node = tnod;
    }
if (od_control.od_node == 0)
    {
    od_control.od_node = 1;
    }

/* Adjust some settings that we don't really need in LAN/local modes. */
if (localmode || lanmode)
    {
    /* No inactivity timer. */
    od_control.od_inactivity = 0;
    /* Since timeout is disabled the time remaining doesn't matter, but
       this makes it look like the user has a lot of time left. */
    od_control.user_timelimit = 1440;
    /* Force an update of the status line. */
    od_kernel();
    /* Turn the status line updating off. */
    od_control.od_status_on = FALSE;
    }

/* Initialize RA credit usage if enabled. */
if (cfg.usecredits)
    {
    orignumcreds = od_control.user_credit;
    }

wdl("OpenDoors post-init completed");

/* Initialize BBS interface functions if enabled. */
switch(cfg.bbstype)
    {
    case BBS_RA2: ra_init(); break;
    case BBS_MAX2: max_init(); break;
#ifdef __OS2__
    case BBS_MAX3: max_mcpinit(); break;
#endif
    case BBS_SBBS11: sbbs_init(); break;
    }

wdl("BBS function init completed");

/* Perform the memory allocations.  This is one of the few initialization
   tasks that is sub-functioned, though this was originally done because
   of the shell memory handlers described above.  Sometimes good things
   result from stupid blunders. */
res = memalloc();
/* Now that the memory has been allocated, we need the exit handler. */
od_control.od_before_exit = before_exit;
/* Abort if not enough memory. */
if (res)
    {
    printf("\nOut Of Memory!\n");
    od_log_write(top_output(OUT_STRING, getlang("LogOutOfMemory")));
    od_exit(200, FALSE);
    }

wdl("Memory allocation completed");

/* Open the files.  Again, this was sub-functioned because of the shell
   handlers. */
openfiles();

wdl("Files opened");

/* Clear all node statuses. */
memset(activenodes, 0, MAXNODES);

wdl("Memory init completed");

/* Load the language file.  The name is taken from the configuration
   information. */
if (!loadlang())
    {
    printf("\nNot enough memory to load language file!\n");
    od_log_write(top_output(OUT_STRING, getlang("LogCantLoadLang")));
    od_exit(203, FALSE);
    }

wdl("Language file loaded");

/* Load CHANNELS.CFG. */
if (!loadchan())
    {
    printf("\nCan't load channel definition list!\n");
    od_log_write(top_output(OUT_STRING, getlang("LogCantLoadChan")));
    od_exit(204, FALSE);
    }

wdl("Channel file loaded");

if (lanmode)
    {
    /* Counter, free node holder.  The choice of xz as a variable name is
       probably left over from my BASIC years, when unintelligible variable
       names were the norm. */
    XINT d, xz = -1;

    /* This section is the whole reason LAN mode exists.  It finds a free
       node if the one requested isn't available. */

    /* See which nodes are using TOP. */
    check_nodes_used(FALSE);
    /* Loop for each remaining node using the specified node as a
       starting point. */
    for (d = od_control.od_node + 1; d < MAXNODES && xz == -1; d++)
        {
        if (!activenodes[d])
            {
            /* Found a free node. */
            xz = d;
            }
        }
    if (xz == -1)
        {
        /* Didn't find a free node. */
        top_output(OUT_SCREEN, getlang("NoFreeNode"));
        top_output(OUT_SCREEN, getlang("ContactSuper"));
        od_log_write(top_output(OUT_STRING, getlang("LogNoFreeNode")));
        od_exit(101, FALSE);
        }
    /* Reset the node and reopen any node-specific files. */
    od_control.od_node = xz;
    lan_updateopenfiles();

wdl("LAN init completed");

    }
else wdl("LAN init not needed");

#ifndef __unix__
if (localmode || lanmode)
    {
    struct text_info ti; /* Screen mode information. */

    gettextinfo(&ti);
    if (ti.currmode == BW40 || ti.currmode == BW80)
        {
        /* If a monochrome screen mode (not necessarily a mono monitor) is
           detected, turn off ANSI since it isn't really needed. */
        od_control.user_ansi = FALSE;
        }
    else
        {
        /* Force ANSI on a colour screen.  Given that there is no worry
           of transmission time in local/LAN mode, it seems logical to
           turn it on. */
        od_control.user_ansi = TRUE;
        }
    /* Local RIP isn't supported by the door kit. */
    od_control.user_rip = FALSE;

wdl("Local init completed");

    }
else 
#endif
	wdl("Local init not needed");

/* Perform some final appearance work. */
od_set_personality("RemoteAccess");
trim_string(od_control.user_location, od_control.user_location, 0);
od_kernel();

wdl("OD Log init completed");

/* We don't use OD's own bulky colour strings so turn it off. */
od_control.od_colour_delimiter = '\0';

/* Reset the screen attribute. */
od_set_colour(D_GREY, D_BLACK);

/* Clear the MIX file info. */
memset(&midxfileinfo, 0, sizeof(struct file_stats_str));

/* Log the node type. */
if (localmode)
    {
    od_log_write(top_output(OUT_STRING, getlang("LogLocal")));
    }
if (lanmode)
    {
    od_log_write(top_output(OUT_STRING, getlang("LogLAN")));
    }
if (!localmode && !lanmode)
    {
    od_log_write(top_output(OUT_STRING, getlang("LogDoor")));
    }

wdl("Secondary memory init completed");

/* Execute a selected task. */
if (todo > 0)
    {
wdl("Init completed - initiating command-line-selected task");
    od_log_write(top_output(OUT_STRING, getlang("LogOneRunMode")));
    switch(todo)
        {
        /* TOP EDIT. */
        case 1: useredit(); break;
        /* TOP PACK. */
        case 2: if (argc > 3) strcpy(outbuf, argv[3]); else outbuf[0] = 0;
                if (argc > 2) strcpy(word_str, argv[2]); else word_str[0] = 0;
                userpack();
                break;
        }
    }

/* Clear all forget statuses. */
memset(forgetstatus, 0, MAXNODES);

/* Unused Poker initialization code. */
/*//|for (res = 0; res < cfg.pokermaxgames; res++)
	{
    pokerlockflags[res] = 0;
    pokeretimes[res] = 0xFFFFFFFFUL;
    pokerdtimes[res] = 0xFFFF;
    pokerwtimes[res] = 0xFFFF;
    pokeringame[res] = 0;
    }*///|

/* Initialize the channel number. */
curchannel = cfg.defaultchannel;

wdl("Tertiary memory init completed");

/* Initialize the number of action files, which is done by counting the
   words in the action file string.  todo is used in the loop because I was
   too lazy to type the entire variable name. */
numactfiles = todo = split_string(cfg.actfilestr);
// Errs from hell
/* Allocate space for all of the filenames. */
cfg.actfilenames = calloc(todo + 1, sizeof(unsigned char XFAR *));
/* Loop for each file. */
for (res = 0; res <= todo; res++)
	{
    /* Initialize the filename buffer. */
    cfg.actfilenames[res] = malloc(13);
    memset(cfg.actfilenames[res], 0, 13);
    if (res == 0)
        {
        /* List 0 is the personal action list, so copy the name from the
           language file. */
        strcpy(cfg.actfilenames[res],
               /* strupr(top_output(OUT_STRING, getlang("PersActListName")))); */
			   top_output(OUT_STRING, getlang("PersActListName")));
        }
    else
        {
        strncpy(cfg.actfilenames[res], get_word(res - 1), 8);
        }
    /* strupr(cfg.actfilenames[res]); */
	cfg.actfilenames[res];
    }

wdl("Pre-action init completed");

/* Load the action files.  Not sure why the note is there to fix the
   check but it could be because of the partially-allocated status that
   can occur if it fails. */
if (!loadactions()) // Fix this check later.
    {
    od_log_write(top_output(OUT_STRING, getlang("LogCantLoadActs")));
    od_exit(205, FALSE);
    }

wdl("Actions loaded");

/* Load CENSOR.CFG. */
if (!load_censor_words())
    {
    od_log_write(top_output(OUT_STRING, getlang("LogCantLoadCWords")));
    }

wdl("Censor Words Loaded");

/* Load spawnable programs, which was a feature removed from TOP due to
   instability. */
//load_spawn_progs(); // check return value later

/* Load BIOQUES.CFG. */
if (!loadbioquestions())
    {
    od_log_write(top_output(OUT_STRING, getlang("LogCantLoadBioQues")));
    }

/* Copy predefined BBS status types into a string array, which was how they
   were handled before the language file existed. */
for (res = 0; res < 11; res++)
    {
    sprintf(outbuf, "SBBSStatusType%i", res);
    sbbs_statustypes[res] = getlang(outbuf);
    if (res < 8)
        {
        sprintf(outbuf, "RAStatusType%i", res);
        ra_statustypes[res] = getlang(outbuf);
        }
    }

wdl("BBS Status Strings Initialized");

wdl("Initialization completed");

/* Phew!  All done! */
return;
}

/* openfiles() - Opens all major files used by TOP.
   Parameters:  None.
   Returns:  Nothing.
   Notes:  Aborts on its own if an error occurs.
*/
void openfiles(void)
{
unsigned char tnam[512]; /* Temporary filename buffer. */
XINT res = 0; /* Result code. */

/* Open all files that TOP needs to keep open while it runs. */

/* User file. */
sprintf(tnam, "%susers.top", cfg.toppath);
userfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                  S_IREAD | S_IWRITE);
/* res holds the number of errors that occurred, which is not used right
   now but could be reported for debugging purposes. */
res += (userfil == -1);
/* Node index. */
sprintf(tnam, "%snodeidx.tch", cfg.topworkpath);
nidxfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                  S_IREAD | S_IWRITE);
res += (nidxfil == -1);
if (nidxfil != -1 && filelength(nidxfil) <
    (long) ((long) od_control.od_node + 1L) * (long) sizeof(node_idx_typ))
    {
    /* Adjust the size of the node index if it is too small. */
    chsize(nidxfil, (long) ((long) od_control.od_node + 1L) *
                   (long) sizeof(node_idx_typ));
    }
/* Active node index. */
sprintf(tnam, "%snodeidx2.tch", cfg.topworkpath);
nidx2fil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                   S_IREAD | S_IWRITE);
res += (nidx2fil == -1);
/* Message file for this node.  (Incoming messages.) */
sprintf(tnam, "%smsg%05i.tch", cfg.topworkpath, od_control.od_node);
msginfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                   S_IREAD | S_IWRITE);
res += (msginfil == -1);
/* Open BBS-specific files if needed. */
if (cfg.bbstype != BBS_UNKNOWN && bbs_call_openfiles)
    {
    res += (*bbs_call_openfiles)();
    }
/* Message index for this node.  (Incoming messages.) */
sprintf(tnam, "%smix%05i.tch", cfg.topworkpath, od_control.od_node);
midxinfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                    S_IREAD | S_IWRITE);
res += (midxinfil == -1);
/* Message change index. */
sprintf(tnam, "%schgidx.tch", cfg.topworkpath);
chgfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                 S_IREAD | S_IWRITE);
res += (chgfil == -1);
/* Adjust the size of the change index if it is too small. */
if (chgfil != -1)
    {
    chsize(chgfil, MAXNODES);
    }
/* Channel data (CMI) index. */
sprintf(tnam, "%schanidx.tch", cfg.topworkpath);
chidxfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                 S_IREAD | S_IWRITE);
res += (chidxfil == -1);
/* Games data files, not used as the games were removed. */
sprintf(tnam, "%sslotstat.top", cfg.toppath);
slotsfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                   S_IREAD | S_IWRITE);
res += (slotsfil == -1);
if (slotsfil != -1)
    {
    chsize(slotsfil, sizeof(slots_stat_typ));
    }
sprintf(tnam, "%smatchstat.top", cfg.toppath);
matchfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                   S_IREAD | S_IWRITE);
res += (slotsfil == -1);
/*//|sprintf(tnam, "%spokerdat.tch", cfg.toppath);
pokdatafil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                     S_IREAD | S_IWRITE);
res += (pokdatafil == -1);*///|
/* Biography response index. */
sprintf(tnam, "%sbigidx.top", cfg.toppath);
bioidxfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                   S_IREAD | S_IWRITE);
res += (bioidxfil == -1);
/* Adjust the size of the index if it is too small. */
if (bioidxfil != -1 &&
    filelength(bioidxfil) < (filelength(userfil) / sizeof(user_data_typ)) *
                            MAXBIOQUES * sizeof(long))
    {
    chsize(bioidxfil, (filelength(userfil) / sizeof(user_data_typ)) *
                       MAXBIOQUES * sizeof(long));
    }
/* Biography responses. */
sprintf(tnam, "%sbioresp.top", cfg.toppath);
biorespfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO,
                                    S_IREAD | S_IWRITE);
res += (biorespfil == -1);

/* Abort on error. */
if (res)
    {
    top_output(OUT_SCREEN, getlang("CantInitFiles"));
    od_exit(201, FALSE);
    }

return;
}

/* lan_updateopenfiles() - Reopen node-dependant files in LAN mode.
   Parameters:  None.
   Returns:  Nothing.
   Notes:  Aborts on its own if an error occurs.
*/
void lan_updateopenfiles(void)
{
unsigned char tnam[512]; /* Temporary filename buffer. */
XINT res = 0; /* Result code. */

/* This function opens files that use the node number in LAN mode, after
   TOP has found a free node number. */

/* Close the previously open files that are affected. */
close(msginfil); close(ipcinfil); close(midxinfil);

/* Adjust the size of the node index for the new node if it is too small. */
if (filelength(nidxfil) <
    (long) ((long) od_control.od_node + 1L) * (long) sizeof(node_idx_typ))
    {
    chsize(nidxfil, (long) ((long) od_control.od_node + 1L) *
                   (long) sizeof(node_idx_typ));
    }

/* Incoming messages. */
sprintf(tnam, "%smsg%05i.tch", cfg.topworkpath, od_control.od_node);
msginfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO, S_IREAD | S_IWRITE);
res += (msginfil == -1);
/* Reopen any BBS-specific files that need the node number. */
if (cfg.bbstype != BBS_UNKNOWN && bbs_call_updateopenfiles)
    {
    res += (*bbs_call_updateopenfiles)();
    }
/* Incoming message index. */
sprintf(tnam, "%smix%05i.tch", cfg.topworkpath, od_control.od_node);
midxinfil = sh_open(tnam, O_RDWR | O_CREAT | O_BINARY, SH_DENYNO, S_IREAD | S_IWRITE);
res += (midxinfil == -1);

/* Abort on error. */
if (res)
    {
    top_output(OUT_SCREEN, getlang("CantInitFiles"));
    od_exit(201, FALSE);
    }

return;
}

/* memalloc() - Allocate most of the memory TOP uses.
   Parameters:  None.
   Returns:  TRUE on error, FALSE if successful.
*/
char memalloc(void)
{
char mres = 0; /* Result code. */

/* See GLOBAL.C for variable descriptions.  TOP allocates all memory even
   on error, for simplicity.  The |= assignment used allows TOP to
   preserve any previously detected error while continuing the allocation. */

/* Remember to change before_exit() when adding new pointers! */
mres |= ((handles = calloc(MAXNODES, 31)) == NULL);
mres |= ((activenodes = malloc(MAXNODES)) == NULL);
mres |= ((outbuf = malloc(512)) == NULL);
mres |= ((forgetstatus = malloc(MAXNODES)) == NULL);
mres |= ((busynodes = malloc(MAXNODES)) == NULL);
mres |= ((node = malloc(sizeof(node_idx_typ))) == NULL);
mres |= ((outputstr = malloc(513)) == NULL);
mres |= ((lastcmd = malloc(256)) == NULL);
mres |= ((chan = calloc(cfg.maxchandefs, sizeof(channel_data_typ))) ==
         NULL);
mres |= ((bioques = calloc(MAXBIOQUES, sizeof(bio_ques_typ))) == NULL);
/*//|mres |= ((pokerlockflags = malloc(cfg.pokermaxgames)) == NULL);
mres |= ((pokeretimes = calloc(cfg.pokermaxgames, sizeof(time_t))) ==
         NULL);
mres |= ((pokerdtimes = calloc(cfg.pokermaxgames, sizeof(XINT))) == NULL);
mres |= ((pokerwtimes = calloc(cfg.pokermaxgames, sizeof(XINT))) == NULL);
mres |= ((pokeringame = malloc(cfg.pokermaxgames)) == NULL);*///|

return mres;
}

/* wdl() - Write a message to the DEBUG log.
   Parameters:  wdl - String to write to the log.
   Returns:  Nothing.
*/
void wdl(char *msg)
    {

    /* Only write if we're in DEBUG mode, i.e. if the debug log has been
       opened. */
    if (debuglog != NULL)
        {
        fprintf(debuglog, "%s\n", msg);
        }

    }

/* closedebuglog() - Closes the TOP DEBUG log.
   Parameters:  None.
   Returns:  Nothing.
*/
void _USERENTRY closedebuglog(void)
    {

    /* Close the debug log. */
    fclose(debuglog);

    }