Annotation of sbbs/sbbs3/main.cpp, revision 1.1

1.1     ! root        1: /* main.cpp */
        !             2: 
        !             3: /* Synchronet main/telnet server thread and related functions */
        !             4: 
        !             5: /* $Id: main.cpp,v 1.1 2000/12/15 17:38:33 rswindell Exp $ */
        !             6: 
        !             7: /****************************************************************************
        !             8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
        !             9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
        !            10:  *                                                                                                                                                     *
        !            11:  * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html         *
        !            12:  *                                                                                                                                                     *
        !            13:  * This program is free software; you can redistribute it and/or                       *
        !            14:  * modify it under the terms of the GNU General Public License                         *
        !            15:  * as published by the Free Software Foundation; either version 2                      *
        !            16:  * of the License, or (at your option) any later version.                                      *
        !            17:  * See the GNU General Public License for more details: gpl.txt or                     *
        !            18:  * http://www.fsf.org/copyleft/gpl.html                                                                                *
        !            19:  *                                                                                                                                                     *
        !            20:  * Anonymous FTP access to the most recent released source is available at     *
        !            21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
        !            22:  *                                                                                                                                                     *
        !            23:  * Anonymous CVS access to the development source and modification history     *
        !            24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
        !            25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
        !            26:  *     (just hit return, no password is necessary)                                                     *
        !            27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
        !            28:  *                                                                                                                                                     *
        !            29:  * For Synchronet coding style and modification guidelines, see                                *
        !            30:  * http://www.synchro.net/source.html                                                                          *
        !            31:  *                                                                                                                                                     *
        !            32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
        !            33:  * format) via e-mail to [email protected]                                                                      *
        !            34:  *                                                                                                                                                     *
        !            35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
        !            36:  ****************************************************************************/
        !            37: 
        !            38: #ifdef __unix__
        !            39:        #include <signal.h>     /* do we need bsd/signal on Linux? */
        !            40: #endif
        !            41: 
        !            42: #include "sbbs.h"
        !            43: #include "telnet.h" 
        !            44: #include "bbs_thrd.h"
        !            45: 
        !            46: //---------------------------------------------------------------------------
        !            47: 
        !            48: /* Temporary */
        !            49: int    mswtyp=0;
        !            50: uint riobp;
        !            51: 
        !            52: #define STATUS_WFC     "Listening"
        !            53: 
        !            54: #define TIMEOUT_THREAD_WAIT            30              // Seconds
        !            55: #define IO_THREAD_BUF_SIZE             10000   // Bytes
        !            56: 
        !            57: // Globals
        !            58: #ifdef _WIN32
        !            59: HANDLE exec_mutex;
        !            60: #endif
        !            61: 
        !            62: static uint node_threads_running=0;
        !            63: 
        !            64: RingBuf* node_inbuf[MAX_NODES];
        !            65: SOCKET spy_socket[MAX_NODES];
        !            66: SOCKET node_socket[MAX_NODES];
        !            67: static SOCKET telnet_socket=INVALID_SOCKET;
        !            68: static SOCKET rlogin_socket=INVALID_SOCKET;
        !            69: static pthread_mutex_t event_mutex;
        !            70: static sbbs_t* sbbs=NULL;
        !            71: static scfg_t  scfg;
        !            72: static bool            scfg_reloaded=true;
        !            73: static char *  text[TOTAL_TEXT];
        !            74: 
        !            75: #ifdef _WINSOCKAPI_
        !            76: 
        !            77: WSADATA WSAData;
        !            78: static BOOL WSAInitialized=FALSE;
        !            79: 
        !            80: static BOOL winsock_startup(void)
        !            81: {
        !            82:        int             status;             /* Status Code */
        !            83: 
        !            84:     if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
        !            85:                lprintf("%s %s",WSAData.szDescription, WSAData.szSystemStatus);
        !            86:                WSAInitialized=TRUE;
        !            87:                return(TRUE);
        !            88:        }
        !            89: 
        !            90:     lprintf("!WinSock startup ERROR %d", status);
        !            91:        return(FALSE);
        !            92: }
        !            93: 
        !            94: #else /* No WINSOCK */
        !            95: 
        !            96: #define winsock_startup()      (TRUE)  
        !            97: 
        !            98: #endif
        !            99: 
        !           100: extern "C" {
        !           101: 
        !           102: static bbs_startup_t* startup=NULL;
        !           103: 
        !           104: static void status(char* str)
        !           105: {
        !           106:        if(startup!=NULL && startup->status!=NULL)
        !           107:            startup->status(str);
        !           108: }
        !           109: 
        !           110: static void update_clients()
        !           111: {
        !           112:        if(startup!=NULL && startup->clients!=NULL)
        !           113:                startup->clients(node_threads_running);
        !           114: }
        !           115: 
        !           116: void client_on(SOCKET sock, client_t* client)
        !           117: {
        !           118:        if(startup!=NULL && startup->client_on!=NULL)
        !           119:                startup->client_on(TRUE,sock,client);
        !           120: }
        !           121: 
        !           122: static void client_off(SOCKET sock)
        !           123: {
        !           124:        if(startup!=NULL && startup->client_on!=NULL)
        !           125:                startup->client_on(FALSE,sock,NULL);
        !           126: }
        !           127: 
        !           128: static void thread_up()
        !           129: {
        !           130:        if(startup!=NULL && startup->thread_up!=NULL)
        !           131:                startup->thread_up(TRUE);
        !           132: }
        !           133: 
        !           134: static void thread_down()
        !           135: {
        !           136:        if(startup!=NULL && startup->thread_up!=NULL)
        !           137:                startup->thread_up(FALSE);
        !           138: }
        !           139: 
        !           140: SOCKET open_socket(int type)
        !           141: {
        !           142:        SOCKET sock;
        !           143: 
        !           144:        sock=socket(AF_INET, type, IPPROTO_IP);
        !           145:        if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) 
        !           146:                startup->socket_open(TRUE);
        !           147:        return(sock);
        !           148: }
        !           149: 
        !           150: int close_socket(SOCKET sock)
        !           151: {
        !           152:        int             result;
        !           153: 
        !           154:        shutdown(sock,SHUT_RDWR);       /* required on Unix */
        !           155:        result=closesocket(sock);
        !           156:        if(/* result==0 && */ startup!=NULL && startup->socket_open!=NULL) 
        !           157:                startup->socket_open(FALSE);
        !           158:        if(result!=0)
        !           159:                lprintf("!ERROR %d closing socket %d",ERROR_VALUE,sock);
        !           160:        return(result);
        !           161: }
        !           162: 
        !           163: int lputs(char* str)
        !           164: {
        !           165:        if(startup==NULL || startup->lputs==NULL)
        !           166:        return(0);
        !           167:     return(startup->lputs(str));
        !           168: }
        !           169: 
        !           170: int lprintf(char *fmt, ...)
        !           171: {
        !           172:        va_list argptr;
        !           173:        char sbuf[1024];
        !           174: 
        !           175:     if(startup==NULL || startup->lputs==NULL)
        !           176:         return(0);
        !           177:     va_start(argptr,fmt);
        !           178:     vsprintf(sbuf,fmt,argptr);
        !           179:     va_end(argptr);
        !           180:     return(startup->lputs(sbuf));
        !           181: }
        !           182: 
        !           183: } /* extern "C" */
        !           184: 
        !           185: 
        !           186: BYTE* telnet_interpret(sbbs_t* sbbs, BYTE* inbuf, int inlen,
        !           187:                                                                        BYTE* outbuf, int& outlen)
        !           188: {
        !           189:        char    str[32];
        !           190:        BYTE*   first_iac=NULL;
        !           191:        BYTE*   first_cr=NULL;
        !           192:        int     i;
        !           193: 
        !           194: 
        !           195:     first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
        !           196: 
        !           197:        if(!(sbbs->telnet_mode&(TELNET_MODE_BIN_RX|TELNET_MODE_GATE)) 
        !           198:                && !(sbbs->console&CON_RAW_IN)) {
        !           199:                if(sbbs->telnet_last_rxch==CR)
        !           200:                        first_cr=inbuf;
        !           201:                else
        !           202:                        first_cr=(BYTE*)memchr(inbuf, CR, inlen);
        !           203:        }
        !           204: 
        !           205:     if(!sbbs->telnet_cmdlen    && first_iac==NULL && first_cr==NULL) {
        !           206:         outlen=inlen;
        !           207:         return(inbuf); // no interpretation needed
        !           208:     }
        !           209: 
        !           210:     if(first_iac!=NULL || first_cr!=NULL) {
        !           211:                if(first_iac!=NULL && (first_cr==NULL || first_iac<first_cr))
        !           212:                        outlen=first_iac-inbuf;
        !           213:                else
        !           214:                        outlen=first_cr-inbuf;
        !           215:            memcpy(outbuf, inbuf, outlen);
        !           216:     } else
        !           217:        outlen=0;
        !           218: 
        !           219:     for(i=outlen;i<inlen;i++) {
        !           220:                if(!(sbbs->telnet_mode&(TELNET_MODE_BIN_RX|TELNET_MODE_GATE)) 
        !           221:                        && !(sbbs->console&CON_RAW_IN)) {
        !           222:                        if(sbbs->telnet_last_rxch==CR
        !           223:                                && (inbuf[i]==LF || inbuf[i]==0)) { // CR/LF or CR/NUL, ignore 2nd char
        !           224:                                sbbs->telnet_last_rxch=inbuf[i];
        !           225:                                continue;
        !           226:                        }
        !           227:                        sbbs->telnet_last_rxch=inbuf[i];
        !           228:                }
        !           229: 
        !           230:         if(inbuf[i]==TELNET_IAC && sbbs->telnet_cmdlen==1) { /* escaped 255 */
        !           231:             sbbs->telnet_cmdlen=0;
        !           232:             outbuf[outlen++]=TELNET_IAC;
        !           233:             continue;
        !           234:         }
        !           235:         if(inbuf[i]==TELNET_IAC || sbbs->telnet_cmdlen) {
        !           236:             sbbs->telnet_cmd[sbbs->telnet_cmdlen++]=inbuf[i];
        !           237:             if(sbbs->telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) {
        !           238:                                if(startup->options&BBS_OPT_DEBUG_TELNET)
        !           239:                        lprintf("Node %d %s telnet command: %s"
        !           240:                                ,sbbs->cfg.node_num
        !           241:                                                ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !           242:                                ,telnet_cmd_desc(sbbs->telnet_cmd[2]));
        !           243:                 sbbs->telnet_cmdlen=0;
        !           244:             }
        !           245:             else if(sbbs->telnet_cmdlen>=3) {
        !           246:                                if(sbbs->telnet_cmd[2]==TELNET_BINARY) {
        !           247:                                        if(sbbs->telnet_cmd[1]==TELNET_WILL)
        !           248:                                                sbbs->telnet_mode|=TELNET_MODE_BIN_RX;
        !           249:                                        else if(sbbs->telnet_cmd[1]==TELNET_WONT)
        !           250:                                                sbbs->telnet_mode&=~TELNET_MODE_BIN_RX;
        !           251:                                }
        !           252:                                if(sbbs->telnet_cmd[2]==TELNET_ECHO) {
        !           253:                                        if(sbbs->telnet_cmd[1]==TELNET_DO)
        !           254:                                                sbbs->telnet_mode|=TELNET_MODE_ECHO;
        !           255:                                        else if(sbbs->telnet_cmd[1]==TELNET_DONT) {
        !           256:                                                sbbs->telnet_mode&=~TELNET_MODE_ECHO;
        !           257:                                                if(!(sbbs->telnet_mode&TELNET_MODE_GATE)) {
        !           258:                                                        sprintf(str,"%c%c%c",TELNET_IAC,TELNET_WILL,TELNET_ECHO);
        !           259:                                                        sbbs->putcom(str,3);
        !           260:                                                }
        !           261:                                        }
        !           262:                                }
        !           263:                                if(startup->options&BBS_OPT_DEBUG_TELNET)
        !           264:                                        lprintf("Node %d %s telnet command: %s %s"
        !           265:                            ,sbbs->cfg.node_num
        !           266:                                                ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !           267:                                                ,telnet_cmd_desc(sbbs->telnet_cmd[1])
        !           268:                                                ,telnet_opt_desc(sbbs->telnet_cmd[2]));
        !           269:                 sbbs->telnet_cmdlen=0;
        !           270:             }
        !           271:                        if(sbbs->telnet_mode&TELNET_MODE_GATE)  // Pass-through commads
        !           272:                                outbuf[outlen++]=inbuf[i];
        !           273:         } else
        !           274:                outbuf[outlen++]=inbuf[i];
        !           275:     }
        !           276:     return(outbuf);
        !           277: }
        !           278: 
        !           279: void input_thread(void *arg)
        !           280: {
        !           281:        BYTE            inbuf[4000];
        !           282:        BYTE            telbuf[sizeof(inbuf)];
        !           283:     BYTE               *wrbuf;
        !           284:     int                        i,rd,wr,avail;
        !           285:        ulong           total_recv=0;
        !           286:        fd_set          socket_set;
        !           287:        sbbs_t*         sbbs = (sbbs_t*) arg;
        !           288:        struct timeval  tv;
        !           289: 
        !           290:        thread_up();
        !           291: 
        !           292:        lprintf("Node %d input thread started",sbbs->cfg.node_num);
        !           293: 
        !           294:        pthread_mutex_init(&sbbs->input_thread_mutex,NULL);
        !           295:     sbbs->input_thread_running = true;
        !           296:        sbbs->console|=CON_R_INPUT;
        !           297: 
        !           298:        while(sbbs->online) {
        !           299: 
        !           300:                pthread_mutex_lock(&sbbs->input_thread_mutex);
        !           301: 
        !           302:                FD_ZERO(&socket_set);
        !           303:                FD_SET(sbbs->client_socket,&socket_set);
        !           304:        
        !           305:                tv.tv_sec=1;
        !           306:                tv.tv_usec=0;
        !           307: 
        !           308:                if((i=select(sbbs->client_socket+1,&socket_set,NULL,NULL,&tv))<1) {
        !           309:                        pthread_mutex_unlock(&sbbs->input_thread_mutex);
        !           310:                        if(i==0) {
        !           311:                                mswait(1);
        !           312:                                continue;
        !           313:                        }
        !           314: 
        !           315:                if(ERROR_VALUE == ENOTSOCK)
        !           316:                 lprintf("Node %d socket closed by peer on input->select", sbbs->cfg.node_num);
        !           317:                        else if(ERROR_VALUE==EINTR)
        !           318:                                lprintf("Node %d input_thread interrupted",sbbs->cfg.node_num);
        !           319:             else if(ERROR_VALUE==ECONNRESET) 
        !           320:                                lprintf("Node %d connection reset by peer on input->select", sbbs->cfg.node_num);
        !           321:             else if(ERROR_VALUE==ECONNABORTED) 
        !           322:                                lprintf("Node %d connection aborted by peer on input->select", sbbs->cfg.node_num);
        !           323:                        else
        !           324:                                lprintf("!Node %d: ERROR %d input->select socket %d"
        !           325:                        ,sbbs->cfg.node_num, ERROR_VALUE, sbbs->client_socket);
        !           326:                        sbbs->online=0;
        !           327:                        break;
        !           328:                }
        !           329: 
        !           330:        rd=RingBufFree(&sbbs->inbuf);
        !           331: 
        !           332:                if(!rd) { // input buffer full
        !           333:                // wait up to 5 seconds to empty (1 byte min)
        !           334:                        time_t start=time(NULL);
        !           335:             while((rd=RingBufFree(&sbbs->inbuf))==0) {
        !           336:                if(time(NULL)-start>=5) {
        !           337:                        rd=1;
        !           338:                        break;
        !           339:                 }
        !           340:                 mswait(1);
        !           341:             }
        !           342:                }
        !           343:                
        !           344:            if(rd > (int)sizeof(inbuf))
        !           345:                rd=sizeof(inbuf);
        !           346: 
        !           347:        rd = recv(sbbs->client_socket, (char*)inbuf, rd, 0);
        !           348: 
        !           349:                pthread_mutex_unlock(&sbbs->input_thread_mutex);
        !           350: 
        !           351:                if(rd == SOCKET_ERROR)
        !           352:                {
        !           353:                if(ERROR_VALUE == ENOTSOCK)
        !           354:                 lprintf("Node %d socket closed by peer on receive", sbbs->cfg.node_num);
        !           355:             else if(ERROR_VALUE==ECONNRESET) 
        !           356:                                lprintf("Node %d connection reset by peer on receive", sbbs->cfg.node_num);
        !           357:             else if(ERROR_VALUE==ECONNABORTED) 
        !           358:                                lprintf("Node %d connection aborted by peer on receive", sbbs->cfg.node_num);
        !           359:                        else
        !           360:                                lprintf("!Node %d: ERROR %d receiving from socket %d"
        !           361:                        ,sbbs->cfg.node_num, ERROR_VALUE, sbbs->client_socket);
        !           362:                        sbbs->online=0;
        !           363:                        break;
        !           364:                }
        !           365: 
        !           366:                if(rd == 0)
        !           367:                {
        !           368:                        lprintf("Node %d disconnected", sbbs->cfg.node_num);
        !           369:                        sbbs->online=0;
        !           370:                        break;
        !           371:                }
        !           372: 
        !           373:                total_recv+=rd;
        !           374: 
        !           375:         // telbuf and wr are modified to reflect telnet escaped data
        !           376:                wrbuf=telnet_interpret(sbbs, inbuf, rd, telbuf, wr);
        !           377:                if(wr > (int)sizeof(telbuf)) 
        !           378:                        lprintf("!TELBUF OVERFLOW (%d>%d)",wr,sizeof(telbuf));
        !           379: 
        !           380:                avail=RingBufFree(&sbbs->inbuf);
        !           381: 
        !           382:         if(avail<wr)
        !           383:                        lprintf("!INPUT BUFFER FULL (%d free)", avail);
        !           384:         else
        !           385:                        RingBufWrite(&sbbs->inbuf, wrbuf, wr);
        !           386: //             if(wr>100)
        !           387: //                     mswait(500);    // Throttle sender
        !           388:        }
        !           389: 
        !           390:     sbbs->input_thread_running = false;
        !           391: 
        !           392:        pthread_mutex_destroy(&sbbs->input_thread_mutex);
        !           393: 
        !           394:        lprintf("Node %d input thread terminated (total bytes received: %lu)"
        !           395:                ,sbbs->cfg.node_num, total_recv);
        !           396: 
        !           397:        thread_down();
        !           398: }
        !           399: 
        !           400: void output_thread(void* arg)
        !           401: {
        !           402:        char            node[128];
        !           403:     BYTE               buf[IO_THREAD_BUF_SIZE];
        !           404:        int                     i;
        !           405:     ulong              avail;
        !           406:        ulong           total_sent=0;
        !           407:     ulong              bufbot=0;
        !           408:     ulong              buftop=0;
        !           409:        sbbs_t*         sbbs = (sbbs_t*) arg;
        !           410: 
        !           411:        thread_up();
        !           412: 
        !           413:     if(sbbs->cfg.node_num)
        !           414:        sprintf(node,"Node %d",sbbs->cfg.node_num);
        !           415:     else
        !           416:        strcpy(node,sbbs->client_name);
        !           417:        lprintf("%s output thread started",node);
        !           418: 
        !           419:     sbbs->output_thread_running = true;
        !           420:        sbbs->console|=CON_R_ECHO;
        !           421: 
        !           422:        while(sbbs->client_socket!=INVALID_SOCKET && telnet_socket!=INVALID_SOCKET) {
        !           423:        if(bufbot==buftop)
        !           424:                avail=RingBufFull(&sbbs->outbuf);
        !           425:         else
        !           426:                avail=buftop-bufbot;
        !           427: 
        !           428:                if(!avail) {
        !           429:                        sem_init(&sbbs->output_sem,0,0);
        !           430:                        sem_wait(&sbbs->output_sem);
        !           431:                        continue; }
        !           432: 
        !           433:         if(bufbot==buftop) { // linear buf empty, read from ring buf
        !           434:             if(avail>sizeof(buf)) {
        !           435:                 lprintf("Reducing output buffer");
        !           436:                 avail=sizeof(buf);
        !           437:             }
        !           438:             buftop=RingBufRead(&sbbs->outbuf, buf, avail);
        !           439:             bufbot=0;
        !           440:         }
        !           441:                i = send(sbbs->client_socket, (char*)buf+bufbot, buftop-bufbot, 0);
        !           442:                if(i == SOCKET_ERROR)
        !           443:                {
        !           444:                if(ERROR_VALUE == ENOTSOCK)
        !           445:                 lprintf("%s client socket closed on send", node);
        !           446:             else if(ERROR_VALUE==ECONNRESET) 
        !           447:                                lprintf("%s connection reset by peer on send", node);
        !           448:             else if(ERROR_VALUE==ECONNABORTED) 
        !           449:                                lprintf("%s connection aborted by peer on send", node);
        !           450:                        else
        !           451:                                lprintf("!%s: ERROR %d sending on socket %d"
        !           452:                        ,node, ERROR_VALUE, sbbs->client_socket);
        !           453:                        sbbs->online=0;
        !           454:                        /* was break; on 4/7/00 */
        !           455:                        i=buftop-bufbot;        // Pretend we sent it all
        !           456:                }
        !           457: 
        !           458:                if(sbbs->cfg.node_num && !(sbbs->sys_status&SS_FILEXFER)) {
        !           459:                        /* Spy on the user locally */
        !           460:                        if(startup->node_spybuf!=NULL 
        !           461:                                && startup->node_spybuf[sbbs->cfg.node_num-1]!=NULL)
        !           462:                                RingBufWrite(startup->node_spybuf[sbbs->cfg.node_num-1],buf+bufbot,i);
        !           463: 
        !           464:                        /* Spy on the user remotely */
        !           465:                        if(spy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET) 
        !           466:                                send(spy_socket[sbbs->cfg.node_num-1],(char*)buf+bufbot,i,0);
        !           467:                }
        !           468: 
        !           469:                bufbot+=i;
        !           470:                total_sent+=i;
        !           471:     }
        !           472: 
        !           473:        sbbs->spymsg("Disconnected");
        !           474: 
        !           475:     sbbs->output_thread_running = false;
        !           476: 
        !           477:        lprintf("%s output thread terminated (total bytes sent: %lu)", node, total_sent);
        !           478: 
        !           479:        thread_down();
        !           480: }
        !           481: 
        !           482: void event_thread(void* arg)
        !           483: {
        !           484:        char            str[256];
        !           485:        char            semfile[128];
        !           486:        int                     i,j,k;
        !           487:        int                     file;
        !           488:        int                     offset;
        !           489:        ulong           l;
        !           490:        time_t          now;
        !           491:        struct tm       now_tm;
        !           492:        struct tm*      tm;
        !           493:        time_t          lastnodechk;
        !           494:        time_t          lastprepack=0;
        !           495:        node_t          node;
        !           496:        glob_t          g;
        !           497:        sbbs_t*         sbbs = (sbbs_t*) arg;
        !           498: 
        !           499:        lprintf("BBS Events thread started");
        !           500: 
        !           501:        sbbs->event_thread_running = true;
        !           502: 
        !           503:        thread_up();
        !           504: 
        !           505:        while(1) {
        !           506: 
        !           507:                pthread_mutex_lock(&event_mutex);
        !           508: 
        !           509:                if(sbbs->terminated || telnet_socket==INVALID_SOCKET)
        !           510:                        break;
        !           511: 
        !           512:                if(scfg_reloaded==true) {
        !           513: 
        !           514:                        for(i=0;i<TOTAL_TEXT;i++)
        !           515:                                sbbs->text[i]=sbbs->text_sav[i]=text[i];
        !           516: 
        !           517:                        memcpy(&sbbs->cfg,&scfg,sizeof(scfg_t));
        !           518: 
        !           519:                        prep_dir(sbbs->cfg.data_dir, sbbs->cfg.temp_dir);
        !           520: 
        !           521:                        // Read TIME.DAB
        !           522:                        sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
        !           523:                        if((file=sbbs->nopen(str,O_RDWR|O_CREAT))==-1) {
        !           524:                                sbbs->errormsg(WHERE,ERR_OPEN,str,0);
        !           525:                                return; 
        !           526:                        }
        !           527:                        for(i=0;i<sbbs->cfg.total_events;i++) {
        !           528:                                sbbs->cfg.event[i]->last=0;
        !           529:                                if(filelength(file)<(long)(sizeof(time_t)*(i+1)))
        !           530:                                        write(file,&sbbs->cfg.event[i]->last,sizeof(time_t));
        !           531:                                else
        !           532:                                        read(file,&sbbs->cfg.event[i]->last,sizeof(time_t)); 
        !           533:                        }
        !           534:                        read(file,&lastprepack,sizeof(time_t));
        !           535:                        close(file);
        !           536: 
        !           537:                        // Read QNET.DAB
        !           538:                        sprintf(str,"%sqnet.dab",sbbs->cfg.ctrl_dir);
        !           539:                        if((file=sbbs->nopen(str,O_RDWR|O_CREAT))==-1) {
        !           540:                                sbbs->errormsg(WHERE,ERR_OPEN,str,0);
        !           541:                                return;
        !           542:                        }
        !           543:                        for(i=0;i<sbbs->cfg.total_qhubs;i++) {
        !           544:                                sbbs->cfg.qhub[i]->last=0;
        !           545:                                if(filelength(file)<(long)(sizeof(time_t)*(i+1)))
        !           546:                                        write(file,&sbbs->cfg.qhub[i]->last,sizeof(time_t));
        !           547:                                else
        !           548:                                        read(file,&sbbs->cfg.qhub[i]->last,sizeof(time_t)); 
        !           549:                        }
        !           550:                        close(file);
        !           551: 
        !           552:                        // Read PNET.DAB
        !           553:                        sprintf(str,"%spnet.dab",sbbs->cfg.ctrl_dir);
        !           554:                        if((file=sbbs->nopen(str,O_RDWR|O_CREAT))==-1) {
        !           555:                                sbbs->errormsg(WHERE,ERR_OPEN,str,0);
        !           556:                                return;
        !           557:                        }
        !           558:                        for(i=0;i<sbbs->cfg.total_phubs;i++) {
        !           559:                                sbbs->cfg.phub[i]->last=0;
        !           560:                                if(filelength(file)<(long)(sizeof(time_t)*(i+1)))
        !           561:                                        write(file,&sbbs->cfg.phub[i]->last,sizeof(time_t));
        !           562:                                else
        !           563:                                        read(file,&sbbs->cfg.phub[i]->last,sizeof(time_t)); 
        !           564:                        }
        !           565:                        close(file);
        !           566: 
        !           567:                        scfg_reloaded=false;
        !           568:                }
        !           569: 
        !           570:                now=time(NULL);
        !           571:                now_tm=*gmtime(&now);
        !           572: 
        !           573:                /* QWK events */
        !           574:                if(!(startup->options&BBS_OPT_NO_QWK_EVENTS)) {
        !           575:                        /* Import any REP files that have magically appeared (via FTP perhaps) */
        !           576:                        sprintf(str,"%sfile/",sbbs->cfg.data_dir);
        !           577:                        offset=strlen(str);
        !           578:                        strcat(str,"*.rep");
        !           579:                        glob(str,0,NULL,&g);
        !           580:                        for(i=0;i<(int)g.gl_pathc;i++) {
        !           581:                                sbbs->useron.number=atoi(g.gl_pathv[i]+offset);
        !           582:                                getuserdat(&sbbs->cfg,&sbbs->useron);
        !           583:                                if(sbbs->useron.number && flength(g.gl_pathv[i])>0) {
        !           584:                                        sbbs->online=ON_LOCAL;
        !           585:                                        lprintf("Un-packing QWK Reply packet from %s",sbbs->useron.alias);
        !           586:                                        sbbs->getusrsubs();
        !           587:                                        sbbs->unpack_rep(g.gl_pathv[i]);
        !           588:                                        /* putuserdat? */
        !           589:                                        remove(g.gl_pathv[i]);
        !           590:                                }
        !           591:                        }
        !           592:                        globfree(&g);
        !           593: 
        !           594:                        /* Create any QWK files that have magically appeared (via FTP perhaps) */
        !           595:                        sprintf(str,"%spack*.now",sbbs->cfg.data_dir);
        !           596:                        offset=strlen(sbbs->cfg.data_dir)+4;
        !           597:                        glob(str,0,NULL,&g);
        !           598:                        for(i=0;i<(int)g.gl_pathc;i++) {
        !           599:                                sbbs->useron.number=atoi(g.gl_pathv[i]+offset);
        !           600:                                getuserdat(&sbbs->cfg,&sbbs->useron);
        !           601:                                if(sbbs->useron.number && !(sbbs->useron.misc&(DELETED|INACTIVE))) {
        !           602:                                        lprintf("Packing QWK Message Packet for %s",sbbs->useron.alias);
        !           603:                                        sbbs->online=ON_LOCAL;
        !           604:                                        sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !           605:                                        sbbs->getmsgptrs();
        !           606:                                        sbbs->getusrsubs();
        !           607:                                        sbbs->batdn_total=0;
        !           608:                                        sprintf(str,"%sfile%c%04u.qwk"
        !           609:                                                ,sbbs->cfg.data_dir,BACKSLASH,sbbs->useron.number);
        !           610:                                        if(sbbs->pack_qwk(str,&l,1)) {
        !           611:                                                lprintf("Packing completed");
        !           612:                                                sbbs->qwk_success(l,0,1);
        !           613:                                                sbbs->putmsgptrs(); 
        !           614:                                        } else
        !           615:                                                lprintf("No packet created (no new messages)");
        !           616:                                        sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !           617:                                        sbbs->online=0;
        !           618:                                }
        !           619:                                remove(g.gl_pathv[i]);
        !           620:                        }
        !           621:                        globfree(&g);
        !           622: 
        !           623:                        /* Create (pre-pack) QWK files for users configured as such */
        !           624:                        sprintf(semfile,"%sprepack.now",sbbs->cfg.data_dir);
        !           625:                        if(sbbs->cfg.preqwk_ar[0] 
        !           626:                                && (fexist(semfile) || (now-lastprepack)/60>(60*24))) {
        !           627:                                j=lastuser(&sbbs->cfg);
        !           628:                                lprintf("Pre-packing QWK Message packets...");
        !           629:                                for(i=1;i<=j;i++) {
        !           630: 
        !           631:                                        sprintf(str,"%5u of %-5u",i,j);
        !           632:                                        status(str);
        !           633:                                        sbbs->useron.number=i;
        !           634:                                        getuserdat(&sbbs->cfg,&sbbs->useron);
        !           635: 
        !           636:                                        if(sbbs->useron.number
        !           637:                                                && !(sbbs->useron.misc&(DELETED|INACTIVE))       /* Pre-QWK */
        !           638:                                                && sbbs->chk_ar(sbbs->cfg.preqwk_ar,&sbbs->useron)) { 
        !           639:                                                for(k=1;k<=sbbs->cfg.sys_nodes;k++) {
        !           640:                                                        sbbs->getnodedat(k,&node,0);
        !           641:                                                        if((node.status==NODE_INUSE || node.status==NODE_QUIET
        !           642:                                                                || node.status==NODE_LOGON) && node.useron==i)
        !           643:                                                                break; 
        !           644:                                                }
        !           645:                                                if(k<=sbbs->cfg.sys_nodes)      /* Don't pre-pack with user online */
        !           646:                                                        continue;
        !           647:                                                lprintf("Pre-packing QWK for %s",sbbs->useron.alias);
        !           648:                                                sbbs->online=ON_LOCAL;
        !           649:                                                sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !           650:                                                sbbs->getmsgptrs();
        !           651:                                                sbbs->getusrsubs();
        !           652:                                                sbbs->batdn_total=0;
        !           653:                                                sprintf(str,"%sfile%c%04u.qwk"
        !           654:                                                        ,sbbs->cfg.data_dir,BACKSLASH,sbbs->useron.number);
        !           655:                                                if(sbbs->pack_qwk(str,&l,1)) {
        !           656:                                                        sbbs->qwk_success(l,0,1);
        !           657:                                                        sbbs->putmsgptrs(); 
        !           658:                                                }
        !           659:                                                sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !           660:                                                sbbs->online=0;
        !           661:                                        } 
        !           662:                                }
        !           663:                                lastprepack=now;
        !           664:                                sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
        !           665:                                if((file=sbbs->nopen(str,O_WRONLY))==-1) {
        !           666:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
        !           667:                                        break; }
        !           668:                                lseek(file,(long)sbbs->cfg.total_events*4L,SEEK_SET);
        !           669:                                write(file,&lastprepack,sizeof(time_t));
        !           670:                                close(file);
        !           671: 
        !           672:                                remove(semfile);
        !           673:                                status(STATUS_WFC);
        !           674:                        }
        !           675:                }
        !           676: 
        !           677:                /* Node Daily Events */
        !           678:                for(i=startup->first_node;i<=startup->last_node;i++) {
        !           679:                        // Node Daily Event
        !           680:                        sbbs->getnodedat(i,&node,0);
        !           681:                        if(node.misc&NODE_EVENT && node.status==NODE_WFC) {
        !           682:                                sbbs->getnodedat(i,&node,1);
        !           683:                                node.status=NODE_EVENT_RUNNING;
        !           684:                                sbbs->putnodedat(i,&node);
        !           685:                                if(sbbs->cfg.node_daily[0]) {
        !           686:                                        sbbs->cfg.node_num=i;
        !           687:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[i-1]);
        !           688: 
        !           689:                                        status("Running node daily event");
        !           690:                                        sbbs->logentry("!:","Run node daily event");
        !           691:                                        sbbs->external(
        !           692:                                                 sbbs->cmdstr(sbbs->cfg.node_daily,nulstr,nulstr,NULL)
        !           693:                                                ,EX_OFFLINE);
        !           694:                                        status(STATUS_WFC);
        !           695:                                }
        !           696:                                sbbs->getnodedat(i,&node,1);
        !           697:                                node.misc&=~NODE_EVENT;
        !           698:                                node.status=NODE_WFC;
        !           699:                                node.useron=0;
        !           700:                                sbbs->putnodedat(i,&node); 
        !           701:                        }
        !           702:                }
        !           703: 
        !           704:                /* QWK Networking Call-out sempahores */
        !           705:                for(i=0;i<sbbs->cfg.total_qhubs;i++)
        !           706:                        if(sbbs->cfg.qhub[i]->node>=startup->first_node 
        !           707:                                && sbbs->cfg.qhub[i]->node<=startup->last_node) {
        !           708:                                sprintf(str,"%sqnet/%s.now",sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
        !           709:                                if(fexist(str))
        !           710:                                        sbbs->cfg.qhub[i]->last=-1; 
        !           711:                        }
        !           712: 
        !           713:                /* Timed Event sempahores */
        !           714:                for(i=0;i<sbbs->cfg.total_events;i++)
        !           715:                        if((sbbs->cfg.event[i]->node>=startup->first_node
        !           716:                                && sbbs->cfg.event[i]->node<=startup->last_node)
        !           717:                                || sbbs->cfg.event[i]->misc&EVENT_EXCL) {
        !           718:                                sprintf(str,"%s%s.now",sbbs->cfg.data_dir,sbbs->cfg.event[i]->code);
        !           719:                                if(fexist(str))
        !           720:                                        sbbs->cfg.event[i]->last=-1; 
        !           721:                        }
        !           722: 
        !           723:                /* QWK Networking Call-out Events */
        !           724:                for(i=0;i<sbbs->cfg.total_qhubs;i++) {
        !           725:                        if(sbbs->cfg.qhub[i]->node<startup->first_node ||
        !           726:                                sbbs->cfg.qhub[i]->node>startup->last_node)
        !           727:                                continue;
        !           728: 
        !           729:                        // See if any packets have come in
        !           730:                        for(j=0;j<101;j++) {
        !           731:                                sprintf(str,"%s%s.q%c%c",sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id
        !           732:                                        ,j>10 ? ((j-1)/10)+'0' : 'w'
        !           733:                                        ,j ? ((j-1)%10)+'0' : 'k');
        !           734:                                if(fexist(str)) {
        !           735:                                        sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !           736:                                        if(sbbs->unpack_qwk(str,i)==false) {
        !           737:                                                char newname[MAX_PATH+1];
        !           738:                                                sprintf(newname,"%s.%lx.bad",str,now);
        !           739:                                                remove(newname);
        !           740:                                                if(rename(str,newname)==0) {
        !           741:                                                        char logmsg[MAX_PATH*3];
        !           742:                                                        sprintf(logmsg,"%s renamed to %s",str,newname);
        !           743:                                                        sbbs->logline("Q!",logmsg);
        !           744:                                                }
        !           745:                                        }
        !           746:                                        remove(str);
        !           747:                                } 
        !           748:                        }
        !           749: 
        !           750:                        tm=gmtime(&sbbs->cfg.qhub[i]->last); /* Qnet call out based on time */
        !           751:                        if((tm==NULL || sbbs->cfg.qhub[i]->last==-1L                                    /* or frequency */
        !           752:                                || ((sbbs->cfg.qhub[i]->freq
        !           753:                                        && (now-sbbs->cfg.qhub[i]->last)/60>sbbs->cfg.qhub[i]->freq)
        !           754:                                        || (sbbs->cfg.qhub[i]->time
        !           755:                                                && (now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.qhub[i]->time
        !           756:                                                && (now_tm.tm_mday!=tm->tm_mday || now_tm.tm_mon!=tm->tm_mon)))
        !           757:                                                && sbbs->cfg.qhub[i]->days&(1<<now_tm.tm_wday))) {
        !           758:                                sprintf(str,"%sqnet/%s.now"
        !           759:                                        ,sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
        !           760:                                remove(str);                                    /* Remove semaphore file */
        !           761:                                sprintf(str,"%sqnet/%s.ptr"
        !           762:                                        ,sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
        !           763:                                file=sbbs->nopen(str,O_RDONLY);
        !           764:                                for(j=0;j<sbbs->cfg.qhub[i]->subs;j++) {
        !           765:                                        sbbs->sub_ptr[sbbs->cfg.qhub[i]->sub[j]]=0;
        !           766:                                        lseek(file,sbbs->cfg.sub[sbbs->cfg.qhub[i]->sub[j]]->ptridx*4L,SEEK_SET);
        !           767:                                        read(file,&sbbs->sub_ptr[sbbs->cfg.qhub[i]->sub[j]],4); 
        !           768:                                }
        !           769:                                if(file!=-1)
        !           770:                                        close(file);
        !           771:                                if(sbbs->pack_rep(i)) {
        !           772:                                        if((file=sbbs->nopen(str,O_WRONLY|O_CREAT))==-1)
        !           773:                                                sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT);
        !           774:                                        else {
        !           775:                                                for(j=l=0;j<sbbs->cfg.qhub[i]->subs;j++) {
        !           776:                                                        while(filelength(file)<
        !           777:                                                                sbbs->cfg.sub[sbbs->cfg.qhub[i]->sub[j]]->ptridx*4L)
        !           778:                                                                write(file,&l,4);               /* initialize ptrs to null */
        !           779:                                                        lseek(file,sbbs->cfg.sub[sbbs->cfg.qhub[i]->sub[j]]->ptridx*4L,SEEK_SET);
        !           780:                                                        write(file,&sbbs->sub_ptr[sbbs->cfg.qhub[i]->sub[j]],4); }
        !           781:                                                close(file); } }
        !           782:                                sbbs->delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !           783: 
        !           784:                                sbbs->cfg.qhub[i]->last=time(NULL);
        !           785:                                sprintf(str,"%sqnet.dab",sbbs->cfg.ctrl_dir);
        !           786:                                if((file=sbbs->nopen(str,O_WRONLY))==-1) {
        !           787:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
        !           788:                                        break; 
        !           789:                                }
        !           790:                                lseek(file,sizeof(time_t)*i,SEEK_SET);
        !           791:                                write(file,&sbbs->cfg.qhub[i]->last,sizeof(time_t));
        !           792:                                close(file);
        !           793: 
        !           794:                                if(sbbs->cfg.qhub[i]->call[0]) {
        !           795:                                        sbbs->cfg.node_num=sbbs->cfg.qhub[i]->node;
        !           796:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[sbbs->cfg.node_num-1]);
        !           797:                                        status("QWK Networking");
        !           798: #if 0
        !           799:                                        sbbs->getnodedat(sbbs->cfg.qhub[i]->node,&node,1);
        !           800:                                        node.status=NODE_NETTING;
        !           801:                                        sbbs->putnodedat(sbbs->cfg.qhub[i]->node,&node);
        !           802: #endif
        !           803:                                        sbbs->external(
        !           804:                                                 sbbs->cmdstr(sbbs->cfg.qhub[i]->call,nulstr,nulstr,NULL)
        !           805:                                                ,EX_OFFLINE);
        !           806:                                        status(STATUS_WFC);
        !           807:                                }
        !           808:                        } 
        !           809:                }
        !           810: 
        !           811:                /* PostLink Networking Call-out Events */
        !           812:                for(i=0;i<sbbs->cfg.total_phubs;i++) {
        !           813:                        if(sbbs->cfg.phub[i]->node<startup->first_node 
        !           814:                                || sbbs->cfg.phub[i]->node>startup->last_node)
        !           815:                                continue;
        !           816:                        tm=localtime(&sbbs->cfg.phub[i]->last);   /* PostLink call out based on time */
        !           817:                        if(tm==NULL)
        !           818:                                continue;
        !           819:                        if(((sbbs->cfg.phub[i]->freq                                                            /* or frequency */
        !           820:                                        && (now-sbbs->cfg.phub[i]->last)/60>sbbs->cfg.phub[i]->freq)
        !           821:                                || (sbbs->cfg.phub[i]->time
        !           822:                                        && (now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.phub[i]->time
        !           823:                                && (now_tm.tm_mday!=tm->tm_mday || now_tm.tm_mon!=tm->tm_mon)))
        !           824:                                && sbbs->cfg.phub[i]->days&(1<<now_tm.tm_wday)) {
        !           825: 
        !           826:                                sbbs->cfg.phub[i]->last=time(NULL);
        !           827:                                sprintf(str,"%spnet.dab",sbbs->cfg.ctrl_dir);
        !           828:                                if((file=sbbs->nopen(str,O_WRONLY))==-1) {
        !           829:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
        !           830:                                        break; 
        !           831:                                }
        !           832:                                lseek(file,sizeof(time_t)*i,SEEK_SET);
        !           833:                                write(file,&sbbs->cfg.phub[i]->last,sizeof(time_t));
        !           834:                                close(file);
        !           835: 
        !           836:                                if(sbbs->cfg.phub[i]->call[0]) {
        !           837:                                        sbbs->cfg.node_num=sbbs->cfg.event[i]->node;
        !           838:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[sbbs->cfg.node_num-1]);
        !           839:                                        status("PostLink Networking");
        !           840: #if 0
        !           841:                                        sbbs->getnodedat(sbbs->cfg.phub[i]->node,&node,1);
        !           842:                                        node.status=NODE_NETTING;
        !           843:                                        sbbs->putnodedat(sbbs->cfg.phub[i]->node,&node);
        !           844: #endif
        !           845:                                        sbbs->external(
        !           846:                                                 sbbs->cmdstr(sbbs->cfg.phub[i]->call,nulstr,nulstr,NULL)
        !           847:                                                        ,EX_OFFLINE);
        !           848:                                        status(STATUS_WFC);
        !           849:                                } 
        !           850:                        }
        !           851:                }
        !           852: 
        !           853:                /* Timed Events */
        !           854:                for(i=0;i<sbbs->cfg.total_events;i++) {
        !           855:                        if(!sbbs->cfg.event[i]->node || sbbs->cfg.event[i]->node>sbbs->cfg.sys_nodes)
        !           856:                                continue;
        !           857:                        tm=gmtime(&sbbs->cfg.event[i]->last);
        !           858:                        if(tm==NULL || sbbs->cfg.event[i]->last==-1
        !           859:                                || ((now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.event[i]->time
        !           860:                                && (now_tm.tm_mday!=tm->tm_mday || now_tm.tm_mon!=tm->tm_mon)
        !           861:                                && sbbs->cfg.event[i]->days&(1<<now_tm.tm_wday))) {
        !           862: 
        !           863:                                if(sbbs->cfg.event[i]->misc&EVENT_EXCL) { /* exclusive event */
        !           864: 
        !           865:                                        if(sbbs->cfg.event[i]->node<startup->first_node
        !           866:                                                || sbbs->cfg.event[i]->node>startup->last_node) {
        !           867:                                                sprintf(str,"Waiting for node %d to run timed event."
        !           868:                                                        ,sbbs->cfg.event[i]->node);
        !           869:                                                status(str);
        !           870:                                                lastnodechk=0;   /* really last event time check */
        !           871:                                                while(!sbbs->terminated) {
        !           872:                                                        mswait(1000);
        !           873:                                                        now=time(NULL);
        !           874:                                                        if(now-lastnodechk<10)
        !           875:                                                                continue;
        !           876:                                                        for(j=startup->first_node;j<=startup->last_node;j++) {
        !           877:                                                                sbbs->getnodedat(j,&node,1);
        !           878:                                                                if(node.status==NODE_WFC)
        !           879:                                                                        node.status=NODE_EVENT_LIMBO;
        !           880:                                                                node.aux=sbbs->cfg.event[i]->node;
        !           881:                                                                sbbs->putnodedat(j,&node);
        !           882:                                                        }
        !           883: 
        !           884: #if 0
        !           885:                                                        getnodedat(node_num,&thisnode,0);
        !           886:                                                        if(thisnode.misc&NODE_DOWN)
        !           887:                                                                return(0);
        !           888: #endif
        !           889:                                                        lastnodechk=now;
        !           890:                                                        sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
        !           891:                                                        if((file=sbbs->nopen(str,O_RDONLY))==-1) {
        !           892:                                                                sbbs->errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
        !           893:                                                                sbbs->cfg.event[i]->last=now;
        !           894:                                                                continue; }
        !           895:                                                        lseek(file,(long)i*4L,SEEK_SET);
        !           896:                                                        read(file,&sbbs->cfg.event[i]->last,sizeof(time_t));
        !           897:                                                        close(file);
        !           898:                                                        if(now-sbbs->cfg.event[i]->last<(60*60))        /* event is done */
        !           899:                                                                break; }
        !           900:                                                sprintf(str,"%s%s.now",sbbs->cfg.data_dir,sbbs->cfg.event[i]->code);
        !           901:                                                remove(str);
        !           902:                                                sbbs->cfg.event[i]->last=now;
        !           903:                                        } else {        // Exclusive event to run on a node under our control
        !           904:                                                status("Waiting for all nodes to become inactive before "
        !           905:                                                        "running timed event.");
        !           906:                                                lastnodechk=0;
        !           907:                                                while(!sbbs->terminated) {
        !           908:                                                        mswait(1000);
        !           909:                                                        now=time(NULL);
        !           910:                                                        if(now-lastnodechk<10)
        !           911:                                                                continue;
        !           912:                                                        lastnodechk=now;
        !           913: #if 0
        !           914:                                                        getnodedat(node_num,&thisnode,0);
        !           915:                                                        if(thisnode.misc&NODE_DOWN)
        !           916:                                                                return(0);
        !           917: #endif
        !           918:                                                        // Check/change the status of the nodes that we're in control of
        !           919:                                                        for(j=startup->first_node;j<=startup->last_node;j++) {
        !           920:                                                                sbbs->getnodedat(j,&node,1);
        !           921:                                                                if(node.status==NODE_WFC) {
        !           922:                                                                        if(j==sbbs->cfg.event[i]->node)
        !           923:                                                                                node.status=NODE_EVENT_WAITING;
        !           924:                                                                        else
        !           925:                                                                                node.status=NODE_EVENT_LIMBO;
        !           926:                                                                        node.aux=sbbs->cfg.event[i]->node;
        !           927:                                                                }
        !           928:                                                                sbbs->putnodedat(j,&node);
        !           929:                                                        }
        !           930: 
        !           931:                                                        for(j=1;j<=sbbs->cfg.sys_nodes;j++) {
        !           932:                                                                sbbs->getnodedat(j,&node,0);
        !           933:                                                                if(j==sbbs->cfg.event[i]->node) {
        !           934:                                                                        if(node.status!=NODE_EVENT_WAITING)
        !           935:                                                                                break;
        !           936:                                                                } else {
        !           937:                                                                        if(node.status!=NODE_OFFLINE
        !           938:                                                                                && node.status!=NODE_EVENT_LIMBO)
        !           939:                                                                                break; 
        !           940:                                                                }
        !           941:                                                        }
        !           942:                                                        if(j>sbbs->cfg.sys_nodes) /* all nodes either offline or in limbo */
        !           943:                                                                break;
        !           944:                                                        sprintf(str,"Waiting for node %d (status=%d)"
        !           945:                                                                ,j,node.status);
        !           946:                                                        status(str);
        !           947:                                                } 
        !           948:                                        } 
        !           949:                                }
        !           950:                                else {  /* non-exclusive */
        !           951:                                        sbbs->getnodedat(sbbs->cfg.event[i]->node,&node,0);
        !           952:                                        if(node.status!=NODE_WFC)
        !           953:                                                continue;
        !           954:                                }
        !           955:                                if(sbbs->cfg.event[i]->node<startup->first_node 
        !           956:                                        || sbbs->cfg.event[i]->node>startup->last_node) {
        !           957:                                        sbbs->cfg.event[i]->last=now;
        !           958:                                        for(j=startup->first_node;j<=startup->last_node;j++) {
        !           959:                                                sbbs->getnodedat(j,&node,1);
        !           960:                                                node.status=NODE_WFC;
        !           961:                                                sbbs->putnodedat(j,&node);
        !           962:                                        }
        !           963:                                }
        !           964:                                else {
        !           965:                                        sbbs->cfg.node_num=sbbs->cfg.event[i]->node;
        !           966:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[sbbs->cfg.node_num-1]);
        !           967:                                
        !           968:                                        sprintf(str,"%s%s.now",sbbs->cfg.data_dir,sbbs->cfg.event[i]->code);
        !           969:                                        remove(str);
        !           970:                                        if(sbbs->cfg.event[i]->misc&EVENT_EXCL) {
        !           971:                                                sbbs->getnodedat(sbbs->cfg.event[i]->node,&node,1);
        !           972:                                                node.status=NODE_EVENT_RUNNING;
        !           973:                                                sbbs->putnodedat(sbbs->cfg.event[i]->node,&node);
        !           974:                                        }
        !           975:                                        lprintf("Running event: %s",sbbs->cfg.event[i]->code);
        !           976:                                        sbbs->external(
        !           977:                                                 sbbs->cmdstr(sbbs->cfg.event[i]->cmd,nulstr,nulstr,NULL)
        !           978:                                                ,EX_OFFLINE
        !           979:                                                ,sbbs->cfg.event[i]->dir);
        !           980:                                        sbbs->cfg.event[i]->last=time(NULL);
        !           981:                                        sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
        !           982:                                        if((file=sbbs->nopen(str,O_WRONLY))==-1) {
        !           983:                                                sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
        !           984:                                                break; }
        !           985:                                        lseek(file,(long)i*4L,SEEK_SET);
        !           986:                                        write(file,&sbbs->cfg.event[i]->last,sizeof(time_t));
        !           987:                                        close(file);
        !           988: 
        !           989:                                        if(sbbs->cfg.event[i]->misc&EVENT_EXCL) { /* exclusive event */
        !           990:                                                // Check/change the status of the nodes that we're in control of
        !           991:                                                for(j=startup->first_node;j<=startup->last_node;j++) {
        !           992:                                                        sbbs->getnodedat(j,&node,1);
        !           993:                                                        node.status=NODE_WFC;
        !           994:                                                        sbbs->putnodedat(j,&node);
        !           995:                                                }
        !           996:                                        }
        !           997:                                } 
        !           998:                                status(STATUS_WFC);
        !           999:                        } 
        !          1000:                }
        !          1001:                pthread_mutex_unlock(&event_mutex);
        !          1002: 
        !          1003:                mswait(1000);
        !          1004:        }
        !          1005:     sbbs->event_thread_running = false;
        !          1006: 
        !          1007:        lprintf("BBS Event thread terminated");
        !          1008: 
        !          1009:        thread_down();
        !          1010: 
        !          1011: }
        !          1012: 
        !          1013: 
        !          1014: //****************************************************************************
        !          1015: sbbs_t::sbbs_t(ushort node_num, DWORD addr, char* name, SOCKET sd,
        !          1016:                           scfg_t* global_cfg, char* global_text[])
        !          1017: {
        !          1018:        char    nodestr[32];
        !          1019:        uint    i;
        !          1020: 
        !          1021:     if(node_num)
        !          1022:        sprintf(nodestr,"BBS Node %d",node_num);
        !          1023:     else
        !          1024:        strcpy(nodestr,name);
        !          1025: 
        !          1026:        lprintf("%s constructor using socket %d", nodestr, sd);
        !          1027: 
        !          1028:        memcpy(&cfg, global_cfg, sizeof(cfg));
        !          1029: 
        !          1030:        cfg.node_num=node_num;
        !          1031:        if(node_num) {
        !          1032:                strcpy(cfg.node_dir, cfg.node_path[node_num-1]);
        !          1033:                prep_dir(cfg.node_dir, cfg.temp_dir);
        !          1034:        } else
        !          1035:        prep_dir(cfg.data_dir, cfg.temp_dir);
        !          1036: 
        !          1037:        terminated = false;
        !          1038:        event_thread_running = false;
        !          1039:     input_thread_running = false;
        !          1040:     output_thread_running = false;
        !          1041: 
        !          1042:        client_addr = addr;
        !          1043:        client_socket = sd;
        !          1044:        sprintf(client_name, "%.*s", (int)sizeof(client_name)-1, name);
        !          1045:        client_socket_dup=INVALID_SOCKET;
        !          1046: 
        !          1047:        /* Init some important variables */
        !          1048: 
        !          1049:        rio_abortable=false;
        !          1050: 
        !          1051:        console = 0;
        !          1052:        online = 0;
        !          1053:        outchar_esc = 0;
        !          1054:        nodemsg_inside = 0;     /* allows single nest */
        !          1055:        nodesync_inside = false;
        !          1056:        errorlog_inside = false;
        !          1057:        errormsg_inside = false;
        !          1058:        gettimeleft_inside = false;
        !          1059:        uselect_total = 0;
        !          1060:        lbuflen = 0;
        !          1061:        connection="Telnet";
        !          1062:     telnet_cmdlen=0;
        !          1063:        telnet_mode=0;
        !          1064:        telnet_last_rxch=0;
        !          1065:        strcpy(cap_fname,"CAPTURE.TXT");
        !          1066:        sys_status=lncntr=tos=criterrs=keybufbot=keybuftop=lbuflen=slcnt=0L;
        !          1067:        debug=1;
        !          1068:        curatr=LIGHTGRAY;
        !          1069:        errorlevel=0;
        !          1070:        logcol=1;
        !          1071:        next_event=0;
        !          1072:        lastuseron[0]=0;
        !          1073:        logfile_fp=NULL;
        !          1074:        nodefile=-1;
        !          1075:        node_ext=-1;
        !          1076:        nodefile_fp=NULL;
        !          1077:        node_ext_fp=NULL;
        !          1078: 
        !          1079:        for(i=0;i<TOTAL_TEXT;i++)
        !          1080:                text[i]=text_sav[i]=global_text[i];
        !          1081: 
        !          1082:        memset(&main_csi,0,sizeof(main_csi));
        !          1083:        memset(&thisnode,0,sizeof(thisnode));
        !          1084:        memset(&useron,0,sizeof(useron));
        !          1085:        memset(&inbuf,0,sizeof(inbuf));
        !          1086:        memset(&outbuf,0,sizeof(outbuf));
        !          1087:        memset(&smb,0,sizeof(smb));
        !          1088: 
        !          1089:        global_str_vars=0;
        !          1090:        global_str_var=NULL;
        !          1091:        global_str_var_name=NULL;
        !          1092:        global_int_vars=0;
        !          1093:        global_int_var=NULL;
        !          1094:        global_int_var_name=NULL;
        !          1095:        sysvar_li=0;
        !          1096:        sysvar_pi=0;
        !          1097: 
        !          1098:        cursub=NULL;
        !          1099:        usrgrp=NULL;
        !          1100:        usrsubs=NULL;
        !          1101:        usrsub=NULL;
        !          1102: 
        !          1103:        sub_cfg=NULL;
        !          1104:        sub_ptr=NULL;
        !          1105:        sub_last=NULL;
        !          1106:        sav_sub_cfg=NULL;
        !          1107:        sav_sub_ptr=NULL;
        !          1108:        sav_sub_last=NULL;
        !          1109: 
        !          1110: 
        !          1111:        curdir=NULL;
        !          1112:        usrlib=NULL;
        !          1113:        usrdirs=NULL;
        !          1114:        usrdir=NULL;
        !          1115: 
        !          1116:        batup_desc=NULL;
        !          1117:        batup_name=NULL;
        !          1118:        batup_misc=NULL;
        !          1119:        batup_dir=NULL;
        !          1120:        batup_alt=NULL;
        !          1121: 
        !          1122:        batdn_name=NULL;
        !          1123:        batdn_dir=NULL;
        !          1124:        batdn_offset=NULL;
        !          1125:        batdn_size=NULL;
        !          1126:        batdn_alt=NULL;
        !          1127:        batdn_cdt=NULL;
        !          1128: 
        !          1129:        spymsg("Connected");
        !          1130: }
        !          1131: 
        !          1132: //****************************************************************************
        !          1133: bool sbbs_t::init()
        !          1134: {
        !          1135:        char            str[MAX_PATH];
        !          1136:        int                     result;
        !          1137:        uint            i,j,k,l;
        !          1138:        node_t          node;
        !          1139:        socklen_t       addr_len;
        !          1140:        SOCKADDR_IN     addr;
        !          1141: 
        !          1142:        if(cfg.node_num) {
        !          1143:                RingBufInit(&inbuf, IO_THREAD_BUF_SIZE);
        !          1144:                node_inbuf[cfg.node_num-1]=&inbuf;
        !          1145:        }
        !          1146: 
        !          1147:     RingBufInit(&outbuf, IO_THREAD_BUF_SIZE);
        !          1148: 
        !          1149:        if(cfg.node_num && client_socket!=INVALID_SOCKET) {
        !          1150: 
        !          1151: #ifdef _WIN32
        !          1152:                if(!DuplicateHandle(GetCurrentProcess(),
        !          1153:                        (HANDLE)client_socket,
        !          1154:                        GetCurrentProcess(),
        !          1155:                        (HANDLE*)&client_socket_dup,
        !          1156:                        0,
        !          1157:                        TRUE, // Inheritable
        !          1158:                        DUPLICATE_SAME_ACCESS)) {
        !          1159:                        errormsg(WHERE,ERR_CREATE,"duplicate socket handle",client_socket);
        !          1160:                        return(false);
        !          1161:                }
        !          1162: #endif
        !          1163: 
        !          1164:                addr_len=sizeof(addr);
        !          1165:                if((result=getsockname(client_socket, (struct sockaddr *)&addr,&addr_len))!=0) {
        !          1166:                        lprintf("Node %d !ERROR %d (%d) getting address/port"
        !          1167:                                ,cfg.node_num, result, ERROR_VALUE);
        !          1168:                        return(false);
        !          1169:                } 
        !          1170:                lprintf("Node %d attached to local interface %s port %d"
        !          1171:                        ,cfg.node_num, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        !          1172: 
        !          1173:                local_addr=addr.sin_addr.s_addr;
        !          1174:        }
        !          1175: 
        !          1176:        comspec=getenv(
        !          1177: #ifdef __unix__
        !          1178:                "SHELL"
        !          1179: #else
        !          1180:                "COMSPEC"
        !          1181: #endif
        !          1182:                );
        !          1183:        if(comspec==NULL) {
        !          1184:                errormsg(WHERE, ERR_CHK, "shell/comspec", 0);
        !          1185:                return(false);
        !          1186:        }
        !          1187: 
        !          1188: #ifdef _WIN32
        !          1189:        output_sem=CreateEvent(
        !          1190:                                         NULL   // pointer to security attributes
        !          1191:                                        ,true   // flag for manual-reset event
        !          1192:                                        ,false  // flag for initial state
        !          1193:                                        ,NULL   // pointer to event-object name
        !          1194:                                        );
        !          1195:        if(output_sem==NULL) {
        !          1196:                errormsg(WHERE, ERR_CREATE, "output_sem", 0);
        !          1197:                return(false);
        !          1198:        }
        !          1199: #endif
        !          1200:        sem_init(&output_sem,0,0);
        !          1201: 
        !          1202:        strcpy(str,cfg.temp_dir);
        !          1203:        if(strcmp(str+1,":\\") && strcmp(str+1,":/"))     /* not root directory */
        !          1204:            str[strlen(str)-1]=0;   /* chop off '\' */
        !          1205:        md(str);
        !          1206: 
        !          1207:        /* Shared NODE files */
        !          1208:        sprintf(str,"%s%s",cfg.ctrl_dir,"node.dab");
        !          1209:        if((nodefile=nopen(str,O_DENYNONE|O_RDWR|O_CREAT))==-1) {
        !          1210:                errormsg(WHERE, ERR_OPEN, str, cfg.node_num);
        !          1211:                return(false); 
        !          1212:        }
        !          1213:        memset(&node,0,sizeof(node_t));  /* write NULL to node struct */
        !          1214:        node.status=NODE_OFFLINE;
        !          1215:        while(filelength(nodefile)<(long)(cfg.sys_nodes*sizeof(node_t))) {
        !          1216:                lseek(nodefile,0L,SEEK_END);
        !          1217:                write(nodefile,&node,sizeof(node_t)); 
        !          1218:        }
        !          1219:        if(cfg.node_num) {
        !          1220:                if(lock(nodefile,(cfg.node_num-1)*sizeof(node_t),sizeof(node_t))
        !          1221:                        || unlock(nodefile,(cfg.node_num-1)*sizeof(node_t),sizeof(node_t))) {
        !          1222:                        errormsg(WHERE, ERR_LOCK, str, cfg.node_num);
        !          1223:                        return(false); 
        !          1224:                }
        !          1225:        }
        !          1226:        close(nodefile);
        !          1227:        nodefile=-1;
        !          1228: 
        !          1229: #if 0
        !          1230:        sprintf(str,"%s%s",cfg.ctrl_dir,"node.exb");
        !          1231:        if((node_ext_fp=fnopen(&node_ext,str,O_DENYNONE|O_RDWR|O_CREAT))==NULL) {
        !          1232:                errormsg(WHERE, ERR_FDOPEN, str, cfg.node_num);
        !          1233:                return(false); 
        !          1234:        }
        !          1235: #endif
        !          1236: 
        !          1237:        if(cfg.node_num) {
        !          1238:                sprintf(str,"%snode.log",cfg.node_dir);
        !          1239:                if((logfile_fp=fopen(str,"a+b"))==NULL) {
        !          1240:                        errormsg(WHERE, ERR_OPEN, str, 0);
        !          1241:                        lprintf("Perhaps this node is already running");
        !          1242:                        return(false); }
        !          1243: 
        !          1244:                if(filelength(fileno(logfile_fp))) {
        !          1245:                        log(crlf);
        !          1246:                        now=time(NULL);
        !          1247:                        struct tm * tm=localtime(&now);
        !          1248:                        if(tm!=NULL)
        !          1249:                        sprintf(str,"%02d:%02d%c  %s %s %02d %u  "
        !          1250:                                "End of preexisting log entry (possible crash)"
        !          1251:                                ,tm->tm_hour>12 ? tm->tm_hour-12 : tm->tm_hour==0 ? 12 : tm->tm_hour
        !          1252:                                ,tm->tm_min,tm->tm_hour>=12 ? 'p' : 'a',wday[tm->tm_wday]
        !          1253:                                ,mon[tm->tm_mon],tm->tm_mday,tm->tm_year+1900);
        !          1254:                        logline("L!",str);
        !          1255:                        log(crlf);
        !          1256:                        catsyslog(1)        !          1257:                }
        !          1258: 
        !          1259:                getnodedat(cfg.node_num,&thisnode,1);
        !          1260:                /* thisnode.status=0; */
        !          1261:                thisnode.action=0;
        !          1262:                thisnode.useron=0;
        !          1263:                thisnode.aux=0;
        !          1264:                thisnode.misc&=(NODE_EVENT|NODE_LOCK);
        !          1265:                criterrs=thisnode.errors;
        !          1266:                putnodedat(cfg.node_num,&thisnode);
        !          1267:        }
        !          1268: 
        !          1269: /** Put in if(cfg.node_num) ? (not needed for server and event threads) */
        !          1270:        backout();
        !          1271: 
        !          1272:        /* Reset COMMAND SHELL */
        !          1273: 
        !          1274:        main_csi.str=(char *)MALLOC(1024);
        !          1275:        if(main_csi.str==NULL) {
        !          1276:                errormsg(WHERE,ERR_ALLOC,"main_csi.str",1024);
        !          1277:                return(false); 
        !          1278:        }
        !          1279:        memset(main_csi.str,0,1024);
        !          1280: /***/
        !          1281: 
        !          1282:        if(cfg.total_grps) {
        !          1283: 
        !          1284:                if((cursub=(uint *)MALLOC(sizeof(uint)*cfg.total_grps))==NULL) {
        !          1285:                        errormsg(WHERE, ERR_ALLOC, "cursub", sizeof(uint)*cfg.total_grps);
        !          1286:                        return(false);
        !          1287:                }
        !          1288: 
        !          1289:                if((usrgrp=(uint *)MALLOC(sizeof(uint)*cfg.total_grps))==NULL) {
        !          1290:                        errormsg(WHERE, ERR_ALLOC, "usrgrp", sizeof(uint)*cfg.total_grps);
        !          1291:                        return(false);
        !          1292:                }
        !          1293: 
        !          1294:                if((usrsubs=(uint *)MALLOC(sizeof(uint)*cfg.total_grps))==NULL) {
        !          1295:                        errormsg(WHERE, ERR_ALLOC, "usrsubs", sizeof(uint)*cfg.total_grps);
        !          1296:                        return(false);
        !          1297:                }
        !          1298: 
        !          1299:                if((usrsub=(uint **)MALLOC(sizeof(uint *)*cfg.total_grps))==NULL) {
        !          1300:                        errormsg(WHERE, ERR_ALLOC, "usrsub", sizeof(uint)*cfg.total_grps);
        !          1301:                        return(false);
        !          1302:                }
        !          1303:  
        !          1304:                if((sub_cfg=(ushort *)MALLOC(sizeof(ushort)*cfg.total_subs))==NULL) {
        !          1305:                        errormsg(WHERE, ERR_ALLOC, "sub_cfg", sizeof(ushort)*cfg.total_subs);
        !          1306:                        return(false);
        !          1307:                }
        !          1308: 
        !          1309:                if((sub_ptr=(ulong *)MALLOC(sizeof(ulong)*cfg.total_subs))==NULL) {
        !          1310:                        errormsg(WHERE, ERR_ALLOC, "sub_ptr", sizeof(ulong)*cfg.total_subs);
        !          1311:                        return(false);
        !          1312:                }
        !          1313: 
        !          1314:                if((sub_last=(ulong *)MALLOC(sizeof(ulong)*cfg.total_subs))==NULL) {
        !          1315:                        errormsg(WHERE, ERR_ALLOC, "sub_last", sizeof(ulong)*cfg.total_subs);
        !          1316:                        return(false); 
        !          1317:                }
        !          1318: 
        !          1319:                if((sav_sub_cfg=(ushort *)MALLOC(sizeof(ushort)*cfg.total_subs))==NULL) {
        !          1320:                        errormsg(WHERE, ERR_ALLOC, "sav_sub_cfg", sizeof(ushort)*cfg.total_subs);
        !          1321:                        return(false);
        !          1322:                }
        !          1323: 
        !          1324:                if((sav_sub_ptr=(ulong *)MALLOC(sizeof(ulong)*cfg.total_subs))==NULL) {
        !          1325:                        errormsg(WHERE, ERR_ALLOC, "sav_sub_ptr", sizeof(ulong)*cfg.total_subs);
        !          1326:                        return(false);
        !          1327:                }
        !          1328: 
        !          1329:                if((sav_sub_last=(ulong *)MALLOC(sizeof(ulong)*cfg.total_subs))==NULL) {
        !          1330:                        errormsg(WHERE, ERR_ALLOC, "sav_sub_last", sizeof(ulong)*cfg.total_subs);
        !          1331:                        return(false); 
        !          1332:                }
        !          1333: 
        !          1334:        }
        !          1335: 
        !          1336: 
        !          1337:        for(i=l=0;i<(uint)cfg.total_grps;i++) {
        !          1338:                for(j=k=0;j<cfg.total_subs;j++)
        !          1339:                        if(cfg.sub[j]->grp==i)
        !          1340:                                k++;    /* k = number of subs per grp[i] */
        !          1341:                if(k>l) l=k;    /* l = the largest number of subs per grp */
        !          1342:        }
        !          1343:        if(l)
        !          1344:                for(i=0;i<cfg.total_grps;i++)
        !          1345:                        if((usrsub[i]=(uint *)MALLOC(sizeof(uint)*l))==NULL) {
        !          1346:                                errormsg(WHERE, ERR_ALLOC, "usrsub[x]", sizeof(uint)*l);
        !          1347:                                return(false);
        !          1348:                        }
        !          1349: 
        !          1350:        if(cfg.total_libs) {
        !          1351: 
        !          1352:                if((curdir=(uint *)MALLOC(sizeof(uint)*cfg.total_libs))==NULL) {
        !          1353:                        errormsg(WHERE, ERR_ALLOC, "curdir", sizeof(uint)*cfg.total_libs);
        !          1354:                        return(false);
        !          1355:                }
        !          1356: 
        !          1357:                if((usrlib=(uint *)MALLOC(sizeof(uint)*cfg.total_libs))==NULL) {
        !          1358:                        errormsg(WHERE, ERR_ALLOC, "usrlib", sizeof(uint)*cfg.total_libs);
        !          1359:                        return(false);
        !          1360:                }
        !          1361: 
        !          1362:                if((usrdirs=(uint *)MALLOC(sizeof(uint)*cfg.total_libs))==NULL) {
        !          1363:                        errormsg(WHERE, ERR_ALLOC, "usrdirs", sizeof(uint)*cfg.total_libs);
        !          1364:                        return(false);
        !          1365:                }
        !          1366: 
        !          1367:                if((usrdir=(uint **)MALLOC(sizeof(uint *)*cfg.total_libs))==NULL) {
        !          1368:                        errormsg(WHERE, ERR_ALLOC, "usrdir", sizeof(uint)*cfg.total_libs);
        !          1369:                        return(false);
        !          1370:                }
        !          1371:        }
        !          1372: 
        !          1373:        for(i=l=0;i<cfg.total_libs;i++) {
        !          1374:                for(j=k=0;j<cfg.total_dirs;j++)
        !          1375:                        if(cfg.dir[j]->lib==i)
        !          1376:                                k++;
        !          1377:                if(k>l) l=k;    /* l = largest number of dirs in a lib */
        !          1378:        }
        !          1379:        if(l) {
        !          1380:                l++;    /* for temp dir */
        !          1381:                for(i=0;i<cfg.total_libs;i++)
        !          1382:                        if((usrdir[i]=(uint *)MALLOC(sizeof(uint)*l))==NULL) {
        !          1383:                                errormsg(WHERE, ERR_ALLOC, "usrdir[x]", sizeof(uint)*l);
        !          1384:                                return(false);
        !          1385:                        }
        !          1386:        }
        !          1387:  
        !          1388:        if(cfg.max_batup) {
        !          1389: 
        !          1390:                if((batup_desc=(char **)MALLOC(sizeof(char *)*cfg.max_batup))==NULL) {
        !          1391:                        errormsg(WHERE, ERR_ALLOC, "batup_desc", sizeof(char *)*cfg.max_batup);
        !          1392:                        return(false);
        !          1393:                }
        !          1394:                if((batup_name=(char **)MALLOC(sizeof(char *)*cfg.max_batup))==NULL) {
        !          1395:                        errormsg(WHERE, ERR_ALLOC, "batup_name", sizeof(char *)*cfg.max_batup);
        !          1396:                        return(false);
        !          1397:                }
        !          1398:                if((batup_misc=(long *)MALLOC(sizeof(long)*cfg.max_batup))==NULL) {
        !          1399:                        errormsg(WHERE, ERR_ALLOC, "batup_misc", sizeof(char *)*cfg.max_batup);
        !          1400:                        return(false);
        !          1401:                }
        !          1402:                if((batup_dir=(uint *)MALLOC(sizeof(uint)*cfg.max_batup))==NULL) {
        !          1403:                        errormsg(WHERE, ERR_ALLOC, "batup_dir", sizeof(char *)*cfg.max_batup);
        !          1404:                        return(false);
        !          1405:                }
        !          1406:                if((batup_alt=(ushort *)MALLOC(sizeof(ushort)*cfg.max_batup))==NULL) {
        !          1407:                        errormsg(WHERE, ERR_ALLOC, "batup_alt", sizeof(char *)*cfg.max_batup);
        !          1408:                        return(false);
        !          1409:                }
        !          1410:                for(i=0;i<cfg.max_batup;i++) {
        !          1411:                        if((batup_desc[i]=(char *)MALLOC(59))==NULL) {
        !          1412:                                errormsg(WHERE, ERR_ALLOC, "batup_desc[x]", 59);
        !          1413:                                return(false);
        !          1414:                        }
        !          1415:                        if((batup_name[i]=(char *)MALLOC(13))==NULL) {
        !          1416:                                errormsg(WHERE, ERR_ALLOC, "batup_name[x]", 13);
        !          1417:                                return(false);
        !          1418:                        } 
        !          1419:                } 
        !          1420:        }
        !          1421: 
        !          1422:        if(cfg.max_batdn) {
        !          1423: 
        !          1424:                if((batdn_name=(char **)MALLOC(sizeof(char *)*cfg.max_batdn))==NULL) {
        !          1425:                        errormsg(WHERE, ERR_ALLOC, "batdn_name", sizeof(char *)*cfg.max_batdn);
        !          1426:                        return(false);
        !          1427:                }
        !          1428:                if((batdn_dir=(uint *)MALLOC(sizeof(uint)*cfg.max_batdn))==NULL)  {
        !          1429:                        errormsg(WHERE, ERR_ALLOC, "batdn_dir", sizeof(uint)*cfg.max_batdn);
        !          1430:                        return(false);
        !          1431:                }
        !          1432:                if((batdn_offset=(long *)MALLOC(sizeof(long)*cfg.max_batdn))==NULL)  {
        !          1433:                        errormsg(WHERE, ERR_ALLOC, "batdn_offset", sizeof(long)*cfg.max_batdn);
        !          1434:                        return(false);
        !          1435:                }
        !          1436:                if((batdn_size=(ulong *)MALLOC(sizeof(ulong)*cfg.max_batdn))==NULL) {
        !          1437:                        errormsg(WHERE, ERR_ALLOC, "batdn_size", sizeof(ulong)*cfg.max_batdn);
        !          1438:                        return(false);
        !          1439:                }
        !          1440:                if((batdn_cdt=(ulong *)MALLOC(sizeof(ulong)*cfg.max_batdn))==NULL) {
        !          1441:                        errormsg(WHERE, ERR_ALLOC, "batdn_cdt", sizeof(long)*cfg.max_batdn);
        !          1442:                        return(false);
        !          1443:                }
        !          1444:                if((batdn_alt=(ushort *)MALLOC(sizeof(ushort)*cfg.max_batdn))==NULL) {
        !          1445:                        errormsg(WHERE, ERR_ALLOC, "batdn_alt", sizeof(ushort)*cfg.max_batdn);
        !          1446:                        return(false);
        !          1447:                }
        !          1448:                for(i=0;i<cfg.max_batdn;i++)
        !          1449:                        if((batdn_name[i]=(char *)MALLOC(13))==NULL) {
        !          1450:                                errormsg(WHERE, ERR_ALLOC, "batdn_name[x]", 13);
        !          1451:                                return(false);
        !          1452:                        } 
        !          1453:        }
        !          1454: 
        !          1455:        reset_logon_vars();
        !          1456: 
        !          1457: #if 0
        !          1458:     lprintf("temp_dir: %s", cfg.temp_dir);
        !          1459:     lprintf("node_dir: %s", cfg.node_dir);
        !          1460:     lprintf("ctrl_dir: %s", cfg.ctrl_dir);
        !          1461:     lprintf("data_dir: %s", cfg.data_dir);
        !          1462:     lprintf("text_dir: %s", cfg.text_dir);
        !          1463:     lprintf("exec_dir: %s", cfg.exec_dir);
        !          1464: #endif
        !          1465: 
        !          1466:        online=ON_REMOTE;
        !          1467: 
        !          1468:        return(true);
        !          1469: }
        !          1470: 
        !          1471: //****************************************************************************
        !          1472: sbbs_t::~sbbs_t()
        !          1473: {
        !          1474:        uint i;
        !          1475:        char node[32];
        !          1476: 
        !          1477:     if(cfg.node_num)
        !          1478:        sprintf(node,"Node %d", cfg.node_num);
        !          1479:     else
        !          1480:        strcpy(node,client_name);
        !          1481: 
        !          1482:        lprintf("%s destructor", node);
        !          1483: 
        !          1484:     hangup();  /* close socket handle */
        !          1485: 
        !          1486:        if(client_socket_dup!=INVALID_SOCKET)
        !          1487:                closesocket(client_socket_dup); /* close duplicate handle */
        !          1488: 
        !          1489:        sem_post(&output_sem);          /* just incase someone's waiting */
        !          1490:        sem_destroy(&output_sem);
        !          1491: 
        !          1492:        if(cfg.node_num)
        !          1493:                node_inbuf[cfg.node_num-1]=NULL;
        !          1494:        if(!input_thread_running)
        !          1495:                RingBufDispose(&inbuf);
        !          1496:        if(!output_thread_running)
        !          1497:                RingBufDispose(&outbuf);
        !          1498: 
        !          1499:        /* Close all open files */
        !          1500: #if 0  /* old way, not compatible with Linux Samba client */
        !          1501:        if(nodefile_fp!=NULL) { 
        !          1502:                fclose(nodefile_fp);
        !          1503:                nodefile_fp=NULL;
        !          1504:        }
        !          1505:        if(node_ext_fp!=NULL) {
        !          1506:                fclose(node_ext_fp);
        !          1507:                node_ext_fp=NULL;
        !          1508:        }
        !          1509: #else
        !          1510:        if(nodefile!=-1) {
        !          1511:                close(nodefile);
        !          1512:                nodefile=-1;
        !          1513:        }
        !          1514:        if(node_ext!=-1) {
        !          1515:                close(node_ext);
        !          1516:                node_ext=-1;
        !          1517:        }
        !          1518: #endif
        !          1519:        if(logfile_fp!=NULL) {
        !          1520:                fclose(logfile_fp);
        !          1521:                logfile_fp=NULL;
        !          1522:        }
        !          1523: 
        !          1524:        /********************************/
        !          1525:        /* Free allocated class members */
        !          1526:        /********************************/
        !          1527: 
        !          1528:        /* Reset text.dat */
        !          1529: 
        !          1530:        for(i=0;i<TOTAL_TEXT && text!=NULL;i++)
        !          1531:                if(text[i]!=text_sav[i]) {
        !          1532:                        if(text[i]!=nulstr)
        !          1533:                                FREE(text[i]); 
        !          1534:                }
        !          1535: 
        !          1536:        /* Global command shell vars */
        !          1537: 
        !          1538:        freevars(&main_csi);
        !          1539:        clearvars(&main_csi);
        !          1540:        FREE_AND_NULL(main_csi.str);    /* crash */
        !          1541:        FREE_AND_NULL(main_csi.cs);
        !          1542: 
        !          1543:        for(i=0;i<global_str_vars && global_str_var!=NULL;i++)
        !          1544:                FREE_AND_NULL(global_str_var[i]);
        !          1545: 
        !          1546:        FREE_AND_NULL(global_str_var);
        !          1547:        FREE_AND_NULL(global_str_var_name);
        !          1548:        global_str_vars=0;
        !          1549: 
        !          1550:        FREE_AND_NULL(global_int_var);
        !          1551:        FREE_AND_NULL(global_int_var_name);
        !          1552:        global_int_vars=0;
        !          1553: 
        !          1554:        /* Sub-board variables */
        !          1555:        for(i=0;i<cfg.total_grps && usrsub!=NULL;i++)
        !          1556:                FREE_AND_NULL(usrsub[i]);
        !          1557: 
        !          1558:        FREE_AND_NULL(cursub);
        !          1559:        FREE_AND_NULL(usrgrp);
        !          1560:        FREE_AND_NULL(usrsubs);
        !          1561:        FREE_AND_NULL(usrsub);
        !          1562:        FREE_AND_NULL(sub_cfg);
        !          1563:        FREE_AND_NULL(sub_ptr);
        !          1564:        FREE_AND_NULL(sub_last);
        !          1565:        FREE_AND_NULL(sav_sub_cfg);
        !          1566:        FREE_AND_NULL(sav_sub_ptr);
        !          1567:        FREE_AND_NULL(sav_sub_last);
        !          1568: 
        !          1569: 
        !          1570:        /* File Directory variables */
        !          1571:        for(i=0;i<cfg.total_libs && usrdir!=NULL;i++)
        !          1572:                FREE_AND_NULL(usrdir[i]);
        !          1573: 
        !          1574:        FREE_AND_NULL(curdir);
        !          1575:        FREE_AND_NULL(usrlib);
        !          1576:        FREE_AND_NULL(usrdirs);
        !          1577:        FREE_AND_NULL(usrdir);
        !          1578: 
        !          1579:        /* Batch upload vars */
        !          1580:        for(i=0;i<cfg.max_batup && batup_desc!=NULL && batup_name!=NULL;i++) {
        !          1581:                FREE_AND_NULL(batup_desc[i]);
        !          1582:                FREE_AND_NULL(batup_name[i]);
        !          1583:        }
        !          1584: 
        !          1585:        FREE_AND_NULL(batup_desc);
        !          1586:        FREE_AND_NULL(batup_name);
        !          1587:        FREE_AND_NULL(batup_misc);
        !          1588:        FREE_AND_NULL(batup_dir);
        !          1589:        FREE_AND_NULL(batup_alt);
        !          1590: 
        !          1591:        /* Batch download vars */
        !          1592:        for(i=0;i<cfg.max_batdn && batdn_name!=NULL;i++)
        !          1593:                FREE_AND_NULL(batdn_name[i]); 
        !          1594: 
        !          1595:        FREE_AND_NULL(batdn_name);
        !          1596:        FREE_AND_NULL(batdn_dir);
        !          1597:        FREE_AND_NULL(batdn_offset);
        !          1598:        FREE_AND_NULL(batdn_size);
        !          1599:        FREE_AND_NULL(batdn_cdt);
        !          1600:        FREE_AND_NULL(batdn_alt);
        !          1601: 
        !          1602:        /******************************************/
        !          1603:        /* Free allocated configuration variables */
        !          1604:        /******************************************/
        !          1605: }
        !          1606: 
        !          1607: /****************************************************************************/
        !          1608: /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
        !          1609: /* number of times if the attempted file is already open or denying access  */
        !          1610: /* for some other reason.      All files are opened in BINARY mode.                    */
        !          1611: /****************************************************************************/
        !          1612: int sbbs_t::nopen(char *str, int access)
        !          1613: {
        !          1614:        char logstr[256];
        !          1615:        int file,share,count=0;
        !          1616: 
        !          1617:     if(access&O_DENYNONE) {
        !          1618:         share=SH_DENYNO;
        !          1619:         access&=~O_DENYNONE; }
        !          1620:     else if(access==O_RDONLY) share=SH_DENYWR;
        !          1621:     else share=SH_DENYRW;
        !          1622:     while(((file=sopen(str,O_BINARY|access,share))==-1)
        !          1623:         && errno==EACCES && count++<LOOP_NOPEN)
        !          1624:         if(count>10)
        !          1625:             mswait(55);
        !          1626:     if(count>(LOOP_NOPEN/2) && count<=LOOP_NOPEN) {
        !          1627:         sprintf(logstr,"NOPEN COLLISION - File: %s Count: %d"
        !          1628:             ,str,count);
        !          1629:         logline("!!",logstr); }
        !          1630:     if(file==-1 && errno==EACCES)
        !          1631:         bputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
        !          1632:     return(file);
        !          1633: }
        !          1634: 
        !          1635: void sbbs_t::spymsg(char*msg)
        !          1636: {
        !          1637:        char str[512];
        !          1638:        struct in_addr addr;
        !          1639: 
        !          1640:        if(!cfg.node_num)
        !          1641:                return;
        !          1642: 
        !          1643:        addr.s_addr=client_addr;
        !          1644:        sprintf(str,"\r\n\r\n*** Spy Message ***\r\nNode %d: %s [%s]\r\n*** %s ***\r\n\r\n"
        !          1645:                ,cfg.node_num,client_name,inet_ntoa(addr),msg);
        !          1646:        if(startup->node_spybuf!=NULL 
        !          1647:                && startup->node_spybuf[cfg.node_num-1]!=NULL) 
        !          1648:                RingBufWrite(startup->node_spybuf[cfg.node_num-1],(uchar*)str,strlen(str));
        !          1649: 
        !          1650:        if(cfg.node_num && spy_socket[cfg.node_num-1]!=INVALID_SOCKET) 
        !          1651:                send(spy_socket[cfg.node_num-1],str,strlen(str),0);
        !          1652: }
        !          1653: 
        !          1654: #define MV_BUFLEN      4096
        !          1655: 
        !          1656: /****************************************************************************/
        !          1657: /* Moves or copies a file from one dir to another                           */
        !          1658: /* both 'src' and 'dest' must contain full path and filename                */
        !          1659: /* returns 0 if successful, -1 if error                                     */
        !          1660: /****************************************************************************/
        !          1661: int sbbs_t::mv(char *src, char *dest, char copy)
        !          1662: {
        !          1663:        char    str[256],*buf,atr=curatr;
        !          1664:        int             ind,outd;
        !          1665:        uint    chunk=MV_BUFLEN;
        !          1666:        ulong   length,l;
        !          1667:        /* struct ftime ftime; */
        !          1668:        FILE *inp,*outp;
        !          1669: 
        !          1670:     if(!stricmp(src,dest))      /* source and destination are the same! */
        !          1671:         return(0);
        !          1672:     if(!fexist(src)) {
        !          1673:         bprintf("\r\n\7MV ERROR: Source doesn't exist\r\n'%s'\r\n"
        !          1674:             ,src);
        !          1675:         return(-1); }
        !          1676:     if(!copy && fexist(dest)) {
        !          1677:         bprintf("\r\n\7MV ERROR: Destination already exists\r\n'%s'\r\n"
        !          1678:             ,dest);
        !          1679:         return(-1); }
        !          1680:     if(!copy && ((src[1]!=':' && dest[1]!=':')
        !          1681:         || (src[1]==':' && dest[1]==':' && toupper(src[0])==toupper(dest[0])))) {
        !          1682:         if(rename(src,dest)) {                                         /* same drive, so move */
        !          1683:             bprintf("\r\nMV ERROR: Error renaming '%s'"
        !          1684:                     "\r\n                      to '%s'\r\n\7",src,dest);
        !          1685:             return(-1); }
        !          1686:         return(0); }
        !          1687:     attr(WHITE);
        !          1688:     if((ind=nopen(src,O_RDONLY))==-1) {
        !          1689:         errormsg(WHERE,ERR_OPEN,src,O_RDONLY);
        !          1690:         return(-1); }
        !          1691:     if((inp=fdopen(ind,"rb"))==NULL) {
        !          1692:         close(ind);
        !          1693:         errormsg(WHERE,ERR_FDOPEN,str,O_RDONLY);
        !          1694:         return(-1); }
        !          1695:     setvbuf(inp,NULL,_IOFBF,32*1024);
        !          1696:     if((outd=nopen(dest,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
        !          1697:         fclose(inp);
        !          1698:         errormsg(WHERE,ERR_OPEN,dest,O_WRONLY|O_CREAT|O_TRUNC);
        !          1699:         return(-1); }
        !          1700:     if((outp=fdopen(outd,"wb"))==NULL) {
        !          1701:         close(outd);
        !          1702:         fclose(inp);
        !          1703:         errormsg(WHERE,ERR_FDOPEN,dest,O_WRONLY|O_CREAT|O_TRUNC);
        !          1704:         return(-1); }
        !          1705:     setvbuf(outp,NULL,_IOFBF,8*1024);
        !          1706:     length=filelength(ind);
        !          1707:     if(!length) {
        !          1708:         fclose(inp);
        !          1709:         fclose(outp);
        !          1710:         errormsg(WHERE,ERR_LEN,src,0);
        !          1711:         return(-1); }
        !          1712:     if((buf=(char *)MALLOC(MV_BUFLEN))==NULL) {
        !          1713:         fclose(inp);
        !          1714:         fclose(outp);
        !          1715:         errormsg(WHERE,ERR_ALLOC,nulstr,MV_BUFLEN);
        !          1716:         return(-1); }
        !          1717:     l=0L;
        !          1718:     while(l<length) {
        !          1719:         bprintf("%2lu%%",l ? (long)(100.0/((float)length/l)) : 0L);
        !          1720:         if(l+chunk>length)
        !          1721:             chunk=length-l;
        !          1722:         if(fread(buf,1,chunk,inp)!=chunk) {
        !          1723:             FREE(buf);
        !          1724:             fclose(inp);
        !          1725:             fclose(outp);
        !          1726:             errormsg(WHERE,ERR_READ,src,chunk);
        !          1727:             return(-1); }
        !          1728:         if(fwrite(buf,1,chunk,outp)!=chunk) {
        !          1729:             FREE(buf);
        !          1730:             fclose(inp);
        !          1731:             fclose(outp);
        !          1732:             errormsg(WHERE,ERR_WRITE,dest,chunk);
        !          1733:             return(-1); }
        !          1734:         l+=chunk;
        !          1735:         bputs("\b\b\b"); }
        !          1736:     bputs("   \b\b\b");  /* erase it */
        !          1737:     attr(atr);
        !          1738:     /* getftime(ind,&ftime);
        !          1739:     setftime(outd,&ftime); */
        !          1740:     FREE(buf);
        !          1741:     fclose(inp);
        !          1742:     fclose(outp);
        !          1743:     if(!copy && remove(src)) {
        !          1744:         errormsg(WHERE,ERR_REMOVE,src,0);
        !          1745:         return(-1); }
        !          1746:     return(0);
        !          1747: }
        !          1748: 
        !          1749: /****************************************************************************/
        !          1750: /* Reads data from dsts.dab into stats structure                            */
        !          1751: /* If node is zero, reads from ctrl\dsts.dab, otherwise from each node         */
        !          1752: /****************************************************************************/
        !          1753: BOOL DLLCALL getstats(scfg_t* cfg, char node, stats_t* stats)
        !          1754: {
        !          1755:     char str[256];
        !          1756:     int file;
        !          1757: 
        !          1758:     sprintf(str,"%sdsts.dab",node ? cfg->node_path[node-1] : cfg->ctrl_dir);
        !          1759:     if((file=nopen(str,O_RDONLY))==-1) {
        !          1760: //        errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
        !          1761:         return(FALSE); 
        !          1762:        }
        !          1763:     lseek(file,4L,SEEK_SET);    /* Skip update time/date */
        !          1764:     read(file,stats,sizeof(stats_t));
        !          1765:     close(file);
        !          1766:        return(TRUE);
        !          1767: }
        !          1768: 
        !          1769: 
        !          1770: void sbbs_t::hangup(void)
        !          1771: {
        !          1772:        mswait(1000);   /* Give socket output buffer time to flush */
        !          1773:        riosync(0);
        !          1774:        if(client_socket!=INVALID_SOCKET) {
        !          1775: //     lprintf("Hangup: closing socket %d",client_socket);
        !          1776:                close_socket(client_socket);
        !          1777:                client_socket=INVALID_SOCKET;
        !          1778:                closesocket(client_socket_dup);
        !          1779:                client_socket_dup=INVALID_SOCKET;
        !          1780:        }
        !          1781:        sem_post(&output_sem);
        !          1782:        online=0;
        !          1783: }
        !          1784: 
        !          1785: int sbbs_t::incom(void)
        !          1786: {
        !          1787:        uchar   ch;
        !          1788: 
        !          1789:        if(!RingBufRead(&inbuf, &ch, 1))
        !          1790:                return(NOINP);
        !          1791: 
        !          1792:        if(rio_abortable && ch==3) {            /* Ctrl-C */
        !          1793:        lprintf("Node %d Ctrl-C hit",cfg.node_num);
        !          1794:                sys_status|=SS_ABORT;
        !          1795:                rioctl(IOFO);
        !          1796:                return(NOINP); }
        !          1797:        return(ch);
        !          1798: }
        !          1799: 
        !          1800: int sbbs_t::outcom(uchar ch)
        !          1801: {
        !          1802:        if(!RingBufFree(&outbuf))
        !          1803:                return(TXBOF);
        !          1804:     RingBufWrite(&outbuf, &ch, 1);
        !          1805:        sem_post(&output_sem);
        !          1806:        return(0);
        !          1807: }
        !          1808: 
        !          1809: void sbbs_t::putcom(char *str, int len)
        !          1810: {
        !          1811:        int i;
        !          1812: 
        !          1813:     if(!len)
        !          1814:        len=strlen(str);
        !          1815:     for(i=0;i<len && online; i++)
        !          1816:         outcom(str[i]);
        !          1817: }
        !          1818: 
        !          1819: void sbbs_t::riosync(char abortable)
        !          1820: {
        !          1821:        if(useron.misc&(RIP|WIP))       /* don't allow abort with RIP or WIP */
        !          1822:                abortable=0;            /* mainly because of ANSI cursor posistion response */
        !          1823:        if(sys_status&SS_ABORT) /* no need to sync if already aborting */
        !          1824:                return;
        !          1825:        time_t start=time(NULL);
        !          1826:        while(online && rioctl(TXBC)) {                         /* wait up to three minutes for tx buf empty */
        !          1827:                if(abortable && rioctl(RXBC)) {                 /* incoming characer */
        !          1828:                        rioctl(IOFO);                                           /* flush output */
        !          1829:                        sys_status|=SS_ABORT;                           /* set abort flag so no pause */
        !          1830:                        break;                                                          /* abort sync */
        !          1831:                }
        !          1832:                if(time(NULL)-start>180) {                              /* timeout */
        !          1833:                        rioctl(IOCS|PAUSE); 
        !          1834:                        break;
        !          1835:                }
        !          1836:                mswait(100);
        !          1837:        }
        !          1838: }
        !          1839: 
        !          1840: /* Legacy Remote I/O Control Interface */
        !          1841: int sbbs_t::rioctl(ushort action)
        !          1842: {
        !          1843:        int             mode;
        !          1844:        int             state;
        !          1845: 
        !          1846:        switch(action) {
        !          1847:                case GVERS:     /* Get version */
        !          1848:                        return(0x200);
        !          1849:                case GUART:     /* Get UART I/O address, not available */
        !          1850:                        return(0xffff);
        !          1851:                case GIRQN:     /* Get IRQ number, not available */
        !          1852:                        return((int)client_socket);
        !          1853:                case GBAUD:     /* Get current bit rate */
        !          1854:                        return(0xffff);
        !          1855:                case RXBC:              /* Get receive buffer count */
        !          1856:                        // ulong        cnt;
        !          1857:                        // ioctlsocket (client_socket,FIONREAD,&cnt);
        !          1858:                        return(/* cnt+ */RingBufFull(&inbuf));
        !          1859:                case RXBS:              /* Get receive buffer size */
        !          1860:                        return(RingBufFree(&inbuf));
        !          1861:                case TXBC:              /* Get transmit buffer count */
        !          1862:                        return(RingBufFull(&outbuf));
        !          1863:                case TXBS:              /* Get transmit buffer size */
        !          1864:                        return(RingBufFree(&outbuf));
        !          1865:                case TXBF:              /* Get transmit buffer free space */
        !          1866:                        return(RingBufFree(&outbuf));
        !          1867:                case IOMODE:
        !          1868:                        mode=0;
        !          1869:                        if(rio_abortable)
        !          1870:                                mode|=ABORT;
        !          1871:                        return(mode);
        !          1872:                case IOSTATE:
        !          1873:                        state=0;
        !          1874:                        if(sys_status&SS_ABORT)
        !          1875:                                state|=ABORT;
        !          1876:                        return(state);
        !          1877:                case IOFI:              /* Flush input buffer */
        !          1878:                        RingBufReInit(&inbuf);
        !          1879:                        break;
        !          1880:                case IOFO:              /* Flush output buffer */
        !          1881:                RingBufReInit(&outbuf);
        !          1882:                        break;
        !          1883:                case IOFB:              /* Flush both buffers */
        !          1884:                        RingBufReInit(&inbuf);
        !          1885:                        RingBufReInit(&outbuf);
        !          1886:                        break;
        !          1887:                case LFN81:
        !          1888:                case LFE71:
        !          1889:                case FIFOCTL:
        !          1890:                        return(0);
        !          1891:                }
        !          1892: 
        !          1893:        if((action&0xff)==IOSM) {       /* Get/Set/Clear mode */
        !          1894:                if(action&ABORT)
        !          1895:                        rio_abortable=true;
        !          1896:                return(0); }
        !          1897: 
        !          1898: 
        !          1899:        if((action&0xff)==IOCM) {       /* Get/Set/Clear mode */
        !          1900:                if(action&ABORT)
        !          1901:                        rio_abortable=false;
        !          1902:                return(0); }
        !          1903: 
        !          1904:        if((action&0xff)==IOSS) {       /* Set state */
        !          1905:                if(action&ABORT)
        !          1906:                        sys_status|=SS_ABORT;
        !          1907:                return(0); }
        !          1908: 
        !          1909:        if((action&0xff)==IOCS) {       /* Clear state */
        !          1910:                if(action&ABORT)
        !          1911:                        sys_status&=~SS_ABORT;
        !          1912:                return(0); }
        !          1913: 
        !          1914:        if((action&0xff)==TXSYNC) { /* Synchronize transmition */
        !          1915:        #if 0 /* TXSYNC */
        !          1916: 
        !          1917:                c=action>>8;            /* Number of seconds */
        !          1918:                w=110+(c*1000);                 /* Number of milliseconds */
        !          1919:                start=clock();
        !          1920:                while(clock()-start<w) {
        !          1921:                        if(!outbufcnt()) {
        !          1922:        #ifdef __OS2__
        !          1923:                                DosDevIOCtl(rio_handle
        !          1924:                                        ,IOCTL_ASYNC, 0x69      /* Query # of chars in tx queue */
        !          1925:                                        ,NULL
        !          1926:                                        ,0
        !          1927:                                        ,NULL
        !          1928:                                        ,&getqueue
        !          1929:                                        ,sizeof(getqueue)
        !          1930:                                        ,NULL);
        !          1931:                                if(getqueue.cur==0)     /* Empty outbound queue */
        !          1932:                                        return(0);
        !          1933:        #else // Win32
        !          1934:                                ClearCommError((HANDLE)rio_handle,&l,&comstat);
        !          1935:                                if(comstat.cbOutQue==0) /* Empty outbound queue */
        !          1936:                                        return(0);
        !          1937:        #endif
        !          1938:                                }
        !          1939:                        mswait(1);
        !          1940:                        }
        !          1941:        #endif
        !          1942:                return(1); }
        !          1943: 
        !          1944:        return(0);
        !          1945: }
        !          1946: 
        !          1947: void sbbs_t::reset_logon_vars(void)
        !          1948: {
        !          1949:        int i;
        !          1950: 
        !          1951:     /* bools */
        !          1952:     qwklogon=false;
        !          1953: 
        !          1954:     sys_status&=~(SS_USERON|SS_TMPSYSOP|SS_LCHAT|SS_ABORT
        !          1955:         |SS_PAUSEON|SS_PAUSEOFF|SS_EVENT|SS_NEWUSER|SS_NEWDAY);
        !          1956:     cid[0]=0;
        !          1957:     wordwrap[0]=0;
        !          1958:     question[0]=0;
        !          1959:     menu_dir[0]=0;
        !          1960:     menu_file[0]=0;
        !          1961:     rows=0;
        !          1962:     lncntr=0;
        !          1963:     autoterm=0;
        !          1964:     keybufbot=keybuftop=lbuflen=0;
        !          1965:     slcnt=0;
        !          1966:     altul=0;
        !          1967:     timeleft_warn=0;
        !          1968:     logon_uls=logon_ulb=logon_dls=logon_dlb=0;
        !          1969:     logon_posts=logon_emails=logon_fbacks=0;
        !          1970:     batdn_total=batup_total=0;
        !          1971:     usrgrps=usrlibs=0;
        !          1972:     curgrp=curlib=0;
        !          1973:     for(i=0;i<cfg.total_libs;i++)
        !          1974:         curdir[i]=0;
        !          1975:     for(i=0;i<cfg.total_grps;i++)
        !          1976:         cursub[i]=0;
        !          1977:        cur_cps=3000;
        !          1978:     cur_rate=30000;
        !          1979:     dte_rate=38400;
        !          1980:        main_cmds=xfer_cmds=posts_read=0;
        !          1981:        lastnodemsg=0;
        !          1982:        lastnodemsguser[0]=0;
        !          1983: }
        !          1984: 
        !          1985: /****************************************************************************/
        !          1986: /* Writes NODE.LOG at end of SYSTEM.LOG                                                                                */
        !          1987: /****************************************************************************/
        !          1988: void sbbs_t::catsyslog(int crash)
        !          1989: {
        !          1990:        char str[256];
        !          1991:        char HUGE16 *buf;
        !          1992:        int  i,file;
        !          1993:        long length;
        !          1994:        struct tm * tm;
        !          1995: 
        !          1996:        if(logfile_fp==NULL) {
        !          1997:                sprintf(str,"%snode.log",cfg.node_dir);
        !          1998:                if((logfile_fp=fopen(str,"rb"))==NULL) {
        !          1999:                        errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
        !          2000:                        return; 
        !          2001:                }
        !          2002:        }
        !          2003:        length=ftell(logfile_fp);
        !          2004:        if(length) {
        !          2005:                if((buf=(char HUGE16 *)LMALLOC(length))==NULL) {
        !          2006:                        errormsg(WHERE,ERR_ALLOC,str,length);
        !          2007:                        return; }
        !          2008:                rewind(logfile_fp);
        !          2009:                if(fread(buf,1,length,logfile_fp)!=(size_t)length) {
        !          2010:                        errormsg(WHERE,ERR_READ,"log file",length);
        !          2011:                        FREE((char *)buf);
        !          2012:                        return; 
        !          2013:                }
        !          2014:                now=time(NULL);
        !          2015:                tm=gmtime(&now);
        !          2016:                if(tm==NULL)
        !          2017:                        return;
        !          2018:                sprintf(str,"%slogs/%2.2d%2.2d%2.2d.log",cfg.data_dir,tm->tm_mon+1,tm->tm_mday
        !          2019:                        ,TM_YEAR(tm->tm_year));
        !          2020:                if((file=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
        !          2021:                        errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
        !          2022:                        FREE((char *)buf);
        !          2023:                        return; }
        !          2024:                if(lwrite(file,buf,length)!=length) {
        !          2025:                        close(file);
        !          2026:                        errormsg(WHERE,ERR_WRITE,str,length);
        !          2027:                        FREE((char *)buf);
        !          2028:                        return; }
        !          2029:                close(file);
        !          2030:                if(crash) {
        !          2031:                        for(i=0;i<2;i++) {
        !          2032:                                sprintf(str,"%scrash.log",i ? cfg.data_dir : cfg.node_dir);
        !          2033:                                if((file=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
        !          2034:                                        errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
        !          2035:                                        FREE((char *)buf);
        !          2036:                                        return; }
        !          2037:                                if(lwrite(file,buf,length)!=length) {
        !          2038:                                        close(file);
        !          2039:                                        errormsg(WHERE,ERR_WRITE,str,length);
        !          2040:                                        FREE((char *)buf);
        !          2041:                                        return; }
        !          2042:                                close(file); } }
        !          2043:                FREE((char *)buf); }
        !          2044: 
        !          2045:        fclose(logfile_fp);
        !          2046: 
        !          2047:        sprintf(str,"%snode.log",cfg.node_dir);
        !          2048:        if((logfile_fp=fopen(str,"w+b"))==NULL) /* Truncate NODE.LOG */
        !          2049:                errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_TRUNC);
        !          2050: }
        !          2051: 
        !          2052: 
        !          2053: void sbbs_t::logoffstats()
        !          2054: {
        !          2055:     char str[256];
        !          2056:     int i,file;
        !          2057:     stats_t stats;
        !          2058: 
        !          2059: #if 0
        !          2060:        if(thisnode.status==NODE_QUIET)       /* Quiet users aren't counted */
        !          2061:                return;
        !          2062: #endif
        !          2063: 
        !          2064:        if(REALSYSOP && !(cfg.sys_misc&SM_SYSSTAT))
        !          2065:                return;
        !          2066:        
        !          2067:        for(i=0;i<2;i++) {
        !          2068:                sprintf(str,"%sdsts.dab",i ? cfg.ctrl_dir : cfg.node_dir);
        !          2069:                if((file=nopen(str,O_RDWR))==-1) {
        !          2070:                        errormsg(WHERE,ERR_OPEN,str,O_RDWR);
        !          2071:                        return; }
        !          2072:                lseek(file,12L,SEEK_SET);   /* Skip timestamp, logons and logons today */
        !          2073:                read(file,&stats.timeon,4);   /* Total time on system  */
        !          2074:                read(file,&stats.ttoday,4); /* Time today on system  */
        !          2075:                read(file,&stats.uls,4);        /* Uploads today         */
        !          2076:                read(file,&stats.ulb,4);        /* Upload bytes today    */
        !          2077:                read(file,&stats.dls,4);        /* Downloads today       */
        !          2078:                read(file,&stats.dlb,4);        /* Download bytes today  */
        !          2079:                read(file,&stats.ptoday,4);     /* Posts today                   */
        !          2080:                read(file,&stats.etoday,4); /* Emails today          */
        !          2081:                read(file,&stats.ftoday,4); /* Feedback sent today  */
        !          2082:                read(file,&stats.nusers,2); /* New users today          */
        !          2083: 
        !          2084:                if(!(useron.rest&FLAG('Q'))) {  /* Don't count QWKnet nodes */
        !          2085:                        stats.timeon+=(now-logontime)/60;
        !          2086:                        stats.ttoday+=(now-logontime)/60;
        !          2087:                        stats.ptoday+=logon_posts;
        !          2088:                }
        !          2089:                stats.uls+=logon_uls;
        !          2090:                stats.ulb+=logon_ulb;
        !          2091:                stats.dls+=logon_dls;
        !          2092:                stats.dlb+=logon_dlb;
        !          2093:                stats.etoday+=logon_emails;
        !          2094:                stats.ftoday+=logon_fbacks;
        !          2095:                if(sys_status&SS_NEWUSER)
        !          2096:                        stats.nusers++;
        !          2097: 
        !          2098:                lseek(file,12L,SEEK_SET);
        !          2099:                write(file,&stats.timeon,4);    /* Total time on system  */
        !          2100:                write(file,&stats.ttoday,4);    /* Time today on system  */
        !          2101:                write(file,&stats.uls,4);       /* Uploads today         */
        !          2102:                write(file,&stats.ulb,4);       /* Upload bytes today    */
        !          2103:                write(file,&stats.dls,4);       /* Downloads today       */
        !          2104:                write(file,&stats.dlb,4);       /* Download bytes today  */
        !          2105:                write(file,&stats.ptoday,4);    /* Posts today           */
        !          2106:                write(file,&stats.etoday,4);    /* Emails today          */
        !          2107:                write(file,&stats.ftoday,4);    /* Feedback sent today   */
        !          2108:                write(file,&stats.nusers,2);    /* New users today               */
        !          2109:                close(file); 
        !          2110:        }
        !          2111: }
        !          2112: 
        !          2113: void node_thread(void* arg)
        !          2114: {
        !          2115:        char                    str[128];
        !          2116:        char                    uname[LEN_ALIAS+1];
        !          2117:        int                             file;
        !          2118:        uint                    i,j;
        !          2119:        uint                    curshell=0;
        !          2120:        time_t                  now;
        !          2121:        node_t                  node;
        !          2122:        user_t                  user;
        !          2123:        sbbs_t*                 sbbs = (sbbs_t*) arg;
        !          2124: 
        !          2125:     node_threads_running++;
        !          2126:        update_clients();
        !          2127:        thread_up();
        !          2128: 
        !          2129:        if(sbbs->answer()) {
        !          2130: 
        !          2131:                if(sbbs->qwklogon) {
        !          2132:                        sbbs->getsmsg(sbbs->useron.number);
        !          2133:                        sbbs->qwk_sec();
        !          2134:                } else while(sbbs->useron.number 
        !          2135:                        && (sbbs->main_csi.misc&CS_OFFLINE_EXEC || sbbs->online)) {
        !          2136: 
        !          2137:                        if(!sbbs->main_csi.cs || curshell!=sbbs->useron.shell) {
        !          2138:                                if(sbbs->useron.shell>=sbbs->cfg.total_shells)
        !          2139:                                        sbbs->useron.shell=0;
        !          2140:                                sprintf(str,"%s%s.bin",sbbs->cfg.exec_dir
        !          2141:                                        ,sbbs->cfg.shell[sbbs->useron.shell]->code);
        !          2142:                                if((file=sbbs->nopen(str,O_RDONLY))==-1) {
        !          2143:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
        !          2144:                                        sbbs->hangup();
        !          2145:                                        break; }
        !          2146:                                FREE_AND_NULL(sbbs->main_csi.cs);
        !          2147:                                sbbs->freevars(&sbbs->main_csi);
        !          2148:                                sbbs->clearvars(&sbbs->main_csi);
        !          2149: 
        !          2150:                                sbbs->main_csi.length=filelength(file);
        !          2151:                                if((sbbs->main_csi.cs=(uchar *)MALLOC(sbbs->main_csi.length))==NULL) {
        !          2152:                                        close(file);
        !          2153:                                        sbbs->errormsg(WHERE,ERR_ALLOC,str,sbbs->main_csi.length);
        !          2154:                                        sbbs->hangup();
        !          2155:                                        break; }
        !          2156: 
        !          2157:                                if(lread(file,sbbs->main_csi.cs,sbbs->main_csi.length)
        !          2158:                                        !=(int)sbbs->main_csi.length) {
        !          2159:                                        sbbs->errormsg(WHERE,ERR_READ,str,sbbs->main_csi.length);
        !          2160:                                        close(file);
        !          2161:                                        FREE(sbbs->main_csi.cs);
        !          2162:                                        sbbs->main_csi.cs=NULL;
        !          2163:                                        sbbs->hangup();
        !          2164:                                        break; }
        !          2165:                                close(file);
        !          2166: 
        !          2167:                                curshell=sbbs->useron.shell;
        !          2168:                                sbbs->main_csi.ip=sbbs->main_csi.cs;
        !          2169:                                sbbs->menu_dir[0]=0;
        !          2170:                                sbbs->menu_file[0]=0;
        !          2171:                                }
        !          2172:                        if(sbbs->exec(&sbbs->main_csi))
        !          2173:                                break;
        !          2174: 
        !          2175:                }
        !          2176:        }
        !          2177: 
        !          2178: #ifdef _WIN32
        !          2179:        if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)) 
        !          2180:                PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          2181: #endif
        !          2182: 
        !          2183:        sbbs->hangup(); /* just to be sure we shut down the output_thread */
        !          2184:        client_off(node_socket[sbbs->cfg.node_num-1]);
        !          2185:     node_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET;
        !          2186: 
        !          2187:        sbbs->logout();
        !          2188:        sbbs->logoffstats();    /* Updates both system and node dsts.dab files */
        !          2189: 
        !          2190:        if(sbbs->sys_status&SS_DAILY) { // New day, run daily events/maintenance
        !          2191: 
        !          2192:                now=time(NULL);
        !          2193: 
        !          2194:                sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
        !          2195:                node.status=NODE_EVENT_RUNNING;
        !          2196:                sbbs->putnodedat(sbbs->cfg.node_num,&node);
        !          2197: 
        !          2198: //             status("Running system daily maintenance");
        !          2199:                sbbs->logentry("!:","Ran system daily maintenance");
        !          2200:                lprintf("Checking users...");
        !          2201:                j=lastuser(&sbbs->cfg);
        !          2202:                for(i=1;i<=j;i++) {
        !          2203: 
        !          2204:                        sprintf(str,"%5u of %-5u",i,j);
        !          2205:                        status(str);
        !          2206:                        user.number=i;
        !          2207:                        getuserdat(&sbbs->cfg,&user);
        !          2208: 
        !          2209:                        /***********************************************/
        !          2210:                        /* Fix name (name.dat and user.dat) mismatches */
        !          2211:                        /***********************************************/
        !          2212:                        username(&sbbs->cfg,i,uname);
        !          2213:                        if(user.misc&DELETED) {
        !          2214:                                if(strcmp(uname,"DELETED USER"))
        !          2215:                                        sbbs->putusername(i,nulstr);
        !          2216:                                continue; }
        !          2217: 
        !          2218:                        if(strcmp(user.alias,uname))
        !          2219:                                sbbs->putusername(i,user.alias);
        !          2220: 
        !          2221:                        if(!(user.misc&(DELETED|INACTIVE))
        !          2222:                                && user.expire && (ulong)user.expire<=(ulong)now) {
        !          2223:                                putsmsg(&sbbs->cfg,i,sbbs->text[AccountHasExpired]);
        !          2224:                                sprintf(str,"%s #%u Expired",user.alias,user.number);
        !          2225:                                sbbs->logentry("!%",str);
        !          2226:                                if(sbbs->cfg.level_misc[user.level]&LEVEL_EXPTOVAL
        !          2227:                                        && sbbs->cfg.level_expireto[user.level]<10) {
        !          2228:                                        user.flags1=sbbs->cfg.val_flags1[sbbs->cfg.level_expireto[user.level]];
        !          2229:                                        user.flags2=sbbs->cfg.val_flags2[sbbs->cfg.level_expireto[user.level]];
        !          2230:                                        user.flags3=sbbs->cfg.val_flags3[sbbs->cfg.level_expireto[user.level]];
        !          2231:                                        user.flags4=sbbs->cfg.val_flags4[sbbs->cfg.level_expireto[user.level]];
        !          2232:                                        user.exempt=sbbs->cfg.val_exempt[sbbs->cfg.level_expireto[user.level]];
        !          2233:                                        user.rest=sbbs->cfg.val_rest[sbbs->cfg.level_expireto[user.level]];
        !          2234:                                        if(sbbs->cfg.val_expire[sbbs->cfg.level_expireto[user.level]])
        !          2235:                                                user.expire=now
        !          2236:                                                        +(sbbs->cfg.val_expire[sbbs->cfg.level_expireto[user.level]]*24*60*60);
        !          2237:                                        else
        !          2238:                                                user.expire=0;
        !          2239:                                        user.level=sbbs->cfg.val_level[sbbs->cfg.level_expireto[user.level]]; }
        !          2240:                                else {
        !          2241:                                        if(sbbs->cfg.level_misc[user.level]&LEVEL_EXPTOLVL)
        !          2242:                                                user.level=sbbs->cfg.level_expireto[user.level];
        !          2243:                                        else
        !          2244:                                                user.level=sbbs->cfg.expired_level;
        !          2245:                                        user.flags1&=~sbbs->cfg.expired_flags1; /* expired status */
        !          2246:                                        user.flags2&=~sbbs->cfg.expired_flags2; /* expired status */
        !          2247:                                        user.flags3&=~sbbs->cfg.expired_flags3; /* expired status */
        !          2248:                                        user.flags4&=~sbbs->cfg.expired_flags4; /* expired status */
        !          2249:                                        user.exempt&=~sbbs->cfg.expired_exempt;
        !          2250:                                        user.rest|=sbbs->cfg.expired_rest;
        !          2251:                                        user.expire=0; }
        !          2252:                                putuserrec(&sbbs->cfg,i,U_LEVEL,2,ultoa(user.level,str,10));
        !          2253:                                putuserrec(&sbbs->cfg,i,U_FLAGS1,8,ultoa(user.flags1,str,16));
        !          2254:                                putuserrec(&sbbs->cfg,i,U_FLAGS2,8,ultoa(user.flags2,str,16));
        !          2255:                                putuserrec(&sbbs->cfg,i,U_FLAGS3,8,ultoa(user.flags3,str,16));
        !          2256:                                putuserrec(&sbbs->cfg,i,U_FLAGS4,8,ultoa(user.flags4,str,16));
        !          2257:                                putuserrec(&sbbs->cfg,i,U_EXPIRE,8,ultoa(user.expire,str,16));
        !          2258:                                putuserrec(&sbbs->cfg,i,U_EXEMPT,8,ultoa(user.exempt,str,16));
        !          2259:                                putuserrec(&sbbs->cfg,i,U_REST,8,ultoa(user.rest,str,16));
        !          2260:                                if(sbbs->cfg.expire_mod[0]) {
        !          2261:                                        sbbs->useron=user;
        !          2262:                                        sbbs->online=ON_LOCAL;
        !          2263:                                        sbbs->exec_bin(sbbs->cfg.expire_mod,&sbbs->main_csi);
        !          2264:                                        sbbs->online=0; }
        !          2265:                                }
        !          2266: 
        !          2267:                        /***********************************************************/
        !          2268:                        /* Auto deletion based on expiration date or days inactive */
        !          2269:                        /***********************************************************/
        !          2270:                        if(!(user.exempt&FLAG('P'))     /* Not a permanent account */
        !          2271:                                && !(user.misc&(DELETED|INACTIVE))       /* alive */
        !          2272:                                && (sbbs->cfg.sys_autodel && (now-user.laston)/(long)(24L*60L*60L)
        !          2273:                                > sbbs->cfg.sys_autodel)) {                     /* Inactive too long */
        !          2274:                                sprintf(str,"Auto-Deleted %s #%u",user.alias,user.number);
        !          2275:                                sbbs->logentry("!*",str);
        !          2276:                                sbbs->delallmail(i);
        !          2277:                                sbbs->putusername(i,nulstr);
        !          2278:                                putuserrec(&sbbs->cfg,i,U_MISC,8,ultoa(user.misc|DELETED,str,16)); }
        !          2279:                }
        !          2280: 
        !          2281:                lprintf("Purging deleted/expired e-mail");
        !          2282:                sprintf(sbbs->smb.file,"%smail",sbbs->cfg.data_dir);
        !          2283:                sbbs->smb.retry_time=sbbs->cfg.smb_retry_time;
        !          2284:                if((i=smb_open(&sbbs->smb))!=0)
        !          2285:                        sbbs->errormsg(WHERE,ERR_OPEN,sbbs->smb.file,i,sbbs->smb.last_error);
        !          2286:                else {
        !          2287:                        if((i=smb_locksmbhdr(&sbbs->smb))!=0)
        !          2288:                                sbbs->errormsg(WHERE,ERR_LOCK,sbbs->smb.file,i,sbbs->smb.last_error);
        !          2289:                        else
        !          2290:                                sbbs->delmail(0,MAIL_ALL);
        !          2291:                        smb_close(&sbbs->smb); 
        !          2292:                }
        !          2293: 
        !          2294: 
        !          2295:                sbbs->sys_status&=~SS_DAILY;
        !          2296:                if(sbbs->cfg.sys_daily[0]) {
        !          2297: //                     status("Running system daily event");
        !          2298:                        sbbs->logentry("!:","Ran system daily event");
        !          2299:                        sbbs->external(sbbs->cmdstr(sbbs->cfg.sys_daily,nulstr,nulstr,NULL)
        !          2300:                                ,EX_OFFLINE); 
        !          2301:                }
        !          2302:        }
        !          2303: 
        !          2304:        // Node Daily Event
        !          2305:        sbbs->getnodedat(sbbs->cfg.node_num,&node,0);
        !          2306:        if(node.misc&NODE_EVENT) {
        !          2307:                sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
        !          2308:                node.status=NODE_EVENT_RUNNING;
        !          2309:                sbbs->putnodedat(sbbs->cfg.node_num,&node);
        !          2310:                if(sbbs->cfg.node_daily[0]) {
        !          2311: //                     status("Running node daily event");
        !          2312:                        sbbs->logentry("!:","Run node daily event");
        !          2313:                        sbbs->external(
        !          2314:                                 sbbs->cmdstr(sbbs->cfg.node_daily,nulstr,nulstr,NULL)
        !          2315:                                ,EX_OFFLINE);
        !          2316:                }
        !          2317:                sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
        !          2318:                node.misc&=~NODE_EVENT;
        !          2319:                sbbs->putnodedat(sbbs->cfg.node_num,&node); 
        !          2320:        }
        !          2321: 
        !          2322:     // Wait for all node threads to terminate
        !          2323:        if(sbbs->input_thread_running || sbbs->output_thread_running) {
        !          2324:                lprintf("Waiting for node %d %s to terminate..."
        !          2325:                        ,sbbs->cfg.node_num
        !          2326:                        ,(sbbs->input_thread_running && sbbs->output_thread_running) ?
        !          2327:                        "I/O threads" : sbbs->input_thread_running
        !          2328:                                ? "input thread" : "output thread");
        !          2329:                time_t start=time(NULL);
        !          2330:                while(sbbs->input_thread_running
        !          2331:                || sbbs->output_thread_running) {
        !          2332:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
        !          2333:                                lprintf("!TIMEOUT waiting for node %d "
        !          2334:                                "%s to terminate", sbbs->cfg.node_num
        !          2335:                                        ,(sbbs->input_thread_running && sbbs->output_thread_running) ?
        !          2336:                                "I/O threads"
        !          2337:                                        : sbbs->input_thread_running
        !          2338:                                ? "input thread" : "output thread");
        !          2339:                                break;
        !          2340:                        }
        !          2341:                        mswait(100);
        !          2342:                }
        !          2343:        }
        !          2344: 
        !          2345:        sbbs->catsyslog(0);
        !          2346: 
        !          2347:        status(STATUS_WFC);
        !          2348: 
        !          2349:        sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
        !          2350:        if(node.misc&NODE_DOWN)
        !          2351:                node.status=NODE_OFFLINE;
        !          2352:        else
        !          2353:                node.status=NODE_WFC;
        !          2354:        node.misc&=~NODE_DOWN;
        !          2355:        node.useron=0;
        !          2356:        sbbs->putnodedat(sbbs->cfg.node_num,&node);
        !          2357: 
        !          2358:     if(!sbbs->input_thread_running && !sbbs->output_thread_running 
        !          2359:                && !sbbs->event_thread_running) {
        !          2360:                delete sbbs;
        !          2361:            node_threads_running--;
        !          2362:                update_clients();
        !          2363:                thread_down();
        !          2364:     }
        !          2365: }
        !          2366: 
        !          2367: time_t checktime(void)
        !          2368: {
        !          2369:        struct tm tm;
        !          2370: 
        !          2371:     memset(&tm,0,sizeof(tm));
        !          2372:     tm.tm_year=94;
        !          2373:     tm.tm_mday=1;
        !          2374:     return(mktime(&tm)-0x2D24BD00L);
        !          2375: }
        !          2376: 
        !          2377: char* DLLCALL bbs_ver(void)
        !          2378: {
        !          2379:        static char ver[256];
        !          2380:        char compiler[32];
        !          2381: 
        !          2382:        COMPILER_DESC(compiler);
        !          2383: 
        !          2384:        sprintf(ver,"Synchronet BBS/Telnet Server v%s%c%s  SMBLIB v%s  Compiled %s %s with %s"
        !          2385:                ,VERSION, REVISION
        !          2386: #ifdef _DEBUG
        !          2387:                ," Debug"
        !          2388: #else
        !          2389:                ,""
        !          2390: #endif
        !          2391:                ,smb_lib_ver()
        !          2392:                ,__DATE__, __TIME__, compiler
        !          2393:                );
        !          2394: 
        !          2395:        return(ver);
        !          2396: }
        !          2397: 
        !          2398: void DLLCALL bbs_terminate(void)
        !          2399: {
        !          2400:        if(telnet_socket!=INVALID_SOCKET) {
        !          2401:        lprintf("BBS Terminate: closing telnet socket %d",telnet_socket);
        !          2402:                close_socket(telnet_socket);
        !          2403:                telnet_socket=INVALID_SOCKET;
        !          2404:     }
        !          2405: }
        !          2406: 
        !          2407: static void cleanup(int code)
        !          2408: {
        !          2409:        if(telnet_socket!=INVALID_SOCKET) {
        !          2410:                close_socket(telnet_socket);
        !          2411:                telnet_socket=INVALID_SOCKET;
        !          2412:        }
        !          2413:        if(rlogin_socket!=INVALID_SOCKET) {
        !          2414:                close_socket(rlogin_socket);
        !          2415:                rlogin_socket=INVALID_SOCKET;
        !          2416:        }
        !          2417: 
        !          2418: 
        !          2419: #ifdef _WINSOCKAPI_
        !          2420:        if(WSAInitialized && WSACleanup()!=0) 
        !          2421:                lprintf("!WSACleanup ERROR %d",ERROR_VALUE);
        !          2422: #endif
        !          2423: 
        !          2424:        free_cfg(&scfg);
        !          2425:        free_text(text);
        !          2426: 
        !          2427: #ifdef _WIN32
        !          2428:        CloseHandle(exec_mutex);
        !          2429: #endif
        !          2430:        pthread_mutex_destroy(&event_mutex);
        !          2431: 
        !          2432:     lputs("BBS System thread terminated");
        !          2433:        status("Down");
        !          2434:        if(startup->terminated!=NULL)
        !          2435:                startup->terminated(code);
        !          2436:        thread_down();
        !          2437: }
        !          2438: 
        !          2439: void DLLCALL bbs_thread(void* arg)
        !          2440: {
        !          2441:        char *                  host_name;
        !          2442:     char                       str[256];
        !          2443:        char                    logstr[256];
        !          2444:        SOCKADDR_IN             server_addr={0};
        !          2445:        SOCKADDR_IN             client_addr;
        !          2446:        socklen_t               client_addr_len;
        !          2447:        SOCKET                  client_socket;
        !          2448:        fd_set                  socket_set;
        !          2449:        SOCKET                  high_socket_set;
        !          2450:        int                             i;
        !          2451:     int                                file;
        !          2452:        int                             result;
        !          2453:        BOOL                    option;
        !          2454:        time_t                  t;
        !          2455:        time_t                  start;
        !          2456:        node_t                  node;
        !          2457:        sbbs_t*                 events;
        !          2458:        client_t                client;
        !          2459:        startup=(bbs_startup_t*)arg;
        !          2460: 
        !          2461:     if(startup==NULL) {
        !          2462:        sbbs_beep(100,500);
        !          2463:        fprintf(stderr, "No startup structure passed!\n");
        !          2464:        return;
        !          2465:     }
        !          2466: 
        !          2467:        if(startup->size!=sizeof(bbs_startup_t)) {      // verify size
        !          2468:                sbbs_beep(100,500);
        !          2469:                sbbs_beep(300,500);
        !          2470:                sbbs_beep(100,500);
        !          2471:                fprintf(stderr, "Invalid startup structure!\n");
        !          2472:                return;
        !          2473:        }
        !          2474: 
        !          2475:        thread_up();
        !          2476: 
        !          2477:        status("Initializing");
        !          2478: 
        !          2479: #ifdef __unix__                /* Ignore "Broken Pipe" signal */
        !          2480:        signal(SIGPIPE,SIG_IGN);
        !          2481: #endif
        !          2482: 
        !          2483:        memset(text, 0, sizeof(text));
        !          2484:     memset(&scfg, 0, sizeof(scfg));
        !          2485: 
        !          2486:        node_threads_running=0;
        !          2487: 
        !          2488:        char compiler[32];
        !          2489:        COMPILER_DESC(compiler);
        !          2490: 
        !          2491:        lprintf("Synchronet BBS/Telnet Server Version %s Revision %c%s"
        !          2492:                ,VERSION,REVISION
        !          2493: #ifdef _DEBUG
        !          2494:                ," Debug"
        !          2495: #else
        !          2496:                ,""
        !          2497: #endif
        !          2498:                );
        !          2499:        lprintf("Compiled %s %s with %s", __DATE__, __TIME__, compiler);
        !          2500:        lprintf("SMBLIB v%s (format %x.%02x)",smb_lib_ver(),smb_ver()>>8,smb_ver()&0xff);
        !          2501: 
        !          2502:     if(startup->first_node<1 || startup->first_node>startup->last_node) {
        !          2503:        lprintf("!ILLEGAL node configuration (first: %d, last: %d)"
        !          2504:                ,startup->first_node, startup->last_node);
        !          2505:                cleanup(1);
        !          2506:         return;
        !          2507:     }
        !          2508: 
        !          2509:        if(sizeof(node_t)!=SIZEOF_NODE_T) {
        !          2510:                lprintf("!COMPILER ERROR: sizeof(node_t)=%d instead of %d"
        !          2511:                        ,sizeof(node_t),SIZEOF_NODE_T);
        !          2512:                cleanup(1);
        !          2513:                return;
        !          2514:        }
        !          2515: 
        !          2516:        srand(time(NULL));
        !          2517: 
        !          2518:        if(!(startup->options&BBS_OPT_LOCAL_TIMEZONE)) {
        !          2519:                if(PUTENV("TZ=UCT0"))
        !          2520:                        lprintf("!putenv() FAILED");
        !          2521:                tzset();
        !          2522: 
        !          2523:                if((t=checktime())!=0) {   /* Check binary time */
        !          2524:                        lprintf("!TIME PROBLEM (%ld)",t);
        !          2525:                        cleanup(1);
        !          2526:                        return;
        !          2527:                }
        !          2528:        }
        !          2529: 
        !          2530: #ifdef _WIN32
        !          2531:     if((exec_mutex=CreateMutex(NULL,false,NULL))==NULL) {
        !          2532:        lprintf("!ERROR %d creating exec_mutex", GetLastError());
        !          2533:                cleanup(1);
        !          2534:         return;
        !          2535:     }
        !          2536: #endif
        !          2537: 
        !          2538:        pthread_mutex_init(&event_mutex,NULL);
        !          2539: 
        !          2540:        if(!winsock_startup()) {
        !          2541:                cleanup(1);
        !          2542:                return;
        !          2543:        }
        !          2544: 
        !          2545:        t=time(NULL);
        !          2546:        lprintf("Initializing on %.24s with options: %lx"
        !          2547:                ,ctime(&t),startup->options);
        !          2548: 
        !          2549:        /* Initial configuration and load from CNF files */
        !          2550:        scfg.startup=startup;
        !          2551:     sprintf(scfg.ctrl_dir, "%.*s", (int)sizeof(scfg.ctrl_dir)-1
        !          2552:        ,startup->ctrl_dir);
        !          2553:     lprintf("Loading configuration files from %s", scfg.ctrl_dir);
        !          2554:        scfg.node_num=startup->first_node;
        !          2555:        if(!load_cfg(&scfg, text)) {
        !          2556:                lprintf("!Failed to load configuration files");
        !          2557:                cleanup(1);
        !          2558:                return;
        !          2559:        }
        !          2560:        scfg_reloaded=true;
        !          2561: 
        !          2562:     if(startup->last_node>scfg.sys_nodes) {
        !          2563:        lprintf("Specified last_node (%d) > sys_nodes (%d), auto-corrected"
        !          2564:                ,startup->last_node, scfg.sys_nodes);
        !          2565:         startup->last_node=scfg.sys_nodes;
        !          2566:     }
        !          2567: 
        !          2568:        /* Create missing directories */
        !          2569:        make_data_dirs(&scfg);
        !          2570: 
        !          2571:        /* Create missing node directories and dsts.dab files */
        !          2572:        for(i=0;i<=scfg.sys_nodes;i++) {
        !          2573:                if(i)
        !          2574:                        md(scfg.node_path[i-1]);
        !          2575:                sprintf(str,"%sdsts.dab",i ? scfg.node_path[i-1] : scfg.ctrl_dir);
        !          2576:                if(flength(str)<DSTSDABLEN) {
        !          2577:                        if((file=sopen(str,O_WRONLY|O_CREAT|O_APPEND, SH_DENYNO))==-1) {
        !          2578:                close(file);
        !          2579:                                lprintf("!Error creating %s",str);
        !          2580:                                cleanup(1);
        !          2581:                                return; }
        !          2582:                        while(filelength(file)<DSTSDABLEN)
        !          2583:                                if(write(file,"\0",1)!=1)
        !          2584:                                        break;                          /* Create NULL system dsts.dab */
        !          2585:                        close(file); 
        !          2586:                } 
        !          2587:        }
        !          2588: 
        !          2589:        /* Initial global node variables */
        !          2590:        for(i=0;i<MAX_NODES;i++) {
        !          2591:                node_inbuf[i]=NULL;
        !          2592:        node_socket[i]=INVALID_SOCKET;
        !          2593:                spy_socket[i]=INVALID_SOCKET;
        !          2594:        }
        !          2595: 
        !          2596:        startup->node_inbuf=node_inbuf;
        !          2597: 
        !          2598:     /* open a socket and wait for a client */
        !          2599: 
        !          2600:     telnet_socket = open_socket(SOCK_STREAM);
        !          2601: 
        !          2602:        if(telnet_socket == INVALID_SOCKET) {
        !          2603:                lprintf("!ERROR %d creating Telnet socket", ERROR_VALUE);
        !          2604:                cleanup(1);
        !          2605:                return;
        !          2606:        }
        !          2607: 
        !          2608:     lprintf("Telnet socket %d opened",telnet_socket);
        !          2609: 
        !          2610:        if(startup->options&BBS_OPT_KEEP_ALIVE) {
        !          2611:                lprintf("Enabling WinSock Keep Alives");
        !          2612:                option = TRUE;
        !          2613: 
        !          2614:                result = setsockopt(telnet_socket, SOL_SOCKET, SO_KEEPALIVE
        !          2615:                ,(char *)&option, sizeof(option));
        !          2616: 
        !          2617:                if(result != 0) {
        !          2618:                        lprintf("!ERROR %d (%d) setting Telnet socket option", result, ERROR_VALUE);
        !          2619:                        cleanup(1);
        !          2620:                        return;
        !          2621:                }
        !          2622: 
        !          2623:        }
        !          2624: 
        !          2625:        LINGER linger;
        !          2626: 
        !          2627:        linger.l_onoff=true;
        !          2628:     linger.l_linger=5; /* seconds */
        !          2629: 
        !          2630:        result = setsockopt(telnet_socket, SOL_SOCKET, SO_LINGER
        !          2631:        ,(char *)&linger, sizeof(linger));
        !          2632: 
        !          2633:        if(result != 0) {
        !          2634:                lprintf("!ERROR %d (%d) setting Telnet socket options.", result, ERROR_VALUE);
        !          2635:                cleanup(1);
        !          2636:                return;
        !          2637:        }
        !          2638: 
        !          2639:        /*****************************/
        !          2640:        /* Listen for incoming calls */
        !          2641:        /*****************************/
        !          2642:     memset(&server_addr, 0, sizeof(server_addr));
        !          2643: 
        !          2644:        server_addr.sin_addr.s_addr = htonl(startup->telnet_interface);
        !          2645:     server_addr.sin_family = AF_INET;
        !          2646:     server_addr.sin_port   = htons(startup->telnet_port);
        !          2647: 
        !          2648:     result = bind(telnet_socket, (struct sockaddr *)&server_addr
        !          2649:        ,sizeof(server_addr));
        !          2650: 
        !          2651:        if(result != 0) {
        !          2652:                lprintf("!ERROR %d (%d) binding Telnet socket to port %d"
        !          2653:                        ,result, ERROR_VALUE,startup->telnet_port);
        !          2654:                cleanup(1);
        !          2655:                return;
        !          2656:        }
        !          2657: 
        !          2658:     result = listen(telnet_socket, 1);
        !          2659: 
        !          2660:        if(result != 0) {
        !          2661:                lprintf("!ERROR %d (%d) listening on Telnet socket", result, ERROR_VALUE);
        !          2662:                cleanup(1);
        !          2663:                return;
        !          2664:        }
        !          2665:        lprintf("Telnet server listening on port %d",startup->telnet_port);
        !          2666: 
        !          2667:        if(startup->options&BBS_OPT_ALLOW_RLOGIN) {
        !          2668: 
        !          2669:                /* open a socket and wait for a client */
        !          2670: 
        !          2671:                rlogin_socket = open_socket(SOCK_STREAM);
        !          2672: 
        !          2673:                if(rlogin_socket == INVALID_SOCKET) {
        !          2674:                        lprintf("!ERROR %d creating RLogin socket", ERROR_VALUE);
        !          2675:                        cleanup(1);
        !          2676:                        return;
        !          2677:                }
        !          2678: 
        !          2679:                lprintf("RLogin socket %d opened",rlogin_socket);
        !          2680: 
        !          2681:                LINGER linger;
        !          2682: 
        !          2683:                linger.l_onoff=true;
        !          2684:                linger.l_linger=5;      /* seconds */
        !          2685: 
        !          2686:                result = setsockopt(telnet_socket, SOL_SOCKET, SO_LINGER
        !          2687:                ,(char *)&linger, sizeof(linger));
        !          2688: 
        !          2689:                if(result != 0) {
        !          2690:                        lprintf("!ERROR %d (%d) setting RLogin socket options.", result, ERROR_VALUE);
        !          2691:                        cleanup(1);
        !          2692:                        return;
        !          2693:                }
        !          2694: 
        !          2695:                /*****************************/
        !          2696:                /* Listen for incoming calls */
        !          2697:                /*****************************/
        !          2698:                memset(&server_addr, 0, sizeof(server_addr));
        !          2699: 
        !          2700:                server_addr.sin_addr.s_addr = htonl(startup->rlogin_interface);
        !          2701:                server_addr.sin_family = AF_INET;
        !          2702:                server_addr.sin_port   = htons(startup->rlogin_port);
        !          2703: 
        !          2704:                result = bind(rlogin_socket, (struct sockaddr *)&server_addr
        !          2705:                ,sizeof(server_addr));
        !          2706: 
        !          2707:                if(result != 0) {
        !          2708:                        lprintf("!ERROR %d (%d) binding RLogin socket to port %d"
        !          2709:                                ,result, ERROR_VALUE,startup->rlogin_port);
        !          2710:                        cleanup(1);
        !          2711:                        return;
        !          2712:                }
        !          2713: 
        !          2714:                result = listen(rlogin_socket, 1);
        !          2715: 
        !          2716:                if(result != 0) {
        !          2717:                        lprintf("!ERROR %d (%d) listening on RLogin socket", result, ERROR_VALUE);
        !          2718:                        cleanup(1);
        !          2719:                        return;
        !          2720:                }
        !          2721:                lprintf("RLogin server listening on port %d",startup->rlogin_port);
        !          2722:        }
        !          2723: 
        !          2724: 
        !          2725:        sbbs = new sbbs_t(0, server_addr.sin_addr.s_addr
        !          2726:                ,"BBS System", telnet_socket, &scfg, text);
        !          2727:     sbbs->online = 0;
        !          2728:        if(sbbs->init()==false) {
        !          2729:                lputs("!BBS initialization failed");
        !          2730:                cleanup(1);
        !          2731:                return;
        !          2732:        }
        !          2733:        _beginthread(output_thread, 0, sbbs);
        !          2734: 
        !          2735:        events = new sbbs_t(0, server_addr.sin_addr.s_addr
        !          2736:                ,"BBS Events", INVALID_SOCKET, &scfg, text);
        !          2737:     events->online = 0;
        !          2738:        if(events->init()==false) {
        !          2739:                lputs("!Events initialization failed");
        !          2740:                cleanup(1);
        !          2741:                return;
        !          2742:        }
        !          2743:        _beginthread(event_thread, 0, events);
        !          2744: 
        !          2745:        for(i=startup->first_node;i<=startup->last_node;i++) {
        !          2746:                sbbs->getnodedat(i,&node,1);
        !          2747:                node.status=NODE_WFC;
        !          2748:                node.misc&=NODE_EVENT;
        !          2749:                node.action=0;
        !          2750:                sbbs->putnodedat(i,&node);
        !          2751:        }
        !          2752: 
        !          2753:        lprintf("BBS System thread started for nodes %d through %d"
        !          2754:        ,startup->first_node, startup->last_node);
        !          2755:        status(STATUS_WFC);
        !          2756: 
        !          2757:        /* signal caller that we've started up successfully */
        !          2758:     if(startup->started!=NULL)
        !          2759:        startup->started();
        !          2760: 
        !          2761:        while(telnet_socket!=INVALID_SOCKET) {
        !          2762: 
        !          2763:                if(node_threads_running==0) {   /* check for re-run flags */
        !          2764:                        bool rerun=false;
        !          2765:                        for(i=startup->first_node;i<=startup->last_node;i++) {
        !          2766:                                sbbs->getnodedat(i,&node,0);
        !          2767:                                if(node.misc&NODE_RRUN) {
        !          2768:                                        sbbs->getnodedat(i,&node,1);
        !          2769:                                        if(!rerun)
        !          2770:                                                lprintf("Node %d flagged for re-run",i);
        !          2771:                                        rerun=true;
        !          2772:                                        node.misc&=~NODE_RRUN;
        !          2773:                                        sbbs->putnodedat(i,&node);
        !          2774:                                }
        !          2775:                        }
        !          2776:                        if(rerun) {
        !          2777:                                lprintf("Loading configuration files from %s", scfg.ctrl_dir);
        !          2778:                                scfg.node_num=startup->first_node;
        !          2779:                                pthread_mutex_lock(&event_mutex);
        !          2780:                                if(!load_cfg(&scfg, text)) {
        !          2781:                                        lprintf("!Failed to load configuration files");
        !          2782:                                        break;
        !          2783:                                }
        !          2784:                                scfg_reloaded=true;
        !          2785:                                pthread_mutex_unlock(&event_mutex);
        !          2786:                        }
        !          2787:                }
        !          2788: 
        !          2789: 
        !          2790:        sbbs->online=0;
        !          2791: 
        !          2792:                /* now wait for connection */
        !          2793: 
        !          2794:                FD_ZERO(&socket_set);
        !          2795:                FD_SET(telnet_socket,&socket_set);
        !          2796:                high_socket_set=telnet_socket+1;
        !          2797:                if(startup->options&BBS_OPT_ALLOW_RLOGIN) {
        !          2798:                        FD_SET(rlogin_socket,&socket_set);
        !          2799:                        if(rlogin_socket+1>high_socket_set)
        !          2800:                                high_socket_set=rlogin_socket+1;
        !          2801:                }
        !          2802: 
        !          2803:                struct timeval tv;
        !          2804:                tv.tv_sec=2;
        !          2805:                tv.tv_usec=0;
        !          2806: 
        !          2807:                if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
        !          2808:                        if(i==0) {
        !          2809:                                mswait(1);
        !          2810:                                continue;
        !          2811:                        }
        !          2812:                        if(ERROR_VALUE==EINTR)
        !          2813:                                lprintf("Telnet Server listening interrupted");
        !          2814:                        else if(ERROR_VALUE == ENOTSOCK)
        !          2815:                lprintf("Telnet Server sockets closed");
        !          2816:                        else
        !          2817:                                lprintf("!ERROR %d selecting sockets",ERROR_VALUE);
        !          2818:                        break;
        !          2819:                }
        !          2820: 
        !          2821:                client_addr_len = sizeof(client_addr);
        !          2822: 
        !          2823:                bool rlogin = false;
        !          2824: 
        !          2825:                if(FD_ISSET(telnet_socket,&socket_set)) 
        !          2826:                        client_socket = accept(telnet_socket, (struct sockaddr *)&client_addr
        !          2827:                        ,&client_addr_len);
        !          2828:                else if(FD_ISSET(rlogin_socket,&socket_set)) {
        !          2829:                        client_socket = accept(rlogin_socket, (struct sockaddr *)&client_addr
        !          2830:                        ,&client_addr_len);
        !          2831:                        rlogin = true;
        !          2832:                } else {
        !          2833:                        lprintf("!No sockets set by select");
        !          2834:                        continue;
        !          2835:                }
        !          2836: 
        !          2837: 
        !          2838:                if(client_socket == INVALID_SOCKET)
        !          2839:                {
        !          2840:                        if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINTR)
        !          2841:                lputs("BBS socket closed");
        !          2842:             else
        !          2843:                                lprintf("!ERROR %d accept failed", ERROR_VALUE);
        !          2844:                        break;
        !          2845:                }
        !          2846:                lprintf("New client socket: %d",client_socket);
        !          2847:                if(startup->socket_open!=NULL)
        !          2848:                        startup->socket_open(TRUE);
        !          2849: 
        !          2850: #ifdef _WIN32
        !          2851:                if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)) 
        !          2852:                        PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          2853: #endif
        !          2854: 
        !          2855:                linger.l_onoff=true;
        !          2856:                linger.l_linger=5;      /* seconds */
        !          2857: 
        !          2858:                result = setsockopt(client_socket, SOL_SOCKET, SO_LINGER
        !          2859:                ,(char *)&linger, sizeof(linger));
        !          2860: 
        !          2861:                if(result != 0) {
        !          2862:                        lprintf("!ERROR %d (%d) setting socket options.", result, ERROR_VALUE);
        !          2863:                        close_socket(client_socket);
        !          2864:                        continue;
        !          2865:                }
        !          2866: 
        !          2867:                char host_ip[32];
        !          2868: 
        !          2869:                strcpy(host_ip,inet_ntoa(client_addr.sin_addr));
        !          2870: 
        !          2871:                lprintf("%s connection accepted from: %s"
        !          2872:                        , rlogin ? "RLogin" : "Telnet", host_ip);
        !          2873: 
        !          2874:                sbbs->client_socket=client_socket;      // require for output to the user
        !          2875:         sbbs->online=ON_REMOTE;
        !          2876: 
        !          2877:                if(sbbs->trashcan(host_ip,"ip")) {
        !          2878:                        close_socket(client_socket);
        !          2879:                        lprintf("IP blocked in ip.can");
        !          2880:                        sprintf(logstr, "Blocked IP: %s",host_ip);
        !          2881:                        sbbs->logline("@!",logstr);
        !          2882:                        continue;
        !          2883:                }
        !          2884: 
        !          2885:                if(rlogin) {
        !          2886:                        if(!sbbs->trashcan(host_ip,"rlogin")) {
        !          2887:                                close_socket(client_socket);
        !          2888:                                lprintf("IP not listed in rlogin.can");
        !          2889:                                sprintf(logstr, "Invalid RLogin from: %s",host_ip);
        !          2890:                                sbbs->logline("@!",logstr);
        !          2891:                                continue;
        !          2892:                        }
        !          2893:                        sbbs->outcom(0); /* acknowledge RLogin per RFC 1282 */
        !          2894:                }
        !          2895: 
        !          2896:                sbbs->putcom(crlf);
        !          2897:                sbbs->putcom(VERSION_NOTICE);
        !          2898:                sbbs->putcom(crlf);
        !          2899: 
        !          2900:                sbbs->bprintf("Connection from: %s\r\n", host_ip);
        !          2901: 
        !          2902:                struct hostent* h;
        !          2903:                if(startup->options&BBS_OPT_NO_HOST_LOOKUP)
        !          2904:                        h=NULL;
        !          2905:                else {
        !          2906:                        sbbs->bprintf("Resolving host name...");
        !          2907:                        h=gethostbyaddr((char *)&client_addr.sin_addr
        !          2908:                                ,sizeof(client_addr.sin_addr),AF_INET);
        !          2909:                }
        !          2910:                if(h!=NULL && h->h_name!=NULL)
        !          2911:                        host_name=h->h_name;
        !          2912:                else
        !          2913:                        host_name="<no name>";
        !          2914: 
        !          2915:                lprintf("Host name: %s", host_name);
        !          2916: 
        !          2917:                if(sbbs->trashcan(host_name,"host")) {
        !          2918:                        close_socket(client_socket);
        !          2919:                        lprintf("Host name blocked in host.can");
        !          2920:                        sprintf(logstr, "Blocked Host Name: %s",host_name);
        !          2921:                        sbbs->logline("@!",logstr);
        !          2922:                        continue;
        !          2923:                }
        !          2924: 
        !          2925:                /* Initialize client display */
        !          2926:                client.size=sizeof(client);
        !          2927:                client.time=time(NULL);
        !          2928:                sprintf(client.addr,"%.*s",(int)sizeof(client.addr)-1,host_ip);
        !          2929:                sprintf(client.host,"%.*s",(int)sizeof(client.host)-1,host_name);
        !          2930:                client.port=ntohs(client_addr.sin_port);
        !          2931:                client.protocol=rlogin ? "RLogin":"Telnet";
        !          2932:                client.user="<unknown>";
        !          2933:                client_on(client_socket,&client);
        !          2934: 
        !          2935:                sprintf(logstr, "%s %s", host_name, host_ip);
        !          2936:                sbbs->logline("@*",logstr);
        !          2937: 
        !          2938:                for(i=startup->first_node;i<=startup->last_node;i++) {
        !          2939:                        sbbs->getnodedat(i,&node,1);
        !          2940:                        if(node.status==NODE_WFC) {
        !          2941:                                node.status=NODE_LOGON;
        !          2942:                                sbbs->putnodedat(i,&node);
        !          2943:                                break;
        !          2944:                        }
        !          2945:                        sbbs->putnodedat(i,&node);
        !          2946:                }
        !          2947: 
        !          2948:                if(i>startup->last_node) {
        !          2949:                        sbbs->putcom("\r\nSorry, all telnet nodes are in use or otherwise unavailable.\r\n");
        !          2950:                        sbbs->putcom("Please try again later.\r\n");
        !          2951:                        lprintf("No nodes available for login.");
        !          2952:                        mswait(3000);
        !          2953:                        close_socket(client_socket);
        !          2954:                        client_off(client_socket);
        !          2955:                        continue;
        !          2956:                }
        !          2957: 
        !          2958:         node_socket[i-1]=client_socket;
        !          2959: 
        !          2960:                lprintf("Connecting client to node %d",i);
        !          2961: 
        !          2962:                sbbs_t* new_node = new sbbs_t(i, client_addr.sin_addr.s_addr, host_name
        !          2963:                ,client_socket, &scfg, text);
        !          2964: 
        !          2965:                new_node->client=client;
        !          2966: 
        !          2967:                if(new_node->init()==false) {
        !          2968:                        lprintf("!Node %d Initialization failure",new_node->cfg.node_num);
        !          2969:                        sbbs->putcom("\r\nSorry, initialization failed. Try again later.\r\n");
        !          2970:                        mswait(3000);
        !          2971:                        sbbs->getnodedat(new_node->cfg.node_num,&node,1);
        !          2972:                        node.status=NODE_WFC;
        !          2973:                        sbbs->putnodedat(new_node->cfg.node_num,&node);
        !          2974:                        delete new_node;
        !          2975:                        node_socket[i-1]=INVALID_SOCKET;
        !          2976:                        close_socket(client_socket);
        !          2977:                        client_off(client_socket);
        !          2978:                        continue;
        !          2979:                }
        !          2980: 
        !          2981:                if(rlogin==true) {
        !          2982:                        new_node->connection="RLogin";
        !          2983:                        new_node->sys_status|=SS_RLOGIN;
        !          2984:                }
        !          2985: 
        !          2986:                new_node->input_thread=(HANDLE)_beginthread(input_thread,0, new_node);
        !          2987:                _beginthread(output_thread, 0, new_node);
        !          2988:                _beginthread(node_thread, 0, new_node);
        !          2989:        }
        !          2990: 
        !          2991:     // Close all open sockets
        !          2992:     for(i=0;i<MAX_NODES;i++)
        !          2993:        if(node_socket[i]!=INVALID_SOCKET) {
        !          2994:                lprintf("Closing node %d socket %d", i+1, node_socket[i]);
        !          2995:                close_socket(node_socket[i]);
        !          2996:         }
        !          2997: 
        !          2998:        sbbs->client_socket=INVALID_SOCKET;
        !          2999:        events->terminated=true;
        !          3000:     // Wake-up BBS output thread so it can terminate
        !          3001:     sem_post(&sbbs->output_sem);
        !          3002: 
        !          3003:     // Wait for all node threads to terminate
        !          3004:        if(node_threads_running) {
        !          3005:                lprintf("Waiting for %d node threads to terminate...", node_threads_running);
        !          3006:                start=time(NULL);
        !          3007:                while(node_threads_running) {
        !          3008:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
        !          3009:                                lprintf("!TIMEOUT waiting for %d node thread(s) to "
        !          3010:                        "terminate", node_threads_running);
        !          3011:                                break;
        !          3012:                        }
        !          3013:                        mswait(100);
        !          3014:                }
        !          3015:        }
        !          3016: 
        !          3017:        // Wait for Events thread to terminate
        !          3018:        if(events->event_thread_running) {
        !          3019:                pthread_mutex_unlock(&event_mutex);
        !          3020:                lprintf("Waiting for event thread to terminate...");
        !          3021:                start=time(NULL);
        !          3022:                while(events->event_thread_running) {
        !          3023:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
        !          3024:                                lprintf("!TIMEOUT waiting for BBS event thread to "
        !          3025:                        "terminate");
        !          3026:                                break;
        !          3027:                        }
        !          3028:                        mswait(100);
        !          3029:                }
        !          3030:        }
        !          3031: 
        !          3032:     // Wait for BBS output thread to terminate
        !          3033:        if(sbbs->output_thread_running) {
        !          3034:                lprintf("Waiting for system output thread to terminate...");
        !          3035:                start=time(NULL);
        !          3036:                while(sbbs->output_thread_running) {
        !          3037:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
        !          3038:                                lprintf("!TIMEOUT waiting for BBS output thread to "
        !          3039:                        "terminate");
        !          3040:                                break;
        !          3041:                        }
        !          3042:                        mswait(100);
        !          3043:                }
        !          3044:        }
        !          3045: 
        !          3046:     // Set all nodes' status to OFFLINE
        !          3047:     for(i=startup->first_node;i<=startup->last_node;i++) {
        !          3048:         sbbs->getnodedat(i,&node,1);
        !          3049:         node.status=NODE_OFFLINE;
        !          3050:         sbbs->putnodedat(i,&node);
        !          3051:     }
        !          3052: 
        !          3053:        if(!events->event_thread_running)
        !          3054:                delete events;
        !          3055: 
        !          3056:     if(!sbbs->output_thread_running)
        !          3057:            delete sbbs;
        !          3058: 
        !          3059:        cleanup(0);
        !          3060: }
        !          3061: 
        !          3062: 
        !          3063: 

unix.superglobalmegacorp.com

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