Annotation of sbbs/sbbs2/sdk/xsdk.c, revision 1.1.1.1

1.1       root        1: /* XSDK.C */
                      2: 
                      3: /****************************************************************************/
                      4: /*                     Synchronet External Program Software Development Kit                    */
                      5: /*                                                     1995 Digital Dynamics                                                   */
                      6: /****************************************************************************/
                      7: 
                      8: /****************************************************************************/
                      9: /* This source code file is public domain and may be modified, compiled        */
                     10: /* distributed, or used in any way, in part or whole for any purposes          */
                     11: /* without the consent or notification of Digital Dynamics.                            */
                     12: /*                                                                                                                                                     */
                     13: /* We only request that you display to the user, at some point, in your        */
                     14: /* program the character "XSDK" and the version number.                     */
                     15: /* example: bprintf("XSDK v%s",xsdk_ver);                                   */
                     16: /****************************************************************************/
                     17: 
                     18: /****************************************************************************/
                     19: /* The source code for two external programs developed by Digital Dynamics     */
                     20: /* using XSDK (Synchronet Blackjack [SBJ] and Synchronet BBS List [SBL])       */
                     21: /* are available to the public domain as examples of how to implement the      */
                     22: /* functions and variables included in this software development kit.          */
                     23: /****************************************************************************/
                     24: 
                     25: /****************************************************/
                     26: /* For use with Borland/Turbo C and C++ compilers.     */
                     27: /* Tabstop set to 4.                                                           */
                     28: /****************************************************/
                     29: 
                     30: /***************************** Revision History *****************************\
                     31: 
                     32:                        Initial version for use with Synchronet v1a r6
                     33:        1.0�    
                     34:                        Added bgotoxy() macro
                     35:                        Added mnehigh and mnelow vars for control of the mnemonic colors
                     36:                        Added sys_nodes and node_num variables to xtrn_sdk.c
                     37:                        Added MAX_NODES to xtrn_sdk.h
                     38:                        Added printfile() function to xtrn_sdk.c
                     39:                        Added rputs() (Raw put string)
                     40:                        Added getstr() (Get string)
                     41:                        Added redrwstr() (Redraw string)
                     42:                        Added stripattr() (String attributes)
                     43:                        Added sys_op var and the reading from the xtrn.dat
                     44:                        Removed user_min and the reading from the xtrn.dat
                     45:                        Changed read_xtrn_dat() to initdata()
                     46:                        Added ctrl-break handler to xtrn_sdk
                     47:                        Changed xtrn.dat format (again), adding system operator,
                     48:                                guru name, user ml, tl, birthdate and sex.
                     49:                        Added username() function
                     50:                        Renamed xtrn_sdk.* to xsdk.* and xtrnvars.c to xsdkvars.c
                     51:                                and xtrndefs.h to xsdkdefs.h
                     52:                        Added fexist() function
                     53:        1.0
                     54:                        Ctrl-p is now switched into ctrl-^ by SBBS
                     55:                        Fixed relative data_dir bug in username()
                     56:        1.01
                     57:                        Added flength() function and lowered disk activity
                     58:                        Lowered MAX_CARDS from 20 to 10 and made the re-shuffling happen
                     59:                                less often.
                     60:        1.02
                     61:                        Fixed bug in attr() for monochrome users
                     62:        1.03
                     63:                        Made warning and timeout times variables (sec_warn and sec_timeout)
                     64:                        Added SYSOP macro
                     65:                        Made it so sysop won't get timeout
                     66:                        Added user's phone number to XTRN.DAT
                     67:                        Added modem and com port information to XTRN.DAT
                     68:                        Added ahtoul function
                     69:                        Changed getstr commands Ctrl-L to Ctrl-R and Ctrl-P to Ctrl-\
                     70:        1.04
                     71:                        Added intercommunication between the external programs and users
                     72:                        on the BBS or other external programs written with XSDK.
                     73:                        Added rprintf() function
                     74:                        Made many changes to getstr() function
                     75:        2.00
                     76:                        Added DESQview awareness
                     77:                        Removed difftime() function calls completely
                     78:                        Added ungetkey() function
                     79:                        Added memory address of last modem status register for com routines
                     80:                                so we can track DCD incase user hangs up.
                     81:                        Added checkline function that does the checking of DCD.
                     82:                        Added new bug-free fdelay() routine to replace TC's delay() that
                     83:                                crashes multi-taskers such as DESQview and Windows
                     84:        2.01
                     85:                        Added external program name access for user listings.
                     86:                        Added last node to send message to remembering and defaulting.
                     87:                        Added MALLOC and FREE macros for memory model non-specific memory
                     88:                                allocation.
                     89:        2.02
                     90:                        Added INTRSBBS.DAT support for Synchronet shrinking to run programs
                     91:                                written with XSDK (new with v1b rev 01).
                     92:                        Added user's main flags, transfer flags, exemptions, and
                     93:                                restrictions to XTRN.DAT
                     94:                        Added support for the NODE_PAGE action (paging for private chat)
                     95:                                when listing nodes (printnodedat()).
                     96:                        Added user expiration date support to XTRN.DAT
                     97:        2.03
                     98:                        Fixed bug with com_base variable being messed up.
                     99:                        New messaging system supported (for v1b r2 and higher)
                    100:                                (putnmsg and getnmsg functions).
                    101:        2.10
                    102:                        Added support for file retrieving node status display.
                    103:                        NOPEN collision notice only appears after 25 retries.
                    104:        2.11
                    105:                        Changed getnmsg function to not use IXB files.
                    106:                        Changed getsmsg function to not re-open for truncate.
                    107:                        Added user address, location, and zip/postal code suppport.
                    108:                        Added support for local arrow keys, home, end, ins, and del.
                    109:                        Remote keys ^] (back one space) and ^BkSpc (del) supported now.
                    110:                        Added support for high-bit Ctrl-A codes (for cursor positioning)
                    111:                        Removed file locking check - slowed down initialization sometimes.
                    112:                        Change user_ml to user_level, removed user_tl, changed user_mf to
                    113:                                user_flags1, changed user_tf to user_flags2, and added
                    114:                                user_flags3 and user_flags4.
                    115:                        cls() now updates lncntr like it should have.
                    116:                        Added ctrl-break handler so that users can abort printfile()
                    117:                        If a ctrl-c is received by inkey, the aborted flag is set.
                    118:                        Removed fdelay from XSDK and replaced with mswait for better
                    119:                                multitasker performance
                    120:        2.20
                    121:                        New mswait that support OS2/Windows, DOS Idle, and non-DV modes.
                    122:                        XTRN.DAT passes mode of mswait configured in node setup.
                    123:        2.21
                    124:                        Added user's real name/company name (user_realname) to XTRN.DAT
                    125:        2.22
                    126:                        Added usernumber() function to get user number from a user name.
                    127:        2.23
                    128:                        DTE rate (com_rate) now a ulong (instead of uint) to allow 115.2K
                    129:        2.24
                    130:                        New K_AUTODEL mode for getstr() function, to be used in conjunction
                    131:                                with the K_EDIT mode. Makes overwriting existing strings very
                    132:                                easy for users.
                    133:                        Supports intelligent timeslice APIs while waiting for a key with
                    134:                                getkey() and with getstr() if K_LOWPRIO mode is used.
                    135:                        Hitting Ctrl-C sets the 'aborted' variable to 1.
                    136:                        Time zone and daylight savings automatically initialized to 0.
                    137:                        Modem strings up to 63 chars in XTRN.DAT now supported.
                    138:                        Fixed 10 character zip code bug in XSDKVARS.C.
                    139:                        Node directories (node_dir) up to 127 chars now supported.
                    140:                        nopen() can now open DENYNONE if passed access O_DENYNONE.
                    141:        2.30
                    142:                        Added support for the following Ctrl-A codes: ;,.<>[]A
                    143:                        Changed definitions of TAB, SP, etc. to hex
                    144:        2.31
                    145:                        C restriction disallows users to use Ctrl-P.
                    146:                        T exemption disables "Time's up" message.
                    147:                        Added center() function for outputting centered lines of text.
                    148:                        Added auto-pause to cls() and outchar() functions when clearing
                    149:                                the screen and lncntr is greater than 1
                    150:                        Changed bstrlen() to not count control characters (CR,LF,TAB,etc)
                    151:                        XSDK is now Watcom C++ compatible (although SBJ.C and SBL.C aren't)
                    152:                        XSDK.H is now *.CPP compatible
                    153:                        Added support for Ctrl-AQ (reset pause) and Ctrl-AZ (premature EOF)
                    154:        2.32
                    155:                        Change bstrlen(char *str) to bstrlen(uchar *str)
                    156:                        Fixed bug in getstr() when word-wrapping a line that contains
                    157:                                ctrl-a codes and the input string did not begin at column 1.
                    158:                        Added user_dce variable (initialized by initdata from XTRN.DAT)
                    159:                        Fixed printnodedat() to not show Waiting for call (M)
                    160:                        Fixed typo in C restriction Ctrl-P message.
                    161:                        Moved call of checkline() in getkey() to immediately abort when
                    162:                                user hangs-up, even when keys are in the input buffer.
                    163:                        Added setmode() call to initdata() to set stderr to binary mode
                    164:                        Changed putchar() to write() in outchar() to elminate LF to CRLF
                    165:                                expansion
                    166:        2.33
                    167:                        Improved cls() routine for auto-pause feature.
                    168:                        Added get_term() automatic RIP and WIP terminal detection function.
                    169:        2.34
                    170:                        Added exec_dir, text_dir, and temp_dir variables to XTRN.DAT
                    171:                                format and initdata() function.
                    172:                        Added _fullpath() calls to initdata() to fix dir paths.
                    173:                        Added sys_id (QWK ID) to XTRN.DAT format and initdat() func.
                    174:                        Added node_misc to XTRN.DAT format and initdata() function.
                    175:                        If NM_LOWPRIO (low priority string input) is toggled on in
                    176:                                node_misc, then time-slices are always given up during input.
                    177:                        XSDK is now Symantec C++ compatible
                    178:        2.40
                    179:                        node_misc was being read as a decimal number (it's stored in
                    180:                                the XTRN.DAT as hex), thus causing time-slice APIs to not
                    181:                                function correctly.
                    182:        2.41
                    183:                        Ctrl-T is now intercepted by inkey() and displays the time the
                    184:                                program was launched, the current time, time used, and time
                    185:                                left (similar to SBBS).
                    186:                        Users are now warned of their last 5 minutes available (like SBBS).
                    187:        2.42
                    188: 
                    189: \****************************************************************************/
                    190: 
                    191: #include "xsdk.h"
                    192: 
                    193: char *xsdk_ver="2.42";
                    194: 
                    195: #ifdef __TURBOC__
                    196: extern long timezone=0L;
                    197: extern daylight=0;
                    198: #endif
                    199: 
                    200: #ifdef __SC__
                    201: #include <disp.h>
                    202: short wherey(void);
                    203: void clrscr(void);
                    204: #endif  
                    205: 
                    206: 
                    207: /****************************************************************************/
                    208: /* This allows users to abort the listing of text by using Ctrl-C           */
                    209: /****************************************************************************/
                    210: int cbreakh(void)      /* ctrl-break handler */
                    211: {
                    212: aborted=1;
                    213: return(1);             /* 1 to continue, 0 to abort */
                    214: }
                    215: 
                    216: /****************************************************************************/
                    217: /* Performs printf() using bbs bputs function                                                          */
                    218: /****************************************************************************/
                    219: int bprintf(char *fmt, ...)
                    220: {
                    221:        va_list argptr;
                    222:        char sbuf[1024];
                    223:        int chcount;
                    224: 
                    225: va_start(argptr,fmt);
                    226: chcount=vsprintf(sbuf,fmt,argptr);
                    227: va_end(argptr);
                    228: bputs(sbuf);
                    229: return(chcount);
                    230: }
                    231: 
                    232: /****************************************************************************/
                    233: /* Performs printf() using bbs rputs function                                                          */
                    234: /****************************************************************************/
                    235: int rprintf(char *fmt, ...)
                    236: {
                    237:        va_list argptr;
                    238:        char sbuf[1024];
                    239:        int chcount;
                    240: 
                    241: va_start(argptr,fmt);
                    242: chcount=vsprintf(sbuf,fmt,argptr);
                    243: va_end(argptr);
                    244: rputs(sbuf);
                    245: return(chcount);
                    246: }
                    247: 
                    248: /****************************************************************************/
                    249: /* Outputs a NULL terminated string locally and remotely (if applicable)       */
                    250: /****************************************************************************/
                    251: void bputs(char *str)
                    252: {
                    253:        ulong l=0;
                    254: 
                    255: while(str[l] && !aborted) {
                    256:        if(str[l]==1) {                         /* ctrl-a */
                    257:                ctrl_a(str[++l]);               /* skip the ctrl-a */
                    258:                if(str[l]=='Z')         /* Ctrl-AZ marks premature end of file */
                    259:                        break;
                    260:                l++; }                                  /* skip the attribute code */
                    261:        else
                    262:                outchar(str[l++]); }
                    263: }
                    264: 
                    265: /****************************************************************************/
                    266: /* Outputs a NULL terminated string locally and remotely (if applicable)       */
                    267: /* Does not process ctrl-a codes (raw output)                                                          */
                    268: /* Max length of str is 64 kbytes                                                                                      */
                    269: /****************************************************************************/
                    270: void rputs(char *str)
                    271: {
                    272:        ulong l=0;
                    273: 
                    274: while(str[l])
                    275:        outchar(str[l++]);
                    276: }
                    277: 
                    278: /****************************************************************************/
                    279: /* Returns the number of characters in 'str' not counting ctrl-ax codes                */
                    280: /* or the null terminator                                                                                                      */
                    281: /****************************************************************************/
                    282: int bstrlen(uchar *str)
                    283: {
                    284:        int i=0;
                    285: 
                    286: while(*str) {
                    287:        if(*str<SP) {   /* ctrl char */
                    288:                if(*str==1) /* ctrl-A */
                    289:                        str++;
                    290:                else if(*str!=CR && *str!=LF && *str!=FF)
                    291:                        i++; }
                    292:        else
                    293:                i++;
                    294:        if(!(*str))
                    295:                break;
                    296:        str++; }
                    297: return(i);
                    298: }
                    299: 
                    300: /****************************************************************************/
                    301: /* Outputs the string 'str' centered for an 80 column display               */
                    302: /* Automatically appends "\r\n" to output                                   */
                    303: /****************************************************************************/
                    304: void center(char *str)
                    305: {
                    306:         int i,j;
                    307: 
                    308: j=bstrlen(str);
                    309: for(i=0;i<(80-j)/2;i++)
                    310:        outchar(SP);
                    311: bputs(str);
                    312: }
                    313: 
                    314: /****************************************************************************/
                    315: /* Outputs one character to the screen. Handles, pause, saving and                     */
                    316: /* restoring lines, etc.                                                                                                       */
                    317: /****************************************************************************/
                    318: void outchar(char ch)
                    319: {
                    320: 
                    321: write(fileno(con_fp),&ch,1);
                    322: 
                    323: if(ch==LF) {
                    324:        lncntr++;
                    325:        lbuflen=0;
                    326:        tos=0; }
                    327: else if(ch==FF) {
                    328:        if(lncntr>1) {
                    329:                lncntr=0;
                    330:                CRLF;
                    331:                pause(); }
                    332:        lncntr=0;
                    333:        lbuflen=0;
                    334:        tos=1; }
                    335: else if(ch==BS) {
                    336:        if(lbuflen)
                    337:                lbuflen--; }
                    338: else {
                    339:        if(!lbuflen)
                    340:                latr=curatr;
                    341:        if(lbuflen>=LINE_BUFSIZE) lbuflen=0;
                    342:        lbuf[lbuflen++]=ch; }
                    343: if(lncntr==user_rows-1) {
                    344:        lncntr=0;
                    345:     pause(); }
                    346: }
                    347: 
                    348: /****************************************************************************/
                    349: /* Prints PAUSE message and waits for a key stoke                                                      */
                    350: /****************************************************************************/
                    351: void pause(void)
                    352: {
                    353:        uchar tempattrs=curatr,*msg="\1_\1r\1h[Hit a key] ";
                    354:        int i,j;
                    355: 
                    356: lncntr=0;
                    357: bputs(msg);
                    358: j=bstrlen(msg);
                    359: getkey(0);
                    360: for(i=0;i<j;i++)
                    361:        bputs("\b \b");
                    362: attr(tempattrs);
                    363: }
                    364: 
                    365: /****************************************************************************/
                    366: /* Prompts user for Y or N (yes or no) and CR is interpreted as a Y                    */
                    367: /* Returns 1 for Y or 0 for N                                                                                          */
                    368: /* Called from quite a few places                                                                                      */
                    369: /****************************************************************************/
                    370: char yesno(char *str)
                    371: {
                    372:        char ch;
                    373: 
                    374: bprintf("\1_\1b\1h%s (Y/n) ? \1w",str);
                    375: while(1) {
                    376:        ch=getkey(K_UPPER);
                    377:        if(ch=='Y' || ch==CR) {
                    378:                bputs("Yes\r\n");
                    379:                return(1); }
                    380:        if(ch=='N' || aborted) {
                    381:                bputs("No\r\n");
                    382:                return(0); } }
                    383: }
                    384: 
                    385: /****************************************************************************/
                    386: /* Prompts user for N or Y (no or yes) and CR is interpreted as a N                    */
                    387: /* Returns 1 for N or 0 for Y                                                                                          */
                    388: /* Called from quite a few places                                                                                      */
                    389: /****************************************************************************/
                    390: char noyes(char *str)
                    391: {
                    392:        char ch;
                    393: 
                    394: bprintf("\1_\1b\1h%s (y/N) ? \1w",str);
                    395: while(1) {
                    396:        ch=getkey(K_UPPER);
                    397:        if(ch=='N' || ch==CR || aborted) {
                    398:                bputs("No\r\n");
                    399:                return(1); }
                    400:        if(ch=='Y') {
                    401:                bputs("Yes\r\n");
                    402:                return(0); } }
                    403: }
                    404: 
                    405: /****************************************************************************/
                    406: /* Outputs a string highlighting characters preceeded by a tilde with the      */
                    407: /* color specified in mnehigh and the rest of the line is in color mnelow.     */
                    408: /* If the user doesn't have ANSI, it puts the character following the tilde */
                    409: /* in parenthesis.                                                                                                                     */
                    410: /****************************************************************************/
                    411: void mnemonics(char *str)
                    412: {
                    413:        long l;
                    414: 
                    415: attr(mnelow);
                    416: l=0L;
                    417: while(str[l]) {
                    418:        if(str[l]=='~' && str[l+1]) {
                    419:                if(!(user_misc&ANSI))
                    420:                        outchar('(');
                    421:                l++;
                    422:                attr(mnehigh);
                    423:                outchar(str[l]);
                    424:                l++;
                    425:                if(!(user_misc&ANSI))
                    426:                        outchar(')');
                    427:                attr(mnelow); }
                    428:        else
                    429:                outchar(str[l++]); }
                    430: attr(LIGHTGRAY);
                    431: }
                    432: 
                    433: /****************************************************************************/
                    434: /* If a key has been pressed, the ASCII code is returned. If not, 0 is         */
                    435: /* returned. Ctrl-P and Ctrl-U are intercepted here.                                           */
                    436: /****************************************************************************/
                    437: char inkey(int mode)
                    438: {
                    439:        static in_ctrl_p;
                    440:        uchar ch=0,hour,min,sec;
                    441:        ushort tleft;
                    442:        uint i;
                    443:        time_t now;
                    444: 
                    445: if(keybufbot!=keybuftop) {
                    446:        ch=keybuf[keybufbot++];
                    447:        if(keybufbot==KEY_BUFSIZE)
                    448:                keybufbot=0; }
                    449: else if(_bios_keybrd(1)) {
                    450:        i=_bios_keybrd(0);
                    451:        if(i&0xff)
                    452:                ch=i&0xff;
                    453:        else {                                  /* Local Alt or Function key hit */
                    454:                i>>=8;
                    455:                switch(i) {
                    456:                        case 0x47:      /* Home - Same as Ctrl-B */
                    457:                                return(2);      /* ctrl-b beginning of line */
                    458:                        case 0x4b:              /* Left Arrow - same as ctrl-] */
                    459:                                return(0x1d);
                    460:                        case 0x4d:              /* Right Arrow - same as ctrl-f */
                    461:                                return(6);
                    462:                        case 0x48:              /* Up arrow - same as ctrl-^ */
                    463:                                return(0x1e);
                    464:                        case 0x50:              /* Down arrow - same as CR */
                    465:                                return(CR);
                    466:                        case 0x4f:        /* End          - same as Ctrl-E */
                    467:                 return(5);  /* ctrl-e - end of line */
                    468:                        case 0x52:      /* Insert */
                    469:                                return(0x1f);   /* ctrl-minus - insert mode */
                    470:                        case 0x53:      /* Delete */
                    471:                 return(0x7f);   /* ctrl-bkspc - del cur char */
                    472:                        }
                    473:                return(0); } }
                    474: 
                    475: if(ch==0x10 || ch==0x1e) {     /* Ctrl-P or Ctrl-^ */
                    476:        if(in_ctrl_p || !ctrl_dir[0])   /* keep from being recursive */
                    477:                return(0);
                    478:        in_ctrl_p=1;
                    479:        SAVELINE;
                    480:        CRLF;
                    481:        nodemsg();
                    482:        CRLF;
                    483:        RESTORELINE;
                    484:        lncntr=0;
                    485:        in_ctrl_p=0;
                    486:        return(0); }
                    487: 
                    488: if(ch==20) { /* Ctrl-T Time left online */
                    489:        SAVELINE;
                    490:        attr(LIGHTGRAY);
                    491:        now=time(NULL);
                    492:        checktimeleft();
                    493:        CRLF;
                    494:        bprintf("\r\nStart     : %.24s",ctime(&starttime));
                    495:        bprintf("\r\nNow       : %.24s",ctime(&now));
                    496:        i=now-starttime;
                    497:        hour=(i/60)/60;
                    498:        min=(i/60)-(hour*60);
                    499:        sec=i-((min+(hour*60))*60);
                    500:        bprintf("\r\nTime Used : %02u:%02u:%02u",hour,min,sec);
                    501:        tleft=timeleft-(now-starttime);
                    502:        hour=(tleft/60)/60;
                    503:        min=(tleft/60)-(hour*60);
                    504:        sec=tleft-((min+(hour*60))*60);
                    505:        bprintf("\r\nTime Left : %02u:%02u:%02u\r\n\r\n",hour,min,sec);
                    506:        RESTORELINE;
                    507:        lncntr=0;
                    508:        return(0); }
                    509: 
                    510: if(ch==21) { /* Ctrl-U Users online */
                    511:        if(!ctrl_dir[0])
                    512:                return(0);
                    513:        SAVELINE;
                    514:        CRLF;
                    515:        whos_online(1);
                    516:        CRLF;
                    517:        RESTORELINE;
                    518:        lncntr=0;
                    519:     return(0); }
                    520: 
                    521: if(ch==3)
                    522:        aborted=1;
                    523: else if(aborted)
                    524:        ch=3;
                    525: 
                    526: if(!ch && (!(mode&K_GETSTR) || mode&K_LOWPRIO|| node_misc&NM_LOWPRIO))
                    527:        mswait(0);
                    528: return(ch);
                    529: }
                    530: 
                    531: /****************************************************************************/
                    532: /* Waits for remote or local user to hit a key. Inactivity timer is checked */
                    533: /* and hangs up if inactive for 4 minutes. Returns key hit, or uppercase of */
                    534: /* key hit if mode&K_UPPER or key out of KEY BUFFER. Does not print key.       */
                    535: /****************************************************************************/
                    536: char getkey(int mode)
                    537: {
                    538:        char ch,warn=0;
                    539:        ushort tleft;
                    540:        time_t timeout,now;
                    541: 
                    542: aborted=lncntr=0;
                    543: timeout=time(NULL);
                    544: do {
                    545:        checkline();
                    546:        ch=inkey(mode);
                    547:        now=time(NULL);
                    548:        if(ch) {
                    549:                if(mode&K_NUMBER && isprint(ch) && !isdigit(ch))
                    550:                        continue;
                    551:                if(mode&K_ALPHA && isprint(ch) && !isalpha(ch))
                    552:                        continue;
                    553:                if(ch==LF) continue;
                    554:                if(mode&K_UPPER)
                    555:                        return(toupper(ch));
                    556:                return(ch); }
                    557:        checktimeleft();
                    558: 
                    559:        tleft=timeleft-(now-starttime);
                    560:        if((tleft/60)<(5-timeleft_warn)) {      /* Running out of time warning */
                    561:                timeleft_warn=5-(tleft/60);
                    562:         SAVELINE;
                    563:                bprintf("&n&h\r\n\7\r\nYou only have &r&i%u&n&h minute%s "
                    564:                        "left.\r\n\r\n"
                    565:                        ,((ushort)tleft/60)+1,(tleft/60) ? "s" : "");
                    566:         RESTORELINE; }
                    567: 
                    568:        if(now-timeout>=sec_warn && !warn)              /* Inactivity warning */
                    569:                for(warn=0;warn<5;warn++)
                    570:                        outchar(7);
                    571:        } while(now-timeout<sec_timeout);
                    572: bputs("\r\nInactive too long.\r\n");
                    573: exit(0);
                    574: return(0);     /* never gets here, but makes compiler happy */
                    575: }
                    576: 
                    577: /****************************************************************************/
                    578: /* If remote user, checks DCD to see if user has hung up or not.                       */
                    579: /****************************************************************************/
                    580: void checkline(void)
                    581: {
                    582: if(com_port && !((*msr)&DCD)) exit(0);
                    583: }
                    584: 
                    585: /****************************************************************************/
                    586: /* Waits for remote or local user to hit a key that is contained inside str.*/
                    587: /* 'str' should contain uppercase characters only. When a valid key is hit, */
                    588: /* it is echoed (upper case) and is the return value.                                          */
                    589: /* If max is non-zero and a number is hit that is not in str, it will be       */
                    590: /* returned with the high bit set. If the return of this function has the      */
                    591: /* high bit set (&0x8000), just flip the bit (^0x8000) to get the number.      */
                    592: /****************************************************************************/
                    593: int getkeys(char *str,int max)
                    594: {
                    595:        uchar ch,n=0;
                    596:        int i=0;
                    597: 
                    598: strupr(str);
                    599: while(!aborted) {
                    600:        ch=getkey(K_UPPER);
                    601:        if(max && ch>0x7f)      /* extended ascii chars are digits to isdigit() */
                    602:                continue;
                    603:        if(ch && !n && (strchr(str,ch))) {      /* return character if in string */
                    604:                outchar(ch);
                    605:                attr(LIGHTGRAY);
                    606:                CRLF;
                    607:                return(ch); }
                    608:        if(ch==CR && max) {             /* return 0 if no number */
                    609:                attr(LIGHTGRAY);
                    610:                CRLF;
                    611:                if(n)
                    612:                        return(i|0x8000);               /* return number plus high bit */
                    613:                return(0); }
                    614:        if(ch==BS && n) {
                    615:                bputs("\b \b");
                    616:                i/=10;
                    617:                n--; }
                    618:        else if(max && isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
                    619:                i*=10;
                    620:                n++;
                    621:                i+=ch&0xf;
                    622:                outchar(ch);
                    623:                if(i*10>max) {
                    624:                        attr(LIGHTGRAY);
                    625:                        CRLF;
                    626:                        return(i|0x8000); } } }
                    627: return(0);
                    628: }
                    629: 
                    630: /****************************************************************************/
                    631: /* Hot keyed number input routine.                                                                                     */
                    632: /****************************************************************************/
                    633: int getnum(int max)
                    634: {
                    635:        uchar ch,n=0;
                    636:        int i=0;
                    637: 
                    638: while(1) {
                    639:        ch=getkey(K_UPPER);
                    640:        if(ch>0x7f)
                    641:                continue;
                    642:        if(ch=='Q') {
                    643:                outchar('Q');
                    644:                CRLF;
                    645:                return(-1); }
                    646:        else if(ch==3) {                /* ctrl-c */
                    647:                CRLF;
                    648:                return(-1); }
                    649:        else if(ch==CR) {
                    650:                CRLF;
                    651:                return(i); }
                    652:        else if(ch==BS && n) {
                    653:                bputs("\b \b");
                    654:                i/=10;
                    655:                n--; }
                    656:        else if(isdigit(ch) && (i*10)+(ch&0xf)<=max && (ch!='0' || n)) {
                    657:                i*=10;
                    658:                n++;
                    659:                i+=ch&0xf;
                    660:                outchar(ch);
                    661:                if(i*10>max) {
                    662:                        CRLF;
                    663:                        return(i); } } }
                    664: return(-1);
                    665: }
                    666: 
                    667: /****************************************************************************/
                    668: /* Waits for remote or local user to input a CR terminated string. 'length' */
                    669: /* is the maximum number of characters that getstr will allow the user to      */
                    670: /* input into the string. 'mode' specifies upper case characters are echoed */
                    671: /* or wordwrap or if in message input (^A sequences allowed). ^W backspaces */
                    672: /* a word, ^X backspaces a line, ^Gs, BSs, TABs are processed, LFs ignored. */
                    673: /* ^N non-destructive BS, ^V center line. Valid keys are echoed.                       */
                    674: /****************************************************************************/
                    675: int getstr(char *strout, int maxlen, int mode)
                    676: {
                    677:        int i,l,x,z;    /* i=current position, l=length, j=printed chars */
                    678:                                        /* x&z=misc */
                    679:        uchar ch,str1[256],str2[256],ins=0,atr;
                    680: 
                    681: if(mode&K_LINE && user_misc&ANSI) {
                    682:        attr(LIGHTGRAY|HIGH|(BLUE<<4));  /* white on blue */
                    683:        for(i=0;i<maxlen;i++)
                    684:                outchar(SP);
                    685:        bprintf("\x1b[%dD",maxlen); }
                    686: i=l=0; /* i=total number of chars, j=number of printable chars */
                    687: if(wordwrap[0]) {
                    688:        strcpy(str1,wordwrap);
                    689:        wordwrap[0]=0; }
                    690: else str1[0]=0;
                    691: if(mode&K_EDIT)
                    692:        strcat(str1,strout);
                    693: if(strlen(str1)>maxlen)
                    694:        str1[maxlen]=0;
                    695: atr=curatr;
                    696: if(mode&K_AUTODEL && str1[0])
                    697:        attr(BLUE|(LIGHTGRAY<<4));
                    698: rputs(str1);
                    699: if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)) && user_misc&ANSI)
                    700:        bputs("\x1b[K");  /* destroy to eol */
                    701: i=l=strlen(str1);
                    702: 
                    703: if(mode&K_AUTODEL && str1[0]) {
                    704:        ch=getkey(mode);
                    705:     attr(atr);
                    706:     if(isprint(ch) || ch==0x7f) {
                    707:         for(i=0;i<l;i++)
                    708:             bputs("\b \b");
                    709:         i=l=0; }
                    710:     else {
                    711:         for(i=0;i<l;i++)
                    712:             outchar(BS);
                    713:         rputs(str1);
                    714:         i=l; }
                    715:        if(ch!=SP && ch!=TAB)
                    716:         ungetkey(ch); }
                    717: 
                    718: while((ch=getkey(mode|K_GETSTR))!=CR && !aborted) {
                    719:        switch(ch) {
                    720:                case 1: /* Ctrl-A for ANSI */
                    721:                        if(!(mode&K_MSG) || i>maxlen-3)
                    722:                                break;
                    723:             if(ins) {
                    724:                                if(l<maxlen)
                    725:                     l++;
                    726:                                for(x=l;x>i;x--)
                    727:                                        str1[x]=str1[x-1];
                    728:                                rprintf("%.*s",l-i,str1+i);
                    729:                                rprintf("\x1b[%dD",l-i);
                    730:                                if(i==maxlen-1)
                    731:                                        ins=0; }
                    732:                        outchar(str1[i++]=1);
                    733:                        break;
                    734:                case 2: /* Ctrl-B Beginning of Line */
                    735:                        if(user_misc&ANSI && i) {
                    736:                                bprintf("\x1b[%dD",i);
                    737:                                i=0; }
                    738:                        break;
                    739:                case 4: /* Ctrl-D Delete word right */
                    740:                if(i<l) {
                    741:                                x=i;
                    742:                                while(x<l && str1[x]!=SP) {
                    743:                                        outchar(SP);
                    744:                                        x++; }
                    745:                                while(x<l && str1[x]==SP) {
                    746:                                        outchar(SP);
                    747:                                        x++; }
                    748:                                bprintf("\x1b[%dD",x-i);   /* move cursor back */
                    749:                                z=i;
                    750:                                while(z<l-(x-i))  {             /* move chars in string */
                    751:                                        outchar(str1[z]=str1[z+(x-i)]);
                    752:                                        z++; }
                    753:                                while(z<l) {                                    /* write over extra chars */
                    754:                                        outchar(SP);
                    755:                                        z++; }
                    756:                                bprintf("\x1b[%dD",z-i);
                    757:                                l-=x-i; }                                               /* l=new length */
                    758:                        break;
                    759:                case 5: /* Ctrl-E End of line */
                    760:                        if(user_misc&ANSI && i<l) {
                    761:                                bprintf("\x1b[%dC",l-i);  /* move cursor right one */
                    762:                                i=l; }
                    763:                        break;
                    764:                case 6: /* Ctrl-F move cursor forewards */
                    765:                        if(i<l && (user_misc&ANSI)) {
                    766:                                bputs("\x1b[C");   /* move cursor right one */
                    767:                                i++; }
                    768:                        break;
                    769:                case 7:
                    770:                        if(!(mode&K_MSG))
                    771:                                break;
                    772:              if(ins) {
                    773:                                if(l<maxlen)
                    774:                     l++;
                    775:                                for(x=l;x>i;x--)
                    776:                                        str1[x]=str1[x-1];
                    777:                                if(i==maxlen-1)
                    778:                                        ins=0; }
                    779:                         if(i<maxlen) {
                    780:                                str1[i++]=7;
                    781:                                outchar(7); }
                    782:                         break;
                    783:                case 14:        /* Ctrl-N Next word */
                    784:                        if(i<l && (user_misc&ANSI)) {
                    785:                                x=i;
                    786:                                while(str1[i]!=SP && i<l)
                    787:                                        i++;
                    788:                                while(str1[i]==SP && i<l)
                    789:                                        i++;
                    790:                                bprintf("\x1b[%dC",i-x); }
                    791:                        break;
                    792:                case 0x1c:        /* Ctrl-\ Previous word */
                    793:                        if(i && (user_misc&ANSI)) {
                    794:                                x=i;
                    795:                                while(str1[i-1]==SP && i)
                    796:                                        i--;
                    797:                                while(str1[i-1]!=SP && i)
                    798:                                        i--;
                    799:                                bprintf("\x1b[%dD",x-i); }
                    800:                        break;
                    801:                case 18:        /* Ctrl-R Redraw Line */
                    802:             redrwstr(str1,i,l,0);
                    803:             break;
                    804:                case TAB:
                    805:                        if(!(i%TABSIZE)) {
                    806:                if(ins) {
                    807:                                        if(l<maxlen)
                    808:                         l++;
                    809:                                        for(x=l;x>i;x--)
                    810:                                                str1[x]=str1[x-1];
                    811:                                        if(i==maxlen-1)
                    812:                                                ins=0; }
                    813:                                str1[i++]=SP;
                    814:                                outchar(SP); }
                    815:                        while(i<maxlen && i%TABSIZE) {
                    816:                if(ins) {
                    817:                                        if(l<maxlen)
                    818:                         l++;
                    819:                                        for(x=l;x>i;x--)
                    820:                                                str1[x]=str1[x-1];
                    821:                                        if(i==maxlen-1)
                    822:                                                ins=0; }
                    823:                                str1[i++]=SP;
                    824:                                outchar(SP); }
                    825:                        if(ins)
                    826:                                redrwstr(str1,i,l,0);
                    827:                        break;
                    828:                case BS:
                    829:                        if(!i)
                    830:                                break;
                    831:                        i--;
                    832:                        l--;
                    833:                        if(i!=l) {                              /* Deleting char in middle of line */
                    834:                                outchar(BS);
                    835:                                z=i;
                    836:                                while(z<l)      {               /* move the characters in the line */
                    837:                                        outchar(str1[z]=str1[z+1]);
                    838:                                        z++; }
                    839:                                outchar(SP);            /* write over the last char */
                    840:                                bprintf("\x1b[%dD",(l-i)+1); }
                    841:                        else
                    842:                                bputs("\b \b");
                    843:                        break;
                    844:                case 22:        /* Ctrl-V       Center line */
                    845:                        str1[l]=0;
                    846:                        l=bstrlen(str1);
                    847:                        for(x=0;x<(maxlen-l)/2;x++)
                    848:                                str2[x]=SP;
                    849:                        str2[x]=0;
                    850:                        strcat(str2,str1);
                    851:                        strcpy(strout,str2);
                    852:                        l=strlen(strout);
                    853:                        if(mode&K_MSG)
                    854:                                redrwstr(strout,i,l,K_MSG);
                    855:                        else {
                    856:                                while(i--)
                    857:                                        bputs("\b");
                    858:                                bputs(strout);
                    859:                                if(mode&K_LINE)
                    860:                                        attr(LIGHTGRAY); }
                    861:                        CRLF;
                    862:                        return(l);
                    863:                case 23:        /* Ctrl-W   Delete word left */
                    864:                        if(i<l) {
                    865:                                x=i;                                                    /* x=original offset */
                    866:                                while(i && str1[i-1]==SP) {
                    867:                                        outchar(BS);
                    868:                                        i--; }
                    869:                                while(i && str1[i-1]!=SP) {
                    870:                                        outchar(BS);
                    871:                                        i--; }
                    872:                                z=i;                            /* i=z=new offset */
                    873:                                while(z<l-(x-i))  {             /* move chars in string */
                    874:                                        outchar(str1[z]=str1[z+(x-i)]);
                    875:                                        z++; }
                    876:                                while(z<l) {                                    /* write over extra chars */
                    877:                                        outchar(SP);
                    878:                                        z++; }
                    879:                                bprintf("\x1b[%dD",z-i);        /* back to new x corridnant */
                    880:                                l-=x-i; }                                               /* l=new length */
                    881:                        else {
                    882:                while(i && str1[i-1]==SP) {
                    883:                                        i--;
                    884:                                        l--;
                    885:                                        bputs("\b \b"); }
                    886:                 while(i && str1[i-1]!=SP) {
                    887:                                        i--;
                    888:                                        l--;
                    889:                                        bputs("\b \b"); } }
                    890:                        break;
                    891:                case 24:        /* Ctrl-X   Delete entire line */
                    892:                        while(i<l) {
                    893:                                outchar(SP);
                    894:                                i++; }
                    895:                        while(l) {
                    896:                                l--;
                    897:                                bputs("\b \b"); }
                    898:                        i=0;
                    899:                        break;
                    900:                case 25:        /* Ctrl-Y       Delete to end of line */
                    901:                        if(user_misc&ANSI) {
                    902:                                bputs("\x1b[s\x1b[K\x1b[u");
                    903:                                l=i; }
                    904:                        break;
                    905:                case 31:        /* Ctrl-Minus           Toggles Insert/Overwrite */
                    906:                        if(!(user_misc&ANSI))
                    907:                                break;
                    908:                        if(ins) {
                    909:                                ins=0;
                    910:                                redrwstr(str1,i,l,0); }
                    911:                        else if(i<l) {
                    912:                                ins=1;
                    913:                                bprintf("\x1b[s\x1b[%dC",80-i);         /* save pos  */
                    914:                                z=curatr;                                                               /* and got to EOL */
                    915:                 attr(z|BLINK|HIGH);
                    916:                                outchar('�');
                    917:                                attr(z);
                    918:                                bputs("\x1b[u"); }  /* restore pos */
                    919:                        break;
                    920:                case 0x1d:      /* Ctrl-]  Reverse Cursor Movement */
                    921:                        if(i && (user_misc&ANSI)) {
                    922:                                bputs("\x1b[D");   /* move cursor left one */
                    923:                                i--; }
                    924:                        break;
                    925:                case 0x7f:      /* Ctrl-BkSpc (DEL) Delete current char */
                    926:                        if(i==l)
                    927:                                break;
                    928:                        l--;
                    929:                        z=i;
                    930:                        while(z<l)      {               /* move the characters in the line */
                    931:                                outchar(str1[z]=str1[z+1]);
                    932:                                z++; }
                    933:                        outchar(SP);            /* write over the last char */
                    934:                        bprintf("\x1b[%dD",(l-i)+1);
                    935:             break;
                    936:                case ESC:
                    937:                        if(!(user_misc&ANSI))
                    938:                                break;
                    939:                        if((ch=getkey(0x8000))!='[') {
                    940:                                ungetch(ch);
                    941:                                break; }
                    942:                        if((ch=getkey(0x8000))=='C') {
                    943:                                if(i<l) {
                    944:                                        bputs("\x1b[C");   /* move cursor right one */
                    945:                                        i++; } }
                    946:                        else if(ch=='D') {
                    947:                                if(i) {
                    948:                                        bputs("\x1b[D");   /* move cursor left one */
                    949:                                        i--; } }
                    950:                        else {
                    951:                                while(isdigit(ch) || ch==';' || isalpha(ch)) {
                    952:                                        if(isalpha(ch)) {
                    953:                                                ch=getkey(0);
                    954:                                                break; }
                    955:                                        ch=getkey(0); }
                    956:                                ungetch(ch); }
                    957:                        break;
                    958:                default:
                    959:                        if(mode&K_WRAP && i==maxlen && ch>=SP && !ins) {
                    960:                                str1[i]=0;
                    961:                                if(ch==SP) {    /* don't wrap a space as last char */
                    962:                                        strcpy(strout,str1);
                    963:                                        if(stripattr(strout))
                    964:                                                redrwstr(strout,i,l,K_MSG);
                    965:                                        CRLF;
                    966:                                        return(i); }
                    967:                                x=i-1;
                    968:                                z=1;
                    969:                                wordwrap[0]=ch;
                    970:                                while(str1[x]!=SP && x)
                    971:                                        wordwrap[z++]=str1[x--];
                    972:                                if(x<(maxlen/2)) {
                    973:                                        wordwrap[1]=0;  /* only wrap one character */
                    974:                                        strcpy(strout,str1);
                    975:                                        if(stripattr(strout))
                    976:                                                redrwstr(strout,i,l,K_MSG);
                    977:                                        CRLF;
                    978:                                        return(i); }
                    979:                                wordwrap[z]=0;
                    980:                                while(z--) {
                    981:                                        i--;
                    982:                                        bputs("\b \b"); }
                    983:                                strrev(wordwrap);
                    984:                                str1[x]=0;
                    985:                                strcpy(strout,str1);
                    986:                                if(stripattr(strout))
                    987:                                        redrwstr(strout,i,x,mode);
                    988:                                CRLF;
                    989:                                return(x); }
                    990:                        if(i<maxlen && ch>=SP) {
                    991:                                if(mode&K_UPRLWR)
                    992:                                        if(!i || (i && (str1[i-1]==SP || str1[i-1]=='-'
                    993:                                                || str1[i-1]=='.' || str1[i-1]=='_')))
                    994:                                                ch=toupper(ch);
                    995:                                        else
                    996:                                                ch=tolower(ch);
                    997:                                if(ins) {
                    998:                                        if(l<maxlen)    /* l<maxlen */
                    999:                         l++;
                   1000:                                        for(x=l;x>i;x--)
                   1001:                                                str1[x]=str1[x-1];
                   1002:                                        rprintf("%.*s",l-i,str1+i);
                   1003:                                        rprintf("\x1b[%dD",l-i);
                   1004:                                        if(i==maxlen-1) {
                   1005:                                                bputs("  \b\b");
                   1006:                                                ins=0; } }
                   1007:                                str1[i++]=ch;
                   1008:                                outchar(ch); } }
                   1009:     if(i>l)
                   1010:                l=i;
                   1011:        if(mode&K_CHAT && !l)
                   1012:                return(0); }
                   1013: if(i>l)
                   1014:        l=i;
                   1015: str1[l]=0;
                   1016: if(!aborted) {
                   1017:     strcpy(strout,str1);
                   1018:     if(stripattr(strout) || ins)
                   1019:         redrwstr(strout,i,l,K_MSG); }
                   1020: else
                   1021:     l=0;
                   1022: if(mode&K_LINE) attr(LIGHTGRAY);
                   1023: if(!(mode&K_NOCRLF)) {
                   1024:        outchar(CR);
                   1025:        if(!(mode&K_MSG && aborted))
                   1026:                outchar(LF); }
                   1027: return(l);
                   1028: }
                   1029: 
                   1030: /****************************************************************************/
                   1031: /* Redraws str using i as current cursor position and l as length           */
                   1032: /****************************************************************************/
                   1033: void redrwstr(char *strin, int i, int l, char mode)
                   1034: {
                   1035:        char str[256],c;
                   1036: 
                   1037: sprintf(str,"%-*.*s",l,l,strin);
                   1038: c=i;
                   1039: while(c--)
                   1040:        outchar(BS);
                   1041: if(mode&K_MSG)
                   1042:        bputs(str);
                   1043: else
                   1044:        rputs(str);
                   1045: if(user_misc&ANSI) {
                   1046:        bputs("\x1b[K");
                   1047:        if(i<l)
                   1048:                bprintf("\x1b[%dD",l-i); }
                   1049: else {
                   1050:        while(c<79)     { /* clear to end of line */
                   1051:                outchar(SP);
                   1052:                c++; }
                   1053:        while(c>l) { /* back space to end of string */
                   1054:                outchar(BS);
                   1055:                c--; } }
                   1056: }
                   1057: 
                   1058: /****************************************************************************/
                   1059: /* Strips invalid Ctrl-Ax sequences from str                                */
                   1060: /* Returns number of ^A's in line                                           */
                   1061: /****************************************************************************/
                   1062: char stripattr(char *strin)
                   1063: {
                   1064:        uchar str[81];
                   1065:        uchar a,c,d,e;
                   1066: 
                   1067: e=strlen(strin);
                   1068: for(a=c=d=0;c<e;c++) {
                   1069:        if(strin[c]==1) {
                   1070:                a++;
                   1071:                switch(toupper(strin[c+1])) {
                   1072:                        case '-':       /* clear                */
                   1073:                        case '_':       /* clear                */
                   1074:                        case 'B':       /* blue         fg      */
                   1075:                        case 'C':       /* cyan         fg      */
                   1076:                        case 'G':       /* green        fg      */
                   1077:                        case 'H':       /* high         fg      */
                   1078:                        case 'I':       /* blink                */
                   1079:                        case 'K':       /* black        fg      */
                   1080:                        case 'L':       /* cls          */
                   1081:                        case 'M':       /* magenta  fg  */
                   1082:                        case 'N':       /* normal       */
                   1083:                        case 'P':       /* pause        */
                   1084:                        case 'Q':   /* pause reset  */
                   1085:                        case 'R':       /* red      fg  */
                   1086:                        case 'W':       /* white    fg  */
                   1087:                        case 'Y':       /* yellow   fg  */
                   1088:                        case '0':       /* black        bg      */
                   1089:                        case '1':       /* red          bg      */
                   1090:                        case '2':       /* green        bg      */
                   1091:                        case '3':   /* brown    bg      */
                   1092:                        case '4':       /* blue         bg      */
                   1093:                        case '5':   /* magenta  bg      */
                   1094:                        case '6':       /* cyan         bg      */
                   1095:                        case '7':       /* white        bg      */
                   1096:                                break;
                   1097:                        default:
                   1098:                                c++;
                   1099:                                continue; } }
                   1100:        str[d++]=strin[c]; }
                   1101: str[d]=0;
                   1102: strcpy(strin,str);
                   1103: return(a);
                   1104: }
                   1105: 
                   1106: /***************************************************************************/
                   1107: /* Changes local and remote text attributes accounting for monochrome      */
                   1108: /***************************************************************************/
                   1109: void attr(char atr)
                   1110: {
                   1111: 
                   1112: if(!(user_misc&ANSI) || aborted)
                   1113:        return;
                   1114: if(!(user_misc&COLOR)) {  /* eliminate colors if user doesn't have them */
                   1115:        if(atr&LIGHTGRAY)               /* if any bits set, set all */
                   1116:                atr|=LIGHTGRAY;
                   1117:        if(atr&(LIGHTGRAY<<4))
                   1118:                atr|=(LIGHTGRAY<<4);
                   1119:        if(atr&LIGHTGRAY && atr&(LIGHTGRAY<<4))
                   1120:                atr&=~LIGHTGRAY; }      /* if background is solid, forground is black */
                   1121: if(curatr==atr) /* attribute hasn't changed. don't send codes */
                   1122:        return;
                   1123: 
                   1124: if((!(atr&HIGH) && curatr&HIGH)        || (!(atr&BLINK) && curatr&BLINK)
                   1125:        || atr==LIGHTGRAY) {
                   1126:        bprintf("\x1b[0m");
                   1127:        curatr=LIGHTGRAY; }
                   1128: 
                   1129: if(atr==LIGHTGRAY) {                            /* no attributes */
                   1130:        curatr=atr;
                   1131:        return; }
                   1132: 
                   1133: if(atr&BLINK) {                                                /* special attributes */
                   1134:        if(!(curatr&BLINK))
                   1135:                bprintf("\x1b[5m"); }
                   1136: if(atr&HIGH) {
                   1137:        if(!(curatr&HIGH))
                   1138:                bprintf("\x1b[1m"); }
                   1139: 
                   1140: if((atr&0x7)==BLACK) {                         /* foreground colors */
                   1141:        if((curatr&0x7)!=BLACK)
                   1142:                bprintf("\x1b[30m"); }
                   1143: else if((atr&0x7)==RED) {
                   1144:        if((curatr&0x7)!=RED)
                   1145:                bprintf("\x1b[31m"); }
                   1146: else if((atr&0x7)==GREEN) {
                   1147:        if((curatr&0x7)!=GREEN)
                   1148:                bprintf("\x1b[32m"); }
                   1149: else if((atr&0x7)==BROWN) {
                   1150:        if((curatr&0x7)!=BROWN)
                   1151:                bprintf("\x1b[33m"); }
                   1152: else if((atr&0x7)==BLUE) {
                   1153:        if((curatr&0x7)!=BLUE)
                   1154:                bprintf("\x1b[34m"); }
                   1155: else if((atr&0x7)==MAGENTA) {
                   1156:        if((curatr&0x7)!=MAGENTA)
                   1157:                bprintf("\x1b[35m"); }
                   1158: else if((atr&0x7)==CYAN) {
                   1159:        if((curatr&0x7)!=CYAN)
                   1160:                bprintf("\x1b[36m"); }
                   1161: else if((atr&0x7)==LIGHTGRAY) {
                   1162:        if((curatr&0x7)!=LIGHTGRAY)
                   1163:                bprintf("\x1b[37m"); }
                   1164: 
                   1165: if((atr&0x70)==(BLACK<<4)) {           /* background colors */
                   1166:        if((curatr&0x70)!=(BLACK<<4))
                   1167:                bprintf("\x1b[40m"); }
                   1168: else if((atr&0x70)==(RED<<4)) {
                   1169:        if((curatr&0x70)!=(RED<<4))
                   1170:                bprintf("\x1b[41m"); }
                   1171: else if((atr&0x70)==(GREEN<<4)) {
                   1172:        if((curatr&0x70)!=(GREEN<<4))
                   1173:                bprintf("\x1b[42m"); }
                   1174: else if((atr&0x70)==(BROWN<<4)) {
                   1175:        if((curatr&0x70)!=(BROWN<<4))
                   1176:                bprintf("\x1b[43m"); }
                   1177: else if((atr&0x70)==(BLUE<<4)) {
                   1178:        if((curatr&0x70)!=(BLUE<<4))
                   1179:                bprintf("\x1b[44m"); }
                   1180: else if((atr&0x70)==(MAGENTA<<4)) {
                   1181:        if((curatr&0x70)!=(MAGENTA<<4))
                   1182:                bprintf("\x1b[45m"); }
                   1183: else if((atr&0x70)==(CYAN<<4)) {
                   1184:        if((curatr&0x70)!=(CYAN<<4))
                   1185:                bprintf("\x1b[46m"); }
                   1186: else if((atr&0x70)==(LIGHTGRAY<<4)) {
                   1187:        if((curatr&0x70)!=(LIGHTGRAY<<4))
                   1188:                bprintf("\x1b[47m"); }
                   1189: 
                   1190: curatr=atr;
                   1191: }
                   1192: 
                   1193: /****************************************************************************/
                   1194: /* Peform clear screen                                                                                                         */
                   1195: /****************************************************************************/
                   1196: void cls(void)
                   1197: {
                   1198:        int i;
                   1199: 
                   1200: if(lncntr>1 && !tos) {
                   1201:        lncntr=0;
                   1202:        CRLF;
                   1203:        pause();
                   1204:        while(lncntr && !aborted)
                   1205:                pause(); }
                   1206: 
                   1207: if(user_misc&ANSI)
                   1208:        bprintf("\x1b[2J");
                   1209: else {
                   1210:        outchar(FF);
                   1211:        clrscr(); }
                   1212: tos=1;
                   1213: lncntr=0;
                   1214: }
                   1215: 
                   1216: #ifdef __WATCOMC__
                   1217: 
                   1218: short wherey(void)
                   1219: {
                   1220:        struct rccoord rc;
                   1221: 
                   1222: rc=_gettextposition();
                   1223: return(rc.col);
                   1224: }
                   1225: 
                   1226: void clrscr(void)
                   1227: {
                   1228: _clearscreen(_GCLEARSCREEN);
                   1229: }
                   1230: 
                   1231: #endif
                   1232: 
                   1233: /****************************************************************************/
                   1234: /* performs the correct attribute modifications for the Ctrl-A code                    */
                   1235: /****************************************************************************/
                   1236: void ctrl_a(char x)
                   1237: {
                   1238:        char atr=curatr;
                   1239:        int i,j;
                   1240: 
                   1241: if((uchar)x>=0x7f) {
                   1242:        if(user_misc&ANSI)
                   1243:                bprintf("\x1b[%uC",(uchar)x-0x7f);
                   1244:        else
                   1245:                for(i=0;i<(uchar)x-0x7f;i++)
                   1246:                        outchar(SP);
                   1247:     return; }
                   1248: 
                   1249: switch(toupper(x)) {
                   1250:        case '-':                                                               /* turn off all attributes if */
                   1251:                if(atr&(HIGH|BLINK|(LIGHTGRAY<<4)))     /* high intensity, blink or */
                   1252:                        attr(LIGHTGRAY);                                /* background bits are set */
                   1253:                break;
                   1254:        case '_':                                                               /* turn off all attributes if */
                   1255:                if(atr&(BLINK|(LIGHTGRAY<<4)))          /* blink or background is set */
                   1256:                        attr(LIGHTGRAY);
                   1257:                break;
                   1258:        case ',':   /* Delay 1/10 sec */
                   1259:                mswait(100);
                   1260:                break;
                   1261:        case ';':   /* Delay 1/2 sec */
                   1262:                mswait(500);
                   1263:                break;
                   1264:        case '.':   /* Delay 2 secs */
                   1265:                mswait(2000);
                   1266:         break;
                   1267:        case 'P':       /* Pause */
                   1268:                pause();
                   1269:                break;
                   1270:        case 'Q':   /* Pause reset */
                   1271:                lncntr=0;
                   1272:                break;
                   1273:        case 'L':       /* CLS (form feed) */
                   1274:                cls();
                   1275:                break;
                   1276:        case '>':   /* CLREOL */
                   1277:                if(user_misc&ANSI)
                   1278:                        bputs("\x1b[K");
                   1279:                else {
                   1280:                        i=j=wherey();
                   1281:                        while(i++<80)
                   1282:                                outchar(SP);
                   1283:                        while(j++<80)
                   1284:                                outchar(BS); }
                   1285:                break;
                   1286:        case '<':   /* Non-destructive backspace */
                   1287:                outchar(BS);
                   1288:                break;
                   1289:        case '[':   /* Carriage return */
                   1290:                outchar(CR);
                   1291:                break;
                   1292:        case ']':   /* Line feed */
                   1293:                outchar(LF);
                   1294:                break;
                   1295:        case 'A':   /* Ctrl-A */
                   1296:                outchar(1);
                   1297:         break;
                   1298:        case 'H':       /* High intensity */
                   1299:                atr|=HIGH;
                   1300:                attr(atr);
                   1301:                break;
                   1302:        case 'I':       /* Blink */
                   1303:                atr|=BLINK;
                   1304:                attr(atr);
                   1305:                break;
                   1306:        case 'N':       /* Normal */
                   1307:                attr(LIGHTGRAY);
                   1308:                break;
                   1309:        case 'R':
                   1310:                atr=(atr&0xf8)|RED;
                   1311:                attr(atr);
                   1312:                break;
                   1313:        case 'S':
                   1314:                nodesync();
                   1315:                break;
                   1316:        case 'G':
                   1317:                atr=(atr&0xf8)|GREEN;
                   1318:                attr(atr);
                   1319:                break;
                   1320:        case 'B':
                   1321:                atr=(atr&0xf8)|BLUE;
                   1322:                attr(atr);
                   1323:                break;
                   1324:     case 'W':  /* White */
                   1325:                atr=(atr&0xf8)|LIGHTGRAY;
                   1326:                attr(atr);
                   1327:                break;
                   1328:     case 'C':
                   1329:                atr=(atr&0xf8)|CYAN;
                   1330:                attr(atr);
                   1331:                break;
                   1332:        case 'M':
                   1333:                atr=(atr&0xf8)|MAGENTA;
                   1334:                attr(atr);
                   1335:                break;
                   1336:        case 'Y':
                   1337:                atr=(atr&0xf8)|BROWN;
                   1338:                attr(atr);
                   1339:                break;
                   1340:     case 'K':  /* Black */
                   1341:                atr=(atr&0xf8)|BLACK;
                   1342:                attr(atr);
                   1343:                break;
                   1344:     case '0':  /* Black Background */
                   1345:                atr=(atr&0x8f)|(BLACK<<4);
                   1346:                attr(atr);
                   1347:                break;
                   1348:        case '1':       /* Red Background */
                   1349:                atr=(atr&0x8f)|(RED<<4);
                   1350:                attr(atr);
                   1351:                break;
                   1352:        case '2':       /* Green Background */
                   1353:                atr=(atr&0x8f)|(GREEN<<4);
                   1354:                attr(atr);
                   1355:                break;
                   1356:        case '3':       /* Yellow Background */
                   1357:                atr=(atr&0x8f)|(BROWN<<4);
                   1358:                attr(atr);
                   1359:                break;
                   1360:        case '4':       /* Blue Background */
                   1361:                atr=(atr&0x8f)|(BLUE<<4);
                   1362:                attr(atr);
                   1363:                break;
                   1364:        case '5':       /* Magenta Background */
                   1365:                atr=(atr&0x8f)|(MAGENTA<<4);
                   1366:                attr(atr);
                   1367:                break;
                   1368:        case '6':       /* Cyan Background */
                   1369:                atr=(atr&0x8f)|(CYAN<<4);
                   1370:                attr(atr);
                   1371:                break;
                   1372:        case '7':       /* White Background */
                   1373:                atr=(atr&0x8f)|(LIGHTGRAY<<4);
                   1374:                attr(atr);
                   1375:                break; }
                   1376: }
                   1377: 
                   1378: /****************************************************************************/
                   1379: /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
                   1380: /* number of times if the attempted file is already open or denying access  */
                   1381: /* for some other reason.      All files are opened in BINARY mode.                    */
                   1382: /****************************************************************************/
                   1383: int nopen(char *str, int access)
                   1384: {
                   1385:        char count=0;
                   1386:        int file,share;
                   1387: 
                   1388: if(access&SH_DENYNO) share=SH_DENYNO;
                   1389: else if(access==O_RDONLY) share=SH_DENYWR;
                   1390: else share=SH_DENYRW;
                   1391: while(((file=sopen(str,O_BINARY|access,share,S_IWRITE))==-1)
                   1392:        && errno==EACCES && count++<LOOP_NOPEN)
                   1393:        if(count>10)
                   1394:                mswait(50);
                   1395: if(count>(LOOP_NOPEN/2) && count<=LOOP_NOPEN)
                   1396:        bprintf("\r\nNOPEN COLLISION - File: %s Count: %d\r\n"
                   1397:                ,str,count);
                   1398: if(file==-1 && errno==EACCES)
                   1399:        bputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
                   1400: return(file);
                   1401: }
                   1402: 
                   1403: /****************************************************************************/
                   1404: /* Reads data from XTRN.DAT in the node directory and fills the appropriate */
                   1405: /* global variables.                                                                                                           */
                   1406: /* Initializes starttime variable with current time.                                           */
                   1407: /****************************************************************************/
                   1408: void initdata(void)
                   1409: {
                   1410:        char str[256],tmp[256];
                   1411:        int i;
                   1412:        FILE *stream;
                   1413: 
                   1414: #if defined(__TURBOC__) || defined(__SC__)     /* Borland or Symantec */
                   1415:        ctrlbrk(cbreakh);
                   1416: #endif
                   1417: 
                   1418: #ifdef __WATCOMC__
                   1419:        putenv("TZ=UCT0");
                   1420:        setvbuf(stdout,NULL,_IONBF,0);
                   1421:        setvbuf(stderr,NULL,_IONBF,0);
                   1422: #endif
                   1423: 
                   1424: #ifdef __SC__
                   1425:     setvbuf(stdout,NULL,_IONBF,0);
                   1426:        con_fp=stdout;
                   1427: #else
                   1428:        con_fp=stderr;
                   1429: #endif
                   1430: 
                   1431: if(setmode(fileno(con_fp),O_BINARY)==-1) {      /* eliminate LF expansion */
                   1432:        printf("Can't set console output to BINARY\n");
                   1433:        exit(1); }
                   1434: 
                   1435: sprintf(str,"%sXTRN.DAT",node_dir);
                   1436: if((stream=fopen(str,"rt"))==NULL) {
                   1437:        printf("Can't open %s\r\n",str);
                   1438:        exit(1); }
                   1439: fgets(str,81,stream);                  /* username */
                   1440: sprintf(user_name,"%.25s",str);
                   1441: truncsp(user_name);
                   1442: fgets(str,81,stream);                  /* system name */
                   1443: sprintf(sys_name,"%.40s",str);
                   1444: truncsp(sys_name);
                   1445: fgets(str,81,stream);                  /* system operator */
                   1446: sprintf(sys_op,"%.40s",str);
                   1447: truncsp(sys_op);
                   1448: fgets(str,81,stream);                  /* system guru */
                   1449: sprintf(sys_guru,"%.40s",str);
                   1450: truncsp(sys_guru);
                   1451: 
                   1452: fgets(str,81,stream);                  /* ctrl dir */
                   1453: str[50]=0;
                   1454: if(str[0]=='.')
                   1455:        sprintf(ctrl_dir,"%s%s",node_dir,str);
                   1456: else
                   1457:        strcpy(ctrl_dir,str);
                   1458: truncsp(ctrl_dir);
                   1459: if(_fullpath(str,ctrl_dir,50))
                   1460:        strcpy(ctrl_dir,str);
                   1461: backslash(ctrl_dir);
                   1462: 
                   1463: fgets(str,81,stream);                  /* data dir */
                   1464: if(str[0]=='.')
                   1465:        sprintf(data_dir,"%s%s",node_dir,str);
                   1466: else
                   1467:        sprintf(data_dir,"%.40s",str);
                   1468: truncsp(data_dir);
                   1469: if(_fullpath(str,data_dir,50))
                   1470:        strcpy(data_dir,str);
                   1471: backslash(data_dir);
                   1472: 
                   1473: fgets(str,81,stream);                  /* total nodes */
                   1474: sys_nodes=atoi(str);
                   1475: fgets(str,81,stream);                  /* current node */
                   1476: node_num=atoi(str);
                   1477: fgets(str,81,stream);                  /* time left */
                   1478: timeleft=atoi(str);
                   1479: fgets(str,81,stream);                  /* ANSI? (Yes, Mono, or No) */
                   1480: user_misc=0;
                   1481: if(str[0]=='Y')
                   1482:        user_misc|=(ANSI|COLOR);
                   1483: else if(str[0]=='M')
                   1484:        user_misc|=ANSI;
                   1485: fgets(str,81,stream);                  /* screen lines */
                   1486: user_rows=atoi(str);
                   1487: fgets(str,81,stream);                  /* credits */
                   1488: user_cdt=atol(str);
                   1489: fgets(str,81,stream);                  /* level */
                   1490: user_level=atoi(str);
                   1491: fgets(str,81,stream);                  /* was transfer level, left for compat. */
                   1492: fgets(str,81,stream);                  /* birthdate */
                   1493: truncsp(str);
                   1494: sprintf(user_birth,"%.8s",str);
                   1495: fgets(str,81,stream);                  /* sex */
                   1496: user_sex=str[0];
                   1497: fgets(str,81,stream);                  /* user number */
                   1498: user_number=atoi(str);
                   1499: fgets(str,81,stream);                  /* user phone number */
                   1500: sprintf(user_phone,"%.12s",str);
                   1501: truncsp(user_phone);
                   1502: fgets(str,81,stream);                  /* com port (0 if local or no modem) */
                   1503: com_port=atoi(str);
                   1504: fgets(str,81,stream);                  /* com (UART) irq */
                   1505: com_irq=atoi(str);
                   1506: fgets(str,81,stream);                  /* com (UART) base address in hex */
                   1507: truncsp(str);
                   1508: com_base=(uint)ahtoul(str);
                   1509: fgets(str,81,stream);                  /* com rate */
                   1510: com_rate=(ulong)atol(str);
                   1511: fgets(str,81,stream);                  /* hardware flow control (Y/N) */
                   1512: if(toupper(str[0])=='Y')
                   1513:        mdm_misc|=MDM_FLOWCTRL;
                   1514: fgets(str,81,stream);                  /* locked DTE rate (Y/N) */
                   1515: if(toupper(str[0])=='Y')
                   1516:        mdm_misc|=MDM_STAYHIGH;
                   1517: fgets(str,81,stream);                  /* modem initialization string */
                   1518: sprintf(mdm_init,"%.63s",str);
                   1519: truncsp(mdm_init);
                   1520: fgets(str,81,stream);                  /* modem special init string */
                   1521: sprintf(mdm_spec,"%.63s",str);
                   1522: truncsp(mdm_spec);
                   1523: fgets(str,81,stream);                  /* modem terminal mode string */
                   1524: sprintf(mdm_term,"%.63s",str);
                   1525: truncsp(mdm_term);
                   1526: fgets(str,81,stream);                  /* modem dial string */
                   1527: sprintf(mdm_dial,"%.63s",str);
                   1528: truncsp(mdm_dial);
                   1529: fgets(str,81,stream);                  /* modem off-hook string */
                   1530: sprintf(mdm_offh,"%.63s",str);
                   1531: truncsp(mdm_offh);
                   1532: fgets(str,81,stream);                  /* modem answer string */
                   1533: sprintf(mdm_answ,"%.63s",str);
                   1534: truncsp(mdm_answ);
                   1535: fgets(str,81,stream);                  /* memory address of modem status register */
                   1536: msr=(uint far *)atol(str);
                   1537: if(!fgets(str,81,stream))              /* total number of external programs */
                   1538:        total_xtrns=0;
                   1539: else
                   1540:        total_xtrns=atoi(str);
                   1541: if(total_xtrns && (xtrn=(char **)MALLOC(sizeof(char *)*total_xtrns))==NULL) {
                   1542:        printf("Allocation error 1: %u\r\n",sizeof(char *)*total_xtrns);
                   1543:        exit(1); }
                   1544: for(i=0;i<total_xtrns;i++) {
                   1545:        fgets(str,81,stream);
                   1546:        truncsp(str);
                   1547:        if((xtrn[i]=(char *)MALLOC(strlen(str)+1))==NULL) {
                   1548:                printf("Allocation error 2 (%u): %u\r\n",i,strlen(str)+1);
                   1549:                exit(1); }
                   1550:        strcpy(xtrn[i],str); }
                   1551: fgets(str,81,stream);                  /* user's main flags */
                   1552: sprintf(user_flags1,"%.26s",str);
                   1553: fgets(str,81,stream);                  /* user's xfer flags */
                   1554: sprintf(user_flags2,"%.26s",str);
                   1555: fgets(str,81,stream);                  /* user's exemptions */
                   1556: sprintf(user_exempt,"%.26s",str);
                   1557: fgets(str,81,stream);                  /* user's restrictions */
                   1558: sprintf(user_rest,"%.26s",str);
                   1559: fgets(str,81,stream);                  /* user's expiration date */
                   1560: truncsp(str);
                   1561: user_expire=ahtoul(str);
                   1562: str[0]=0;
                   1563: fgets(str,81,stream);                  /* user's address */
                   1564: sprintf(user_address,"%.30s",str);
                   1565: truncsp(user_address);
                   1566: fgets(str,81,stream);                  /* user's location (city, state) */
                   1567: sprintf(user_location,"%.30s",str);
                   1568: truncsp(user_location);
                   1569: fgets(str,81,stream);                  /* user's zip/postal code */
                   1570: sprintf(user_zipcode,"%.10s",str);
                   1571: truncsp(user_zipcode);
                   1572: str[0]=0;
                   1573: fgets(str,81,stream);
                   1574: sprintf(user_flags3,"%.26s",str);
                   1575: fgets(str,81,stream);
                   1576: sprintf(user_flags4,"%.26s",str);
                   1577: if(fgets(str,81,stream))               /* Time-slice API type */
                   1578:        mswtyp=ahtoul(str);
                   1579: str[0]=0;
                   1580: fgets(str,81,stream);
                   1581: truncsp(str);
                   1582: sprintf(user_realname,"%.25s",str);
                   1583: str[0]=0;
                   1584: fgets(str,81,stream);
                   1585: user_dce=atol(str);
                   1586: 
                   1587: str[0]=0;
                   1588: fgets(str,81,stream);                  /* exec dir */
                   1589: if(!str[0])
                   1590:        sprintf(exec_dir,"%s..\\EXEC\\",ctrl_dir);
                   1591: else {
                   1592:        if(str[0]=='.')
                   1593:                sprintf(exec_dir,"%s%s",node_dir,str);
                   1594:        else
                   1595:                sprintf(exec_dir,"%.50s",str); }
                   1596: truncsp(exec_dir);
                   1597: if(_fullpath(str,exec_dir,50))
                   1598:        strcpy(exec_dir,str);
                   1599: backslash(exec_dir);
                   1600: 
                   1601: str[0]=0;
                   1602: fgets(str,81,stream);                  /* text dir */
                   1603: if(!str[0])
                   1604:        sprintf(text_dir,"%s..\\TEXT\\",ctrl_dir);
                   1605: else {
                   1606:        if(str[0]=='.')
                   1607:                sprintf(text_dir,"%s%s",node_dir,str);
                   1608:        else
                   1609:                sprintf(text_dir,"%.50s",str); }
                   1610: truncsp(text_dir);
                   1611: if(_fullpath(str,text_dir,50))
                   1612:        strcpy(text_dir,str);
                   1613: backslash(text_dir);
                   1614: 
                   1615: str[0]=0;
                   1616: fgets(str,81,stream);                  /* temp dir */
                   1617: if(!str[0])
                   1618:        sprintf(temp_dir,"%sTEMP\\",node_dir);
                   1619: else {
                   1620:        if(str[0]!='\\' && str[1]!=':')
                   1621:                sprintf(temp_dir,"%s%s",node_dir,str);
                   1622:        else
                   1623:                sprintf(temp_dir,"%.50s",str); }
                   1624: truncsp(temp_dir);
                   1625: if(_fullpath(str,temp_dir,50))
                   1626:        strcpy(temp_dir,str);
                   1627: backslash(temp_dir);
                   1628: 
                   1629: str[0]=0;
                   1630: fgets(str,81,stream);
                   1631: sprintf(sys_id,"%.8s",str);
                   1632: 
                   1633: str[0]=0;
                   1634: fgets(str,81,stream);
                   1635: truncsp(str);
                   1636: if(str[0])
                   1637:        node_misc=(uint)ahtoul(str);
                   1638: else
                   1639:        node_misc=NM_LOWPRIO;
                   1640: 
                   1641: fclose(stream);
                   1642: 
                   1643: sprintf(str,"%sINTRSBBS.DAT",node_dir);     /* Shrank to run! */
                   1644: if(fexist(str)) {
                   1645:        if((stream=fopen(str,"rt"))==NULL) {
                   1646:                printf("Can't open %s\n",str);
                   1647:                exit(1); }
                   1648:        fgets(tmp,81,stream);                                   /* so get MSR address from file */
                   1649:        msr=(uint far *)atol(tmp);
                   1650:        fclose(stream);
                   1651:        remove(str); }
                   1652: 
                   1653: starttime=time(NULL);                  /* initialize start time stamp */
                   1654: wordwrap[0]=0;                                 /* set wordwrap to null */
                   1655: attr(LIGHTGRAY);                               /* initialize color and curatr to plain */
                   1656: mnehigh=LIGHTGRAY|HIGH;                /* mnemonics highlight color */
                   1657: mnelow=GREEN;                                  /* mnemonics normal text color */
                   1658: sec_warn=180;                                  /* seconds till inactivity warning */
                   1659: sec_timeout=300;                               /* seconds till inactivity timeout */
                   1660: tos=lncntr=0;                                  /* init topofscreen and linecounter to 0 */
                   1661: lastnodemsg=0;                                 /* Last node to send message to */
                   1662: aborted=0;                      /* Ctrl-C hit flag */
                   1663: sysop_level=90;                                /* Minimum level to be considered sysop */
                   1664: timeleft_warn=0;                               /* Running out of time warning */
                   1665: 
                   1666: sprintf(str,"%s%s",ctrl_dir,"NODE.DAB");
                   1667: if((nodefile=sopen(str,O_BINARY|O_RDWR,SH_DENYNO))==-1) {
                   1668:        bprintf("\r\n\7Error opening %s\r\n",str);
                   1669:        exit(1); }
                   1670: 
                   1671: sprintf(str,"%sUSER\\NAME.DAT",data_dir);
                   1672: if((i=nopen(str,O_RDONLY))==-1) {
                   1673:        printf("\r\n\7Error opening %s\r\n",str);
                   1674:        exit(1); }
                   1675: memset(str,0,30);
                   1676: read(i,str,26);
                   1677: close(i);
                   1678: if(str[25]==CR)        /* Version 1b */
                   1679:        name_len=25;
                   1680: else                           /* Version 1a */
                   1681:        name_len=30;
                   1682: }
                   1683: 
                   1684: /****************************************************************************/
                   1685: /* Automatic RIP & WIP terminal detection function. Sets RIP and WIP bits      */
                   1686: /* in user_misc variable. Must be called AFTER initdat(), not before.          */
                   1687: /****************************************************************************/
                   1688: void get_term(void)
                   1689: {
                   1690:        char str[128],ch;
                   1691:        int i;
                   1692: 
                   1693: bputs("\r\x1b[!_\x1b[0t_\r        \r");
                   1694: mswait(500);
                   1695: for(i=0;i<120;i++) {
                   1696:        ch=inkey(0);
                   1697:        if(!ch)
                   1698:                break;
                   1699:        mswait(1);
                   1700:        str[i]=ch; }
                   1701: str[i]=0;
                   1702: if(strstr(str,"RIPSCRIP"))
                   1703:        user_misc|=RIP;
                   1704: if(strstr(str,"DC-TERM"))
                   1705:        user_misc|=WIP;
                   1706: }
                   1707: 
                   1708: /****************************************************************************/
                   1709: /* Truncates white-space chars off end of 'str' and terminates at first tab */
                   1710: /****************************************************************************/
                   1711: void truncsp(uchar *str)
                   1712: {
                   1713:        char c;
                   1714: 
                   1715: str[strcspn(str,"\t")]=0;
                   1716: c=strlen(str);
                   1717: while(c && (uchar)str[c-1]<=SP) c--;
                   1718: str[c]=0;
                   1719: }
                   1720: 
                   1721: /****************************************************************************/
                   1722: /* Puts a backslash on path strings                                                                            */
                   1723: /****************************************************************************/
                   1724: void backslash(char *str)
                   1725: {
                   1726:     int i;
                   1727: 
                   1728: i=strlen(str);
                   1729: if(i && str[i-1]!='\\') {
                   1730:     str[i]='\\'; str[i+1]=0; }
                   1731: }
                   1732: 
                   1733: 
                   1734: /****************************************************************************/
                   1735: /* Checks the amount of time inside the external program against the amount */
                   1736: /* of time the user had left online before running the external program and */
                   1737: /* prints a message and exits the program if time has run out.                         */
                   1738: /****************************************************************************/
                   1739: void checktimeleft(void)
                   1740: {
                   1741: if(!SYSOP && !strchr(user_exempt,'T') && time(NULL)-starttime>timeleft) {
                   1742:        bputs("\1_\n\1r\1hTime's up.\n");
                   1743:        exit(0);  }
                   1744: }
                   1745: 
                   1746: /****************************************************************************/
                   1747: /* Prints a file remotely and locally, interpreting ^A sequences.                      */
                   1748: /* 'str' is the path of the file to print                                   */
                   1749: /****************************************************************************/
                   1750: void printfile(char *str)
                   1751: {
                   1752:        char *buf;
                   1753:        int file;
                   1754:        ulong length;
                   1755: 
                   1756: strupr(str);
                   1757: if(!tos)
                   1758:        CRLF;
                   1759: if((file=nopen(str,O_RDONLY))==-1) {
                   1760:        bprintf("File not Found: %s\r\n",str);
                   1761:        return; }
                   1762: length=filelength(file);
                   1763: if((buf=MALLOC(length+1L))==NULL) {
                   1764:        close(file);
                   1765:        bprintf("\7\r\nPRINTFILE: Error allocating %lu bytes of memory for %s.\r\n"
                   1766:                ,length+1L,str);
                   1767:        return; }
                   1768: buf[read(file,buf,length)]=0;
                   1769: close(file);
                   1770: bputs(buf);
                   1771: aborted=0;
                   1772: FREE(buf);
                   1773: }
                   1774: 
                   1775: /****************************************************************************/
                   1776: /* Returns a char pointer to the name of the user that corresponds to          */
                   1777: /* usernumber. Takes value directly from database.                                                     */
                   1778: /****************************************************************************/
                   1779: char *username(uint usernumber)
                   1780: {
                   1781:        static  char name[26];
                   1782:        char    str[128];
                   1783:        int     i,file;
                   1784: 
                   1785: strcpy(name,"UNKNOWN USER");
                   1786: if(!data_dir[0])
                   1787:        return(name);
                   1788: if(!usernumber) {
                   1789:        bputs("\7username: called with zero usernumber\r\n");
                   1790:        return(name); }
                   1791: sprintf(str,"%sUSER\\NAME.DAT",data_dir);
                   1792: if((file=nopen(str,O_RDONLY))==-1) {
                   1793:        bprintf("\7username: couldn't open %s\r\n",str);
                   1794:        return(name); }
                   1795: if(filelength(file)<(long)(usernumber-1)*((long)name_len+2L)) {
                   1796:        close(file);
                   1797:        return(name); }
                   1798: lseek(file,(long)(usernumber-1)*((long)name_len+2L),SEEK_SET);
                   1799: read(file,name,25);
                   1800: close(file);
                   1801: for(i=0;i<25;i++)
                   1802:        if(name[i]==3)
                   1803:                break;
                   1804: name[i]=0;
                   1805: if(!name[0])
                   1806:        strcpy(name,"DELETED USER");
                   1807: return(name);
                   1808: }
                   1809: 
                   1810: /****************************************************************************/
                   1811: /* Returns the number of the user 'username' from the NAME.DAT file.        */
                   1812: /* If the username is not found, the function returns 0.                                       */
                   1813: /****************************************************************************/
                   1814: uint usernumber(char *username)
                   1815: {
                   1816:        char str[128];
                   1817:        int i,file;
                   1818:        FILE *stream;
                   1819: 
                   1820: if(!data_dir[0])
                   1821:        return(0);
                   1822: sprintf(str,"%sUSER\\NAME.DAT",data_dir);
                   1823: if((file=nopen(str,O_RDONLY))==-1 || (stream=fdopen(file,"rb"))==NULL) {
                   1824:        if(file!=-1)
                   1825:                close(file);
                   1826:        bprintf("\7usernumber: couldn't open %s\r\n",str);
                   1827:        return(0); }
                   1828: for(i=1;!feof(stream);i++) {
                   1829:        if(!fread(str,27,1,stream))
                   1830:                break;
                   1831:        str[25]=0;
                   1832:        truncsp(str);   /* chop of trailing EOTs and spaces */
                   1833:        if(!stricmp(str,username)) {
                   1834:                fclose(stream);
                   1835:                return(i); } }
                   1836: fclose(stream);
                   1837: return(0);
                   1838: }
                   1839: 
                   1840: 
                   1841: /****************************************************************************/
                   1842: /* Checks the disk drive for the existance of a file. Returns 1 if it          */
                   1843: /* exists, 0 if it doesn't.                                                                                                    */
                   1844: /* Called from upload                                                                                                          */
                   1845: /****************************************************************************/
                   1846: char fexist(char *filespec)
                   1847: {
                   1848: #ifdef __SC__  /* Symantec */
                   1849: if(findfirst(filespec,0)==NULL)
                   1850:        return(0);
                   1851: return(1);
                   1852: #else                  /* Not Symantec */
                   1853:        struct ffblk f;
                   1854: 
                   1855: if(findfirst(filespec,&f,0)==NULL)
                   1856:        return(1);
                   1857: return(0);
                   1858: #endif                 /* !__SC__ */
                   1859: }
                   1860: 
                   1861: /****************************************************************************/
                   1862: /* Returns the length of the first file found that matches 'filespec'       */
                   1863: /* -1 if the file doesn't exist.                                            */
                   1864: /****************************************************************************/
                   1865: long flength(char *filespec)
                   1866: {
                   1867: #ifdef __SC__          /* Symantec */
                   1868:        struct FILE *f;
                   1869: 
                   1870: if((f=findfirst(filespec,0))==NULL)
                   1871:        return(-1);
                   1872: return(f->size);
                   1873: 
                   1874: #else                          /* Not Symantec */
                   1875: 
                   1876:        struct ffblk f;
                   1877: 
                   1878: if(findfirst(filespec,&f,0)==NULL)
                   1879: #ifdef __TURBOC__      /* Borland */
                   1880:        return(f.ff_fsize);
                   1881: #else                          /* Other (Watcom) */
                   1882:        return(f.size);
                   1883: #endif
                   1884: return(-1L);
                   1885: #endif                         /* !__SC__ */
                   1886: }
                   1887: 
                   1888: /****************************************************************************/
                   1889: /* Returns in 'string' a character representation of the number in l with   */
                   1890: /* commas. Maximum value of l is 4 gigabytes.                                                          */
                   1891: /****************************************************************************/
                   1892: char *ultoac(ulong l, char *string)
                   1893: {
                   1894:        char str[81];
                   1895:        char i,j,k;
                   1896: 
                   1897: ultoa(l,str,10);
                   1898: i=strlen(str)-1;
                   1899: j=i/3+1+i;
                   1900: string[j--]=0;
                   1901: for(k=1;i>-1;k++) {
                   1902:        string[j--]=str[i--];
                   1903:        if(j>0 && !(k%3))
                   1904:                string[j--]=','; }
                   1905: return(string);
                   1906: }
                   1907: 
                   1908: /****************************************************************************/
                   1909: /* Converts an ASCII Hex string into a ulong                                                           */
                   1910: /****************************************************************************/
                   1911: ulong ahtoul(char *str)
                   1912: {
                   1913:        ulong l,val=0;
                   1914: 
                   1915: while((l=(*str++)|0x20)!=0x20)
                   1916:        val=(l&0xf)+(l>>6&1)*9+val*16;
                   1917: return(val);
                   1918: }
                   1919: 
                   1920: /****************************************************************************/
                   1921: /* Reads the data for node number 'number' into the structure 'node'        */
                   1922: /* from NODE.DAB                                                                                                                       */
                   1923: /* if lockit is non-zero, locks this node's record. putnodedat() unlocks it */
                   1924: /****************************************************************************/
                   1925: void getnodedat(uchar number, node_t *node, char lockit)
                   1926: {
                   1927:        char str[256];
                   1928:        int count=0;
                   1929: 
                   1930: if(nodefile<0)
                   1931:        return;
                   1932: number--;      /* make zero based */
                   1933: while(count<LOOP_NODEDAB) {
                   1934:        lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET);
                   1935:        if(lockit
                   1936:                && lock(nodefile,(long)number*sizeof(node_t),sizeof(node_t))==-1) {
                   1937:                count++;
                   1938:                continue; }
                   1939:        if(read(nodefile,node,sizeof(node_t))==sizeof(node_t))
                   1940:                break;
                   1941:        count++; }
                   1942: if(count==LOOP_NODEDAB)
                   1943:        bprintf("\7Error unlocking and reading NODE.DAB\r\n");
                   1944: }
                   1945: 
                   1946: /****************************************************************************/
                   1947: /* Write the data from the structure 'node' into NODE.DAB                                      */
                   1948: /* getnodedat(num,&node,1); must have been called before calling this func  */
                   1949: /*          NOTE: ------^   the indicates the node record has been locked   */
                   1950: /****************************************************************************/
                   1951: void putnodedat(uchar number, node_t node)
                   1952: {
                   1953:        char str[256];
                   1954:        int count;
                   1955: 
                   1956: if(nodefile<0)
                   1957:        return;
                   1958: number--;      /* make zero based */
                   1959: lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET);
                   1960: if(write(nodefile,&node,sizeof(node_t))!=sizeof(node_t)) {
                   1961:        unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t));
                   1962:        bprintf("\7Error writing NODE.DAB for node %u\r\n",number+1);
                   1963:        return; }
                   1964: unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t));
                   1965: }
                   1966: 
                   1967: /****************************************************************************/
                   1968: /* Checks for messages waiting for this node or interruption.                          */
                   1969: /****************************************************************************/
                   1970: void nodesync(void)
                   1971: {
                   1972:        node_t node;
                   1973: 
                   1974: if(!ctrl_dir[0])
                   1975:        return;
                   1976: getnodedat(node_num,&node,0);
                   1977: 
                   1978: if(node.misc&NODE_MSGW)
                   1979:        getsmsg(user_number);           /* getsmsg clears MSGW flag */
                   1980: 
                   1981: if(node.misc&NODE_NMSG)                /* getnmsg clears NMSG flag */
                   1982:        getnmsg();
                   1983: 
                   1984: if(node.misc&NODE_INTR)
                   1985:        exit(0);
                   1986: 
                   1987: }
                   1988: 
                   1989: /****************************************************************************/
                   1990: /* Displays the information for node number 'number' contained in 'node'    */
                   1991: /****************************************************************************/
                   1992: void printnodedat(uchar number, node_t node)
                   1993: {
                   1994:        char hour,mer[3],tmp[256];
                   1995:        int i;
                   1996: 
                   1997: attr(LIGHTGRAY|HIGH);
                   1998: bprintf("Node %2d: ",number);
                   1999: attr(GREEN);
                   2000: switch(node.status) {
                   2001:     case NODE_WFC:
                   2002:         bputs("Waiting for call");
                   2003:         break;
                   2004:     case NODE_OFFLINE:
                   2005:         bputs("Offline");
                   2006:         break;
                   2007:     case NODE_NETTING:
                   2008:         bputs("Networking");
                   2009:         break;
                   2010:     case NODE_LOGON:
                   2011:         bputs("At logon prompt");
                   2012:         break;
                   2013:     case NODE_EVENT_WAITING:
                   2014:         bputs("Waiting for all nodes to become inactive");
                   2015:         break;
                   2016:     case NODE_EVENT_LIMBO:
                   2017:         bprintf("Waiting for node %d to finish external event",node.aux);
                   2018:         break;
                   2019:     case NODE_EVENT_RUNNING:
                   2020:         bputs("Running external event");
                   2021:         break;
                   2022:     case NODE_NEWUSER:
                   2023:                attr(GREEN|HIGH);
                   2024:         bputs("New user");
                   2025:                attr(GREEN);
                   2026:         bputs(" applying for access ");
                   2027:         if(!node.connection)
                   2028:             bputs("Locally");
                   2029:         else
                   2030:             bprintf("at %ubps",node.connection);
                   2031:         break;
                   2032:     case NODE_QUIET:
                   2033:         if(!SYSOP) {
                   2034:             bputs("Waiting for call");
                   2035:             break; }
                   2036:     case NODE_INUSE:
                   2037:                attr(GREEN|HIGH);
                   2038:         if(node.misc&NODE_ANON && !SYSOP)
                   2039:             bputs("UNKNOWN USER");
                   2040:         else
                   2041:                        bputs(username(node.useron));
                   2042:                attr(GREEN);
                   2043:         bputs(" ");
                   2044:         switch(node.action) {
                   2045:             case NODE_MAIN:
                   2046:                 bputs("at main menu");
                   2047:                 break;
                   2048:             case NODE_RMSG:
                   2049:                 bputs("reading messages");
                   2050:                 break;
                   2051:             case NODE_RMAL:
                   2052:                 bputs("reading mail");
                   2053:                 break;
                   2054:             case NODE_RSML:
                   2055:                 bputs("reading sent mail");
                   2056:                 break;
                   2057:             case NODE_RTXT:
                   2058:                 bputs("reading text files");
                   2059:                 break;
                   2060:             case NODE_PMSG:
                   2061:                 bputs("posting message");
                   2062:                 break;
                   2063:             case NODE_SMAL:
                   2064:                 bputs("sending mail");
                   2065:                 break;
                   2066:             case NODE_AMSG:
                   2067:                 bputs("posting auto-message");
                   2068:                 break;
                   2069:             case NODE_XTRN:
                   2070:                 if(!node.aux)
                   2071:                     bputs("at external program menu");
                   2072:                 else {
                   2073:                                        bputs("running ");
                   2074:                                        i=node.aux-1;
                   2075:                                        if(i>=total_xtrns || !xtrn[i][0])
                   2076:                                                bputs("external program");
                   2077:                                        else
                   2078:                                                bputs(xtrn[i]); }
                   2079:                 break;
                   2080:             case NODE_DFLT:
                   2081:                 bputs("changing defaults");
                   2082:                 break;
                   2083:             case NODE_XFER:
                   2084:                 bputs("at transfer menu");
                   2085:                 break;
                   2086:                        case NODE_RFSD:
                   2087:                                bprintf("retrieving from device #%d",node.aux);
                   2088:                 break;
                   2089:             case NODE_DLNG:
                   2090:                 bprintf("downloading");
                   2091:                 break;
                   2092:             case NODE_ULNG:
                   2093:                 bputs("uploading");
                   2094:                 break;
                   2095:             case NODE_BXFR:
                   2096:                                bputs("transferring bidirectional");
                   2097:                 break;
                   2098:             case NODE_LFIL:
                   2099:                 bputs("listing files");
                   2100:                 break;
                   2101:             case NODE_LOGN:
                   2102:                 bputs("logging on");
                   2103:                 break;
                   2104:             case NODE_LCHT:
                   2105:                 bprintf("in local chat with %s",sys_op);
                   2106:                 break;
                   2107:             case NODE_MCHT:
                   2108:                 if(node.aux) {
                   2109:                     bprintf("in multinode chat channel %d",node.aux&0xff);
                   2110:                                        if(node.aux&0x1f00)  /* password */
                   2111:                                                outchar('*'); }
                   2112:                 else
                   2113:                     bputs("in multinode global chat channel");
                   2114:                 break;
                   2115:                        case NODE_PAGE:
                   2116:                                bprintf("paging node %u for private chat",node.aux);
                   2117:                                break;
                   2118:                        case NODE_PCHT:
                   2119:                                bprintf("in private chat with node %u",node.aux);
                   2120:                                break;
                   2121:             case NODE_GCHT:
                   2122:                 bprintf("chatting with %s",sys_guru);
                   2123:                 break;
                   2124:             case NODE_CHAT:
                   2125:                 bputs("in chat section");
                   2126:                 break;
                   2127:             case NODE_TQWK:
                   2128:                 bputs("transferring QWK packet");
                   2129:                 break;
                   2130:             case NODE_SYSP:
                   2131:                 bputs("performing sysop activities");
                   2132:                 break;
                   2133:             default:
                   2134:                 bputs(itoa(node.action,tmp,10));
                   2135:                 break;  }
                   2136:         if(!node.connection)
                   2137:             bputs(" locally");
                   2138:         else
                   2139:             bprintf(" at %ubps",node.connection);
                   2140:         if(node.action==NODE_DLNG) {
                   2141:             if((node.aux/60)>12) {
                   2142:                 hour=(node.aux/60)-12;
                   2143:                 strcpy(mer,"pm"); }
                   2144:             else {
                   2145:                 if((node.aux/60)==0)    /* 12 midnite */
                   2146:                     hour=12;
                   2147:                 else hour=node.aux/60;
                   2148:                 strcpy(mer,"am"); }
                   2149:             bprintf(" ETA %02d:%02d %s"
                   2150:                                ,hour,node.aux%60,mer); }
                   2151:         break; }
                   2152: i=NODE_LOCK;
                   2153: if(node.status==NODE_INUSE || SYSOP)
                   2154:        i|=NODE_POFF|NODE_AOFF|NODE_MSGW|NODE_NMSG;
                   2155: if(node.misc&i) {
                   2156:     bputs(" (");
                   2157:        if(node.misc&(i&NODE_AOFF))
                   2158:                outchar('A');
                   2159:     if(node.misc&NODE_LOCK)
                   2160:                outchar('L');
                   2161:        if(node.misc&(i&(NODE_MSGW|NODE_NMSG)))
                   2162:                outchar('M');
                   2163:        if(node.misc&(i&NODE_POFF))
                   2164:                outchar('P');
                   2165:        outchar(')'); }
                   2166: if(SYSOP && ((node.misc
                   2167:     &(NODE_ANON|NODE_UDAT|NODE_INTR|NODE_RRUN|NODE_EVENT|NODE_DOWN))
                   2168:     || node.status==NODE_QUIET)) {
                   2169:     bputs(" [");
                   2170:     if(node.misc&NODE_ANON)
                   2171:                outchar('A');
                   2172:     if(node.misc&NODE_INTR)
                   2173:                outchar('I');
                   2174:     if(node.misc&NODE_RRUN)
                   2175:                outchar('R');
                   2176:     if(node.misc&NODE_UDAT)
                   2177:                outchar('U');
                   2178:     if(node.status==NODE_QUIET)
                   2179:                outchar('Q');
                   2180:     if(node.misc&NODE_EVENT)
                   2181:                outchar('E');
                   2182:     if(node.misc&NODE_DOWN)
                   2183:                outchar('D');
                   2184:        outchar(']'); }
                   2185: if(node.errors && SYSOP) {
                   2186:        attr(RED|HIGH|BLINK);
                   2187:     bprintf(" %d error%c",node.errors, node.errors>1 ? 's' : '\0' ); }
                   2188: CRLF;
                   2189: }
                   2190: 
                   2191: /****************************************************************************/
                   2192: /* Prints short messages waiting for 'usernumber', if any...                           */
                   2193: /* then deletes them.                                                                                                          */
                   2194: /****************************************************************************/
                   2195: void getsmsg(int usernumber)
                   2196: {
                   2197:        char str[256], *buf;
                   2198:        int file;
                   2199:        long length;
                   2200:        node_t node;
                   2201: 
                   2202: if(!data_dir[0])
                   2203:        return;
                   2204: sprintf(str,"%sMSGS\\%4.4u.MSG",data_dir,usernumber);
                   2205: if(flength(str)<1L) {
                   2206:        return; }
                   2207: if((file=nopen(str,O_RDWR))==-1) {
                   2208:        bprintf("\7Error opening %s for read/write access\r\n",str);
                   2209:        return; }
                   2210: length=filelength(file);
                   2211: if((buf=MALLOC(length+1))==NULL) {
                   2212:        close(file);
                   2213:        bprintf("\7Error allocating %u bytes of memory for %s\r\n",length+1,str);
                   2214:        return; }
                   2215: if(read(file,buf,length)!=length) {
                   2216:        close(file);
                   2217:        FREE(buf);
                   2218:        bprintf("\7Error reading %u bytes from %s\r\n",length,str);
                   2219:        return; }
                   2220: chsize(file,0L);
                   2221: close(file);
                   2222: buf[length]=0;
                   2223: getnodedat(node_num,&node,0);
                   2224: if(node.action==NODE_MAIN || node.action==NODE_XFER) {
                   2225:        CRLF; }
                   2226: if(node.misc&NODE_MSGW) {
                   2227:        getnodedat(node_num,&node,1);
                   2228:        node.misc&=~NODE_MSGW;
                   2229:        putnodedat(node_num,node); }
                   2230: bputs(buf);
                   2231: FREE(buf);
                   2232: }
                   2233: 
                   2234: /****************************************************************************/
                   2235: /* Creates a short message for 'usernumber' than contains 'strin'                      */
                   2236: /****************************************************************************/
                   2237: void putsmsg(int usernumber, char *strin)
                   2238: {
                   2239:        char str[256];
                   2240:        int file,i;
                   2241:     node_t node;
                   2242: 
                   2243: if(!data_dir[0])
                   2244:        return;
                   2245: sprintf(str,"%sMSGS\\%4.4u.MSG",data_dir,usernumber);
                   2246: if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
                   2247:        bprintf("\7Error opening/creating %s for creat/append access\r\n",str);
                   2248:        return; }
                   2249: i=strlen(strin);
                   2250: if(write(file,strin,i)!=i) {
                   2251:        close(file);
                   2252:        bprintf("\7Error writing %u bytes to %s\r\n",i,str);
                   2253:        return; }
                   2254: close(file);
                   2255: for(i=1;i<=sys_nodes;i++) {            /* flag node if user on that msg waiting */
                   2256:        getnodedat(i,&node,0);
                   2257:        if(node.useron==usernumber
                   2258:                && (node.status==NODE_INUSE || node.status==NODE_QUIET)
                   2259:                && !(node.misc&NODE_MSGW)) {
                   2260:                getnodedat(i,&node,1);
                   2261:                node.misc|=NODE_MSGW;
                   2262:         putnodedat(i,node); } }
                   2263: }
                   2264: 
                   2265: /****************************************************************************/
                   2266: /* Prints short messages waiting for this node, if any...                                      */
                   2267: /****************************************************************************/
                   2268: void getnmsg(void)
                   2269: {
                   2270:        char str[256], *buf;
                   2271:        int file;
                   2272:        long length;
                   2273:        node_t thisnode;
                   2274: 
                   2275: if(!data_dir[0])
                   2276:        return;
                   2277: getnodedat(node_num,&thisnode,1);
                   2278: thisnode.misc&=~NODE_NMSG;                     /* clear the NMSG flag */
                   2279: putnodedat(node_num,thisnode);
                   2280: 
                   2281: sprintf(str,"%sMSGS\\N%3.3u.MSG",data_dir,node_num);
                   2282: if(flength(str)<1L) {
                   2283:        return; }
                   2284: if((file=nopen(str,O_RDWR))==-1) {
                   2285:        printf("Couldn't open %s for read/write\r\n",str);
                   2286:        return; }
                   2287: length=filelength(file);
                   2288: if((buf=MALLOC(length+1))==NULL) {
                   2289:        close(file);
                   2290:        printf("Couldn't allocate %lu bytes for %s\r\n",length+1,str);
                   2291:        return; }
                   2292: if(read(file,buf,length)!=length) {
                   2293:        close(file);
                   2294:        FREE(buf);
                   2295:        printf("Couldn't read %lu bytes from %s\r\n",length,str);
                   2296:        return; }
                   2297: chsize(file,0L);
                   2298: close(file);
                   2299: buf[length]=0;
                   2300: 
                   2301: bputs(buf);
                   2302: FREE(buf);
                   2303: }
                   2304: 
                   2305: /****************************************************************************/
                   2306: /* Creates a short message for node 'num' than contains 'strin'             */
                   2307: /****************************************************************************/
                   2308: void putnmsg(int num, char *strin)
                   2309: {
                   2310:        char str[256];
                   2311:        int file,i;
                   2312:     node_t node;
                   2313: 
                   2314: if(!data_dir[0])
                   2315:        return;
                   2316: sprintf(str,"%sMSGS\\N%3.3u.MSG",data_dir,num);
                   2317: if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
                   2318:        printf("Couldn't open %s for append\r\n",str);
                   2319:        return; }
                   2320: i=strlen(strin);
                   2321: if(write(file,strin,i)!=i) {
                   2322:        close(file);
                   2323:        printf("Error writing %u bytes to %s\r\n",i,str);
                   2324:        return; }
                   2325: close(file);
                   2326: getnodedat(num,&node,0);
                   2327: if((node.status==NODE_INUSE || node.status==NODE_QUIET)
                   2328:        && !(node.misc&NODE_NMSG)) {
                   2329:        getnodedat(num,&node,1);
                   2330:        node.misc|=NODE_NMSG;
                   2331:        putnodedat(num,node); }
                   2332: }
                   2333: 
                   2334: /****************************************************************************/
                   2335: /* This function lists users that are online.                                                          */
                   2336: /* If listself is true, it will list the current node.                                         */
                   2337: /* Returns number of active nodes (not including current node).                        */
                   2338: /****************************************************************************/
                   2339: int whos_online(char listself)
                   2340: {
                   2341:        int i,j;
                   2342:        node_t node;
                   2343: 
                   2344: if(!ctrl_dir[0])
                   2345:        return(0);
                   2346: CRLF;
                   2347: for(j=0,i=1;i<=sys_nodes;i++) {
                   2348:        getnodedat(i,&node,0);
                   2349:        if(i==node_num) {
                   2350:                if(listself)
                   2351:                        printnodedat(i,node);
                   2352:                continue; }
                   2353:        if(node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET)) {
                   2354:                printnodedat(i,node);
                   2355:                if(!lastnodemsg)
                   2356:                        lastnodemsg=i;
                   2357:                j++; } }
                   2358: if(!j)
                   2359:        bputs("\1nNo other active nodes.\r\n");
                   2360: return(j);
                   2361: }
                   2362: 
                   2363: /****************************************************************************/
                   2364: /* Sending single line messages between nodes                               */
                   2365: /****************************************************************************/
                   2366: void nodemsg(void)
                   2367: {
                   2368:        char    str[256],line[256],buf[512];
                   2369:        int     i,j;
                   2370:        node_t  thisnode;
                   2371:        node_t  node;
                   2372: 
                   2373: if(!ctrl_dir[0])
                   2374:        return;
                   2375: if(strchr(user_rest,'C')) {
                   2376:        bputs("You cannot send messages.\r\n");
                   2377:        return; }
                   2378: getnodedat(node_num,&thisnode,0);
                   2379: wordwrap[0]=0;
                   2380: if(lastnodemsg) {
                   2381:        getnodedat(lastnodemsg,&node,0);
                   2382:        if(node.status!=NODE_INUSE)
                   2383:                lastnodemsg=0; }
                   2384: if(!whos_online(0))
                   2385:        return;
                   2386: bprintf("\r\n&n&gNumber of node to send message to, &w&hA&n&gll, "
                   2387:        "or &w&hQ&n&guit [%u]: &w&h",lastnodemsg);
                   2388: i=getkeys("QA",sys_nodes);
                   2389: if(i==-1)
                   2390:        return;
                   2391: if(i&0x8000 || !i) {
                   2392:        if(!i)
                   2393:                i=lastnodemsg;
                   2394:        else {
                   2395:                i^=0x8000;
                   2396:                lastnodemsg=i; }
                   2397:        if(!i || i>sys_nodes)
                   2398:                return;
                   2399:        getnodedat(i,&node,0);
                   2400:        if(node.status!=NODE_INUSE && !SYSOP)
                   2401:                bprintf("\r\n&_&w&hNode %d is not in use.\r\n",i);
                   2402:        else if(i==node_num)
                   2403:                bputs("\r\nThere's no need to send a message to yourself.\r\n");
                   2404:        else if(node.misc&NODE_POFF && !SYSOP)
                   2405:                bprintf("\r\n&r&h&iDon't bug %s.&n\r\n"
                   2406:                        ,node.misc&NODE_ANON ? "UNKNOWN USER"
                   2407:                        : username(node.useron));
                   2408:        else {
                   2409:                bputs("&_&y&hMessage: ");
                   2410:                if(!getstr(line,70,K_LINE))
                   2411:                        return;
                   2412:                sprintf(buf
                   2413:                        ,"\7&_&w&hNode %2d: &g%s&n&g sent you a message:\r\n&w&h&4%s&n\r\n"
                   2414:                        ,node_num
                   2415:                        ,thisnode.misc&NODE_ANON ? "UNKNOWN USER" : user_name,line);
                   2416:                putnmsg(i,buf); } }
                   2417: else if(i=='A') {
                   2418:        bputs("&_&y&hMessage: ");
                   2419:        if(!getstr(line,70,K_LINE))
                   2420:                return;
                   2421:        sprintf(buf
                   2422:                ,"\7&_&w&hNode %2d: &g%s&n&g sent all nodes a message:\r\n"
                   2423:                        "&w&h&4%s&n\r\n"
                   2424:                ,node_num
                   2425:                ,thisnode.misc&NODE_ANON ? "UNKNOWN USER" : user_name,line);
                   2426:        for(i=1;i<=sys_nodes;i++) {
                   2427:                if(i==node_num)
                   2428:                        continue;
                   2429:                getnodedat(i,&node,0);
                   2430:                if((node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET))
                   2431:                        && (SYSOP || !(node.misc&NODE_POFF)))
                   2432:                        putnmsg(i,buf); } }
                   2433: 
                   2434: }
                   2435: 
                   2436: /****************************************************************************/
                   2437: /* Puts a character into the input buffer                                                                      */
                   2438: /****************************************************************************/
                   2439: void ungetkey(char ch)
                   2440: {
                   2441: 
                   2442: keybuf[keybuftop++]=ch;
                   2443: if(keybuftop==KEY_BUFSIZE)
                   2444:        keybuftop=0;
                   2445: }
                   2446: 
                   2447: #ifdef __SC__                                  /* Missing from Symantec RTL */
                   2448: void clrscr(void) 
                   2449: {
                   2450:         asm
                   2451:         {       mov ah,8        /*function # for "Get char with attr*/
                   2452:                 xor bh,bh       /*page 0*/
                   2453:                 int 10h         /*Call interrupt 10h (video)*/
                   2454:                 
                   2455:                 mov bh,ah       /*set "set attr" to "current attr"*/
                   2456:                 mov ah,6        /*function # for "Scroll Window Up"*/
                   2457:                 xor cx,cx       /*set upper row & column (0,0)*/
                   2458:                 xor al,al       /*set "# lines to scroll" to 0*/
                   2459:                 mov dh,119      /*set lowqer colum*/
                   2460:                 int 10h         /*Call interrupt 10h*/
                   2461:                 
                   2462:                 mov ah,2        /*function # for "Set Cursor Position"*/
                   2463:                 xor bh,bh       /*set page to 0*/
                   2464:                 xor dx,dx       /*set row & colum to 0 (upper left)*/
                   2465:                 int 10h         /*Call interrupt 10h*/
                   2466:         }
                   2467:         return;
                   2468: }
                   2469: 
                   2470: short wherey(void)
                   2471: {
                   2472:         struct disp_t rc;
                   2473:         return(rc.cursorcol);
                   2474: }               
                   2475: #endif  /* __SC__ */
                   2476: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.