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

main.c 14.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/******************************************************************************
MAIN.C       Main loop and program entry point.

    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

This module contains the program entry point (main() in DOS & OS/2, WinMain()
in Win32) and the main input loop.
******************************************************************************/

#include "top.h"

/* main() - Program entry point under DOS and OS/2.
   Parameters:  ac - Number of command line arguments.
                av - String array of command line arguments.
   Returns:  Nothing.
*/
/* WinMain() - Program entry point under Win32.
   Parameters:  hInstance - Handle of this instance of TOP.
                hPrevInstance - Handle of previous instance of TOP.
                lpszCmdParam - String of command line parameters.
                nCmdShow - Numeric code telling how TOP's window should
                           open (normal, minimized, etc.)
   Returns:  Program result code.
   Notes:  This function never returns.  exit() is always used to quit TOP.
*/
#ifndef __WIN32__
40
extern int main(XINT ac, char *av[])
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
#else
extern int pascal WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                          LPSTR lpszCmdParam, int nCmdShow)
#endif
{

/* This function is a little cluttered but it is manageable. */

#ifdef __WIN32__
/* TOP doesn't use any of the WinMain parameters. */
(void) hInstance;
(void) hPrevInstance;
(void) lpszCmdParam;
/* OpenDoors needs to know how to show the TOP window. */
od_control.od_cmd_show = nCmdShow;
/* Load TOP's custom icon. */
od_control.od_app_icon = LoadIcon(hInstance, "Icon");
/* Because init() needs a separated command line, it is passed the global
   command line variables provided by the Borland compiler. */
init(_argc, _argv);
#else
/* Initialize TOP. */
init(ac, av);
#endif
/* Show a title page if the option is turned on. */
if (cfg.showtitle)
	{
    show_file("toptitle", SCRN_ALL);
    }
/* Find and load the user, creating a new user if needed. */
search_for_user();
/* Show a news file if the option is on. */
if (cfg.shownews)
	{
    show_file("topnews", SCRN_ALL);
    }
/* Prepare the screen for dual window mode if the user has it turned on. */
if (user.pref1 & PREF1_DUALWINDOW)
	{
    top_output(OUT_SCREEN, getlang("DWOutputPrepare"));
    top_output(OUT_SCREEN, getlang("DWOutputSetCurPos"));
    }
/* Show the welcome. */
top_output(OUT_SCREEN, getlang("SitDown"));
/* Show who's in the channel and a basic help. */
channelsummary();
/* Let other users know we're here. */
dispatch_message(MSG_ENTRY, user.emessage, -1, 0, 0);
/* Store the screen location under dual window mode. */
if (user.pref1 & PREF1_DUALWINDOW)
	{
    // Different for AVT when I find out what the store/recv codes are.
    od_disp_emu("\x1B" "[s", TRUE);
    }
/* Run the main input loop forever. */
for (;;)
	{
	main_loop();
    }

}

/* In the main loop, DOS gets the current clock tick from the system to
   help it determine when to timeslice. */
#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__unix__)
#define _clock_tick() (*(long XFAR *)0x46cL)
#endif

/* main_loop() - Main input loop.
   Parameters:  None.
   Returns:  Nothing.
*/
void main_loop(void)
{
XINT key, pos, wwc; /* Input key, string position, word wrap counter. */
unsigned char input[256], ww[81]; /* Input buffer, word wrap buffer. */
XINT tmp; /* Result code. */
#ifndef __OS2__
long clktick; /* Holds the clock tick under DOS. */
#endif
int	xpos,ypos;

/* Initialize variables. */
onflag = 0;
memset(input, 0, MAXSTRLEN + 1); memset(ww, 0, 81);
pos = -1; wwc = 0;
for(;;)
	{
#ifdef __OS2__
    /* Timeslice under OS/2. */
//  od_sleep(0);
    DosSleep(10);
#endif
#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__unix__)
    /* Get the clock tick under DOS. */
    clktick = _clock_tick();
#endif
    /* Clear the key input holder. */
    key = '\0';
    /* Set/clear the onflag if the user has started typing. */
    if (strlen(input) > 0)
        {
        onflag = 1;
        }
    else
        {
        onflag = 0;
        }
    /* If the position is -1 then the screen needs to be initialized. */
    if (pos == -1)
    	{
        /* Clear/initalize the screen in dual window mode. */
        if (onflag && !(user.pref1 & PREF1_DUALWINDOW))
            {
            top_output(OUT_SCREEN, getlang("InputPrefix"));
            } // Also time, date, minleft to bottom
        /* More dual window mode preparation. */
        if (user.pref1 & PREF1_DUALWINDOW)
            {
            if (onflag)
                {
                /* Prepare the screen when the user is typing. */
                // Next four lines are here temporarily!
                // These will get replaced when proper scrolling is done
                top_output(OUT_SCREEN, getlang("DWPrepareInput"));
                top_output(OUT_SCREEN, getlang("DWTopDisplay"));
                top_output(OUT_SCREEN, getlang("DWMiddleDisplay"));
                top_output(OUT_SCREEN, getlang("DWBottomDisplay"));
                top_output(OUT_SCREEN, getlang("DWInputCurPos"));
                /* Prepares the scren to "retype" what the user has already
                   input. */
                top_output(OUT_SCREEN, getlang("DWRestoreInput"));
                }
            else
                {
                /* Prepare the scren when the user is idle. */
                // Next four lines are here temporarily!
                top_output(OUT_SCREEN, getlang("DWPrepareInput"));
                top_output(OUT_SCREEN, getlang("DWTopDisplay"));
                top_output(OUT_SCREEN, getlang("DWMiddleDisplay"));
                top_output(OUT_SCREEN, getlang("DWBottomDisplay"));
                top_output(OUT_SCREEN, getlang("DWInputCurPos"));
                }
            }
        else
            {
            /* Show the prompt in normal mode. */
            top_output(OUT_SCREEN, getlang("DefaultPrompt"), user.handle);
            }
        /* Clear the position counter. */
        pos = 0;
        if (onflag) // Temp for DW mode.
            {
            /* If the user has typing, "retype" what the user has already
               input. */
            pos = strlen(input);
            /* We don't want codes to be processed when retyping. */
            outproclang = FALSE; outproccol = FALSE;
            top_output(OUT_SCREEN, input);
            outproclang = TRUE; outproccol = TRUE;
            /* In dual window mode, clear the onflag.  This is done because
               during message processing, the onflag is used to display the
               interrupt string, but the interrupt string is unnecessary
               in dual window mode. */
            if (user.pref1 & PREF1_DUALWINDOW)
                {
                onflag = 0;
                }
            }
        }

    /* Show messages only if the user isn't typing, or if the user has
       block while typing turned off. */
    if (pos == 0 || (pos > 0 && !(user.pref1 & PREF1_BLKWHILETYP)))
        {
        /* Only poll for messages once enough time has elapsed. */
        if ((((float) myclock() - (float) lastpoll) / (float) CLK_TCK) >=
            POLLTIMEDELAY)
            {
            /* Poker operations, unused. */
/*//|            if ((((float) myclock() - (float) lastpokerpoll) /
                   (float) CLK_TCK) >=
                   ((float) cfg.pokerpolltime / 10.0))
                {
                XINT pokd;

                for (pokd = 0; pokd < cfg.pokermaxgames; pokd++)
                    {
                    if (pokeringame[pokd])
                        {
                        poker_eventkernel(pokd);
                        }
                    }
                lastpokerpoll = myclock();
                }*///|
            /* Store the screen location.  This is no longer used but was
               left in so it could be used later. */
            if (pos > 0)
                {
				od_get_cursor(&ypos,&xpos);
				ystore=ypos;
				xstore=xpos;
                }
            /* Process incoming messages.  Only delete the name if the user
               isn't typing, which is what the parameter indicates. */
            tmp = process_messages(pos == 0 ? TRUE : FALSE);
            /* If the result is greater than one, at least one message was
               processed. */
            if (tmp > 0)
                {
                /* pos is set to -1 to tell the next run of the loop that
                   the screen needs to be restored. */
                pos = -1;
                /* onflag used to be set down here but it works better
                   when set at the start of the loop. */
/*                if (strlen(input) > 0)
                    {
                    onflag = 1;
                    }*/
                }
            if (tmp < 1)
                {
                /* If no messages were processed, check for any BBS
                   pages. */
                if (cfg.bbstype != BBS_UNKNOWN && bbs_call_processmsgs)
                    {
                    tmp = (*bbs_call_processmsgs)();
                    }
                if (tmp > 0)
                    {
                    /* Tell the next loop to restore the screen. */
                    pos = -1;
                    }
                }
            /* Set the last polling time. */
            lastpoll = myclock();
            }
        }
    /* Only get a keypress if the screen is ready. */
    if (pos != -1)
   		{
        /* Check if any keys have been pressed, without waiting for one. */
        key = od_get_key(FALSE);
        }
    /* Process the key if one was pressed. */
    if (key)
   		{
        /* Backspace (also delete). */
        if (key == 8 || key == 127)
   	        {
            /* Only backspace if the user has typed something. */
            if (pos > 0)
                {
                /* Clear the last character and move back the position
                   counter. */
                input[--pos] = '\0';
                /* Display a destructive backspace. */
                od_disp_str("\b \b");
                /* Clear the last character in the word wrap buffer if there
                   is one. */
                if (wwc > 0)
                    {
                    ww[--wwc] = '\0';
                    }
                }
            continue;
            }
        /* ENTER (or RETURN). */
        if (key == 13)
            {
            /* Trim trailing spaces from the input, which users can use to
               annoy people. */
            trim_string(input, input, NO_LTRIM);
            /* Process the input. */
            process_input(input);
            /* Save the screen position in dual window mode. */
            if (user.pref1 & PREF1_DUALWINDOW)
                {
                // Different for AVT when I find out what the store/recv codes are.
                od_disp_emu("\x1B" "[s", TRUE);
                }
            /* Tell the next loop the screen needs restoring. */
            pos = -1;
            /* Reset the buffers and word wrap counter. */
            memset(input, 0, MAXSTRLEN + 1);
            memset(ww, 0, 81);
            wwc = 0;
            continue;
            }
        /* Displayable characters.  Only process if the string isn't too
           long. */
        if (key >= 32 && key <= MAXASCII &&
            pos < MAXSTRLEN)
            {
            /* Store this keypress in the input buffer. */
            input[pos++] = key;
            input[pos] = '\0';
            /* Display the key directly. */
            od_putch(key);
            /* Store the keypress in the word wrap buffer. */
            ww[wwc++] = key;
            ww[wwc] = '\0';
            /* Space, hyphen, and slash are considered the word break
               characters. */
            if (key == ' ' || key == '-' || key == '/')
                {
                /* Clear the word wrap buffers. */
                wwc = 0;
                memset(ww, 0, 81);
                }
			od_get_cursor(&ypos,&xpos);
            if (xpos != 80)
                {
                /* If the cursor isn't at the end of the screen, nothing
                   more needs to be done. */
                continue;
                }
            else
                {
                /* End of line reached, perform word wrap. */
                XINT xwc; /* Backspace counter. */

                /* Only wrap if the current word is less than 50 characters
                   long.  Otherwise it can be slow and annoying to the user. */
                if (wwc < 50)
                    {
                    /* Backspace out the last word. */
                    for (xwc = 0; xwc < wwc; xwc++)
                        {
                        od_disp_str("\b \b");
                        }
                    }
                /* Jump to the next line. */
                od_disp_str("\r\n");
                /* Redisplay the last word if it's not too long. */
                if (wwc < 50)
                    {
                    od_disp_str(ww);
                    }
                /* Clear the word wrap buffer and reset the counter. */
                memset(ww, 0, 81);
                wwc = 0;
                continue;
                }
            }
        }
/* Timeslicing is only done under DOS. */
#if !defined(__OS2__) && !defined(__WIN32__) && !defined(__unix__)
	else
		{
        /* Timeslice if a key wasn't pressed and if the clock tick has
           changed.  Waiting for the next clock tick prevents TOP from
           completely surrendering control of the CPU, which would make
           input hideously slow. */
        if (!key || _clock_tick() != clktick)
	        {
            od_sleep(0);
        	}
        }
#endif
    }

}