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

1.1       root        1: /* main.cpp */
                      2: 
                      3: /* Synchronet main/telnet server thread and related functions */
                      4: 
1.1.1.2 ! root        5: /* $Id: main.cpp,v 1.366 2004/12/30 09:24:05 rswindell Exp $ */
1.1       root        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:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       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: #include "sbbs.h"
1.1.1.2 ! root       39: #include "ident.h"
1.1       root       40: #include "telnet.h" 
1.1.1.2 ! root       41: 
        !            42: #ifdef __unix__
        !            43:        #include <sys/un.h>
        !            44:        #ifndef SUN_LEN
        !            45:                #define SUN_LEN(su) \
        !            46:                (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
        !            47:        #endif
        !            48: #endif
1.1       root       49: 
                     50: //---------------------------------------------------------------------------
                     51: 
                     52: /* Temporary */
                     53: int    mswtyp=0;
                     54: uint riobp;
                     55: 
1.1.1.2 ! root       56: #define TELNET_SERVER "Synchronet Telnet Server"
1.1       root       57: #define STATUS_WFC     "Listening"
                     58: 
1.1.1.2 ! root       59: #define TIMEOUT_THREAD_WAIT            60                      // Seconds (was 15)
        !            60: #define IO_THREAD_BUF_SIZE             20000           // Bytes
1.1       root       61: 
                     62: // Globals
                     63: #ifdef _WIN32
1.1.1.2 ! root       64:        HANDLE          exec_mutex=NULL;
        !            65:        HINSTANCE       hK32=NULL;
1.1       root       66: 
1.1.1.2 ! root       67:        #if defined(_DEBUG) && defined(_MSC_VER)
        !            68:                        HANDLE  debug_log=INVALID_HANDLE_VALUE;
        !            69:                   _CrtMemState mem_chkpoint;
        !            70:        #endif // _DEBUG && _MSC_VER
1.1       root       71: 
1.1.1.2 ! root       72: #endif // _WIN32
1.1       root       73: 
1.1.1.2 ! root       74: time_t uptime=0;
        !            75: DWORD  served=0;
1.1       root       76: 
1.1.1.2 ! root       77: static ulong node_threads_running=0;
        !            78: static ulong thread_count=0;
        !            79:                
        !            80: char   lastuseron[LEN_ALIAS+1];  /* Name of user last online */
        !            81: RingBuf* node_inbuf[MAX_NODES];
        !            82: SOCKET spy_socket[MAX_NODES];
        !            83: #ifdef __unix__
        !            84: SOCKET uspy_socket[MAX_NODES];   /* UNIX domain spy sockets */
1.1       root       85: #endif
1.1.1.2 ! root       86: SOCKET node_socket[MAX_NODES];
        !            87: static SOCKET telnet_socket=INVALID_SOCKET;
        !            88: static SOCKET rlogin_socket=INVALID_SOCKET;
        !            89: static sbbs_t* sbbs=NULL;
        !            90: static scfg_t  scfg;
        !            91: static char *  text[TOTAL_TEXT];
        !            92: static WORD    first_node;
        !            93: static WORD    last_node;
        !            94: static bool    terminate_server=false;
        !            95: static link_list_t recycle_semfiles;
        !            96: static link_list_t shutdown_semfiles;
1.1       root       97: 
                     98: extern "C" {
                     99: 
                    100: static bbs_startup_t* startup=NULL;
                    101: 
                    102: static void status(char* str)
                    103: {
                    104:        if(startup!=NULL && startup->status!=NULL)
1.1.1.2 ! root      105:            startup->status(startup->cbdata,str);
1.1       root      106: }
                    107: 
                    108: static void update_clients()
                    109: {
                    110:        if(startup!=NULL && startup->clients!=NULL)
1.1.1.2 ! root      111:                startup->clients(startup->cbdata,node_threads_running);
1.1       root      112: }
                    113: 
1.1.1.2 ! root      114: void client_on(SOCKET sock, client_t* client, BOOL update)
1.1       root      115: {
                    116:        if(startup!=NULL && startup->client_on!=NULL)
1.1.1.2 ! root      117:                startup->client_on(startup->cbdata,TRUE,sock,client,update);
1.1       root      118: }
                    119: 
                    120: static void client_off(SOCKET sock)
                    121: {
                    122:        if(startup!=NULL && startup->client_on!=NULL)
1.1.1.2 ! root      123:                startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
1.1       root      124: }
                    125: 
1.1.1.2 ! root      126: static void thread_up(BOOL setuid)
1.1       root      127: {
1.1.1.2 ! root      128:        thread_count++;
1.1       root      129:        if(startup!=NULL && startup->thread_up!=NULL)
1.1.1.2 ! root      130:                startup->thread_up(startup->cbdata,TRUE,setuid);
1.1       root      131: }
                    132: 
                    133: static void thread_down()
                    134: {
1.1.1.2 ! root      135:        if(thread_count>0)
        !           136:                thread_count--;
1.1       root      137:        if(startup!=NULL && startup->thread_up!=NULL)
1.1.1.2 ! root      138:                startup->thread_up(startup->cbdata,FALSE,FALSE);
        !           139: }
        !           140: 
        !           141: int lputs(int level, char* str)
        !           142: {
        !           143:        if(startup==NULL || startup->lputs==NULL || str==NULL)
        !           144:        return(0);
        !           145: 
        !           146:     return(startup->lputs(startup->cbdata,level,str));
        !           147: }
        !           148: 
        !           149: int lprintf(int level, char *fmt, ...)
        !           150: {
        !           151:        va_list argptr;
        !           152:        char sbuf[1024];
        !           153: 
        !           154:     va_start(argptr,fmt);
        !           155:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
        !           156:        sbuf[sizeof(sbuf)-1]=0;
        !           157:     va_end(argptr);
        !           158:     return(lputs(level,sbuf));
        !           159: }
        !           160: 
        !           161: int eprintf(int level, char *fmt, ...)
        !           162: {
        !           163:        va_list argptr;
        !           164:        char sbuf[1024];
        !           165: 
        !           166:     if(startup==NULL || startup->event_lputs==NULL)
        !           167:         return(0);
        !           168: 
        !           169:     va_start(argptr,fmt);
        !           170:     vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
        !           171:        sbuf[sizeof(sbuf)-1]=0;
        !           172:     va_end(argptr);
        !           173:        strip_ctrl(sbuf);
        !           174:     return(startup->event_lputs(level,sbuf));
1.1       root      175: }
                    176: 
                    177: SOCKET open_socket(int type)
                    178: {
1.1.1.2 ! root      179:        SOCKET  sock;
        !           180:        char    error[256];
1.1       root      181: 
                    182:        sock=socket(AF_INET, type, IPPROTO_IP);
                    183:        if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) 
1.1.1.2 ! root      184:                startup->socket_open(startup->cbdata,TRUE);
        !           185:        if(sock!=INVALID_SOCKET && set_socket_options(&scfg, sock, error))
        !           186:                lprintf(LOG_ERR,"%04d !ERROR %s",sock,error);
        !           187: 
        !           188:        return(sock);
        !           189: }
        !           190: 
        !           191: SOCKET accept_socket(SOCKET s, SOCKADDR* addr, socklen_t* addrlen)
        !           192: {
        !           193:        SOCKET  sock;
        !           194: 
        !           195:        sock=accept(s,addr,addrlen);
        !           196:        if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) 
        !           197:                startup->socket_open(startup->cbdata,TRUE);
        !           198: 
1.1       root      199:        return(sock);
                    200: }
                    201: 
                    202: int close_socket(SOCKET sock)
                    203: {
                    204:        int             result;
                    205: 
1.1.1.2 ! root      206:        if(sock==INVALID_SOCKET || sock==0)
        !           207:                return(0);
        !           208: 
1.1       root      209:        shutdown(sock,SHUT_RDWR);       /* required on Unix */
                    210:        result=closesocket(sock);
1.1.1.2 ! root      211:        if(startup!=NULL && startup->socket_open!=NULL)
        !           212:                startup->socket_open(startup->cbdata,FALSE);
        !           213:        if(result!=0 && ERROR_VALUE!=ENOTSOCK)
        !           214:                lprintf(LOG_ERR,"!ERROR %d closing socket %d",ERROR_VALUE,sock);
1.1       root      215:        return(result);
                    216: }
                    217: 
1.1.1.2 ! root      218: 
        !           219: u_long resolve_ip(char *addr)
1.1       root      220: {
1.1.1.2 ! root      221:        HOSTENT*        host;
        !           222:        char*           p;
        !           223: 
        !           224:        if(*addr==0)
        !           225:                return((u_long)INADDR_NONE);
        !           226: 
        !           227:        for(p=addr;*p;p++)
        !           228:                if(*p!='.' && !isdigit(*p))
        !           229:                        break;
        !           230:        if(!(*p))
        !           231:                return(inet_addr(addr));
        !           232:        if((host=gethostbyname(addr))==NULL) 
        !           233:                return((u_long)INADDR_NONE);
        !           234:        return(*((ulong*)host->h_addr_list[0]));
1.1       root      235: }
                    236: 
1.1.1.2 ! root      237: } /* extern "C" */
        !           238: 
        !           239: #ifdef _WINSOCKAPI_
        !           240: 
        !           241: WSADATA WSAData;
        !           242: #define SOCKLIB_DESC WSAData.szDescription
        !           243: static BOOL WSAInitialized=FALSE;
        !           244: 
        !           245: static BOOL winsock_startup(void)
1.1       root      246: {
1.1.1.2 ! root      247:        int             status;             /* Status Code */
1.1       root      248: 
1.1.1.2 ! root      249:     if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
        !           250:                lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
        !           251:                WSAInitialized=TRUE;
        !           252:                return(TRUE);
        !           253:        }
        !           254: 
        !           255:     lprintf(LOG_ERR,"!WinSock startup ERROR %d", status);
        !           256:        return(FALSE);
1.1       root      257: }
                    258: 
1.1.1.2 ! root      259: #else /* No WINSOCK */
        !           260: 
        !           261: #define winsock_startup()      (TRUE)
        !           262: #define SOCKLIB_DESC NULL
        !           263: 
        !           264: #endif
        !           265: 
        !           266: #ifdef JAVASCRIPT
        !           267: 
        !           268: static js_server_props_t js_server_props;
        !           269: 
        !           270: JSBool 
        !           271: DLLCALL js_CreateArrayOfStrings(JSContext* cx, JSObject* parent, const char* name, char* str[],uintN flags)
        !           272: {
        !           273:        JSObject*       array;
        !           274:        JSString*       js_str;
        !           275:        jsval           val;
        !           276:        size_t          i;
        !           277:        jsuint          len=0;
        !           278:                
        !           279:        if(JS_GetProperty(cx,parent,name,&val) && val!=JSVAL_VOID)
        !           280:                array=JSVAL_TO_OBJECT(val);
        !           281:        else
        !           282:                if((array=JS_NewArrayObject(cx, 0, NULL))==NULL)        /* Assertion here, in _heap_alloc_dbg, June-21-2004 */
        !           283:                        return(JS_FALSE);                                                               /* Caused by nntpservice.js? */
        !           284: 
        !           285:        if(!JS_DefineProperty(cx, parent, name, OBJECT_TO_JSVAL(array)
        !           286:                ,NULL,NULL,flags))
        !           287:                return(JS_FALSE);
        !           288: 
        !           289:        if(!JS_GetArrayLength(cx, array, &len))
        !           290:                return(JS_FALSE);
        !           291: 
        !           292:        for(i=0;str[i]!=NULL;i++) {
        !           293:                if((js_str = JS_NewStringCopyZ(cx, str[i]))==NULL)
        !           294:                        break;
        !           295:                val = STRING_TO_JSVAL(js_str);
        !           296:                if(!JS_SetElement(cx, array, len+i, &val))
        !           297:                        break;
        !           298:        }
        !           299: 
        !           300:        return(JS_TRUE);
        !           301: }
        !           302: 
        !           303: /* Convert from Synchronet-specific jsSyncMethodSpec to JSAPI's JSFunctionSpec */
        !           304: 
        !           305: JSBool
        !           306: DLLCALL js_DescribeSyncObject(JSContext* cx, JSObject* obj, const char* str, int ver)
        !           307: {
        !           308:        JSString* js_str = JS_NewStringCopyZ(cx, str);
        !           309: 
        !           310:        if(js_str==NULL)
        !           311:                return(JS_FALSE);
        !           312: 
        !           313:        return(JS_DefineProperty(cx,obj,"_description"
        !           314:                        ,STRING_TO_JSVAL(js_str),NULL,NULL,JSPROP_READONLY)
        !           315:                && JS_DefineProperty(cx,obj,"_ver"
        !           316:                        ,INT_TO_JSVAL(ver),NULL,NULL,JSPROP_READONLY));
        !           317: }
        !           318: 
        !           319: JSBool
        !           320: DLLCALL js_DescribeSyncConstructor(JSContext* cx, JSObject* obj, const char* str)
        !           321: {
        !           322:        JSString* js_str = JS_NewStringCopyZ(cx, str);
        !           323: 
        !           324:        if(js_str==NULL)
        !           325:                return(JS_FALSE);
        !           326: 
        !           327:        return(JS_DefineProperty(cx,obj,"_constructor"
        !           328:                ,STRING_TO_JSVAL(js_str),NULL,NULL,JSPROP_READONLY));
        !           329: }
        !           330: 
        !           331: #ifdef _DEBUG
        !           332: 
        !           333: #if 0
        !           334: static char* server_prop_desc[] = {
        !           335: 
        !           336:         "server name and version number"
        !           337:        ,"detailed version/build information"
        !           338:        ,NULL
        !           339: };
        !           340: #endif
        !           341: 
        !           342: 
        !           343: static const char* method_array_name = "_method_list";
        !           344: static const char* propver_array_name = "_property_ver_list";
        !           345: 
        !           346: /*
        !           347:  * from jsatom.c:
        !           348:  * Keep this in sync with jspubtd.h -- an assertion below will insist that
        !           349:  * its length match the JSType enum's JSTYPE_LIMIT limit value.
        !           350:  */
        !           351: static const char *js_type_str[] = {
        !           352:     "void",                    // changed from "undefined"
        !           353:     "object",
        !           354:     "function",
        !           355:     "string",
        !           356:     "number",
        !           357:     "boolean",
        !           358:        "array",
        !           359:        "alias",
        !           360:        "undefined"
        !           361: };
        !           362: 
        !           363: JSBool
        !           364: DLLCALL js_DefineSyncProperties(JSContext *cx, JSObject *obj, jsSyncPropertySpec* props)
        !           365: {
        !           366:        uint            i;
        !           367:        jsval           val;
        !           368:        jsuint          len=0;
        !           369:        JSObject*       array;
        !           370: 
        !           371:        if((array=JS_NewArrayObject(cx, 0, NULL))==NULL)
        !           372:                return(JS_FALSE);
        !           373: 
        !           374:        if(!JS_DefineProperty(cx, obj, propver_array_name, OBJECT_TO_JSVAL(array)
        !           375:                ,NULL,NULL,JSPROP_READONLY))
        !           376:                return(JS_FALSE);
        !           377: 
        !           378:        for(i=0;props[i].name;i++) {
        !           379:                if(!JS_DefinePropertyWithTinyId(cx, obj, /* Never reserve any "slots" for properties */
        !           380:                        props[i].name,props[i].tinyid, JSVAL_VOID, NULL, NULL, props[i].flags|JSPROP_SHARED))
        !           381:                        return(JS_FALSE);
        !           382:                if(props[i].flags&JSPROP_ENUMERATE) {   /* No need to version invisible props */
        !           383:                        val = INT_TO_JSVAL(props[i].ver);
        !           384:                        if(!JS_SetElement(cx, array, len++, &val))
        !           385:                                return(JS_FALSE);
        !           386:                }
        !           387:        }
        !           388: 
        !           389:        return(JS_TRUE);
        !           390: }
        !           391: 
        !           392: JSBool 
        !           393: DLLCALL js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *funcs, BOOL append)
        !           394: {
        !           395:        int                     i;
        !           396:        jsuint          len=0;
        !           397:        jsval           val;
        !           398:        JSObject*       method;
        !           399:        JSObject*       method_array;
        !           400:        JSString*       js_str;
        !           401: 
        !           402:        /* Return existing method_list array if it's already been created */
        !           403:        if(JS_GetProperty(cx,obj,method_array_name,&val) && val!=JSVAL_VOID)
        !           404:                method_array=JSVAL_TO_OBJECT(val);
        !           405:        else
        !           406:                if((method_array=JS_NewArrayObject(cx, 0, NULL))==NULL) 
        !           407:                        return(JS_FALSE);
        !           408: 
        !           409:        if(!JS_DefineProperty(cx, obj, method_array_name, OBJECT_TO_JSVAL(method_array)
        !           410:                , NULL, NULL, 0))
        !           411:                return(JS_FALSE);
        !           412: 
        !           413:        if(append)
        !           414:                if(!JS_GetArrayLength(cx, method_array, &len))
        !           415:                        return(JS_FALSE);
        !           416: 
        !           417:        for(i=0;funcs[i].name;i++) {
        !           418: 
        !           419:                if(!JS_DefineFunction(cx, obj, funcs[i].name, funcs[i].call, funcs[i].nargs, 0))
        !           420:                        return(JS_FALSE);
        !           421: 
        !           422:                if(funcs[i].type==JSTYPE_ALIAS)
        !           423:                        continue;
        !           424: 
        !           425:                method = JS_NewObject(cx, NULL, NULL, method_array);    /* exception here June-7-2003 */
        !           426: 
        !           427:                if(method==NULL)
        !           428:                        return(JS_FALSE);
        !           429: 
        !           430:                if(funcs[i].name!=NULL) {
        !           431:                        if((js_str=JS_NewStringCopyZ(cx,funcs[i].name))==NULL)
        !           432:                                return(JS_FALSE);
        !           433:                        val = STRING_TO_JSVAL(js_str);
        !           434:                        JS_SetProperty(cx, method, "name", &val);
        !           435:                }
        !           436: 
        !           437:                val = INT_TO_JSVAL(funcs[i].nargs);
        !           438:                if(!JS_SetProperty(cx, method, "nargs", &val))
        !           439:                        return(JS_FALSE);
        !           440: 
        !           441:                if((js_str=JS_NewStringCopyZ(cx,js_type_str[funcs[i].type]))==NULL)
        !           442:                        return(JS_FALSE);
        !           443:                val = STRING_TO_JSVAL(js_str);
        !           444:                JS_SetProperty(cx, method, "type", &val);
        !           445: 
        !           446:                if(funcs[i].args!=NULL) {
        !           447:                        if((js_str=JS_NewStringCopyZ(cx,funcs[i].args))==NULL)
        !           448:                                return(JS_FALSE);
        !           449:                        val = STRING_TO_JSVAL(js_str);
        !           450:                        JS_SetProperty(cx, method, "args", &val);
        !           451:                }
        !           452: 
        !           453:                if(funcs[i].desc!=NULL) { 
        !           454:                        if((js_str=JS_NewStringCopyZ(cx,funcs[i].desc))==NULL)
        !           455:                                return(JS_FALSE);
        !           456:                        val = STRING_TO_JSVAL(js_str);
        !           457:                        JS_SetProperty(cx, method, "desc", &val);
        !           458:                }
        !           459: 
        !           460:                if(funcs[i].ver) {
        !           461:                        val = INT_TO_JSVAL(funcs[i].ver);
        !           462:                        JS_SetProperty(cx,method, "ver", &val);
        !           463:                }
        !           464: 
        !           465:                val=OBJECT_TO_JSVAL(method);
        !           466:                if(!JS_SetElement(cx, method_array, len+i, &val))
        !           467:                        return(JS_FALSE);
        !           468:        }
        !           469: 
        !           470:        return(JS_TRUE);
        !           471: }
        !           472: 
        !           473: #else // NON-DEBUG
        !           474: 
        !           475: JSBool
        !           476: DLLCALL js_DefineSyncProperties(JSContext *cx, JSObject *obj, jsSyncPropertySpec* props)
        !           477: {
        !           478:        uint i;
        !           479: 
        !           480:        for(i=0;props[i].name;i++) 
        !           481:                if(!JS_DefinePropertyWithTinyId(cx, obj, 
        !           482:                        props[i].name,props[i].tinyid, JSVAL_VOID, NULL, NULL, props[i].flags|JSPROP_SHARED))
        !           483:                        return(JS_FALSE);
        !           484: 
        !           485:        return(JS_TRUE);
        !           486: }
        !           487: 
        !           488: 
        !           489: JSBool 
        !           490: DLLCALL js_DefineSyncMethods(JSContext* cx, JSObject* obj, jsSyncMethodSpec *funcs, BOOL append)
        !           491: {
        !           492:        uint i;
        !           493: 
        !           494:        for(i=0;funcs[i].name;i++)
        !           495:                if(!JS_DefineFunction(cx, obj, funcs[i].name, funcs[i].call, funcs[i].nargs, 0))
        !           496:                        return(JS_FALSE);
        !           497:        return(JS_TRUE);
        !           498: }
        !           499: 
        !           500: #endif
        !           501: 
        !           502: /* This is a stream-lined version of JS_DefineConstDoubles */
        !           503: JSBool
        !           504: DLLCALL js_DefineConstIntegers(JSContext* cx, JSObject* obj, jsConstIntSpec* ints, int flags)
        !           505: {
        !           506:        uint    i;
        !           507:        jsval   val;
        !           508: 
        !           509:        for(i=0;ints[i].name;i++) {
        !           510:         if(!JS_NewNumberValue(cx, ints[i].val, &val))
        !           511:                        return(JS_FALSE);
        !           512: 
        !           513:                if(!JS_DefineProperty(cx, obj, ints[i].name, val ,NULL, NULL, flags))
        !           514:                        return(JS_FALSE);
        !           515:        }
        !           516:                
        !           517:        return(JS_TRUE);
        !           518: }
        !           519: 
        !           520: static JSBool
        !           521: js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           522: {
        !           523:     uintN              i=0;
        !           524:        int32           level=LOG_INFO;
        !           525:     JSString*  str=NULL;
        !           526:        sbbs_t*         sbbs;
        !           527: 
        !           528:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           529:                return(JS_FALSE);
        !           530: 
        !           531:        if(JSVAL_IS_NUMBER(argv[i]))
        !           532:                JS_ValueToInt32(cx,argv[i++],&level);
        !           533: 
        !           534:     for(; i<argc; i++) {
        !           535:                if((str=JS_ValueToString(cx, argv[i]))==NULL)
        !           536:                    return(JS_FALSE);
        !           537:                if(sbbs->online==ON_LOCAL) {
        !           538:                        if(startup!=NULL && startup->event_lputs!=NULL)
        !           539:                                startup->event_lputs(level,JS_GetStringBytes(str));
        !           540:                } else
        !           541:                        lputs(level,JS_GetStringBytes(str));
        !           542:        }
        !           543: 
        !           544:        if(str==NULL)
        !           545:                *rval = JSVAL_VOID;
        !           546:        else
        !           547:                *rval = STRING_TO_JSVAL(str);
        !           548:     return(JS_TRUE);
        !           549: }
        !           550: 
        !           551: static JSBool
        !           552: js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           553: {
        !           554:        uchar*          buf;
        !           555:        int32           len=128;
        !           556:        sbbs_t*         sbbs;
        !           557: 
        !           558:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           559:                return(JS_FALSE);
1.1       root      560: 
1.1.1.2 ! root      561:        *rval = JSVAL_VOID;
1.1       root      562: 
1.1.1.2 ! root      563:        if(argc)
        !           564:                JS_ValueToInt32(cx,argv[0],&len);
        !           565: 
        !           566:        if((buf=(uchar*)malloc(len))==NULL)
        !           567:                return(JS_TRUE);
        !           568: 
        !           569:        len=RingBufRead(&sbbs->inbuf,buf,len);
        !           570: 
        !           571:        if(len>0)
        !           572:                *rval = STRING_TO_JSVAL(JS_NewStringCopyN(cx,(char*)buf,len));
        !           573: 
        !           574:        free(buf);
        !           575:        return(JS_TRUE);
        !           576: }
        !           577: 
        !           578: static JSBool
        !           579: js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           580: {
        !           581:        char*           buf;
        !           582:        int32           len=128;
        !           583:        sbbs_t*         sbbs;
        !           584: 
        !           585:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           586:                return(JS_FALSE);
        !           587: 
        !           588:        *rval = JSVAL_VOID;
        !           589: 
        !           590:        if(argc)
        !           591:                JS_ValueToInt32(cx,argv[0],&len);
        !           592: 
        !           593:        if((buf=(char*)malloc(len))==NULL)
        !           594:                return(JS_TRUE);
        !           595: 
        !           596:        len=sbbs->getstr(buf,len,K_NONE);
        !           597: 
        !           598:        if(len>0)
        !           599:                *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,buf));
        !           600: 
        !           601:        free(buf);
        !           602:        return(JS_TRUE);
        !           603: }
        !           604: 
        !           605: static JSBool
        !           606: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           607: {
        !           608:     uintN              i;
        !           609:     JSString*  str=NULL;
        !           610:        sbbs_t*         sbbs;
        !           611: 
        !           612:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           613:                return(JS_FALSE);
        !           614: 
        !           615:     for (i = 0; i < argc; i++) {
        !           616:                if((str=JS_ValueToString(cx, argv[i]))==NULL)
        !           617:                    return(JS_FALSE);
        !           618:                if(sbbs->online==ON_LOCAL)
        !           619:                        eprintf(LOG_INFO,"%s",JS_GetStringBytes(str));
        !           620:                else
        !           621:                        sbbs->bputs(JS_GetStringBytes(str));
        !           622:        }
        !           623: 
        !           624:        if(str==NULL)
        !           625:                *rval = JSVAL_VOID;
        !           626:        else
        !           627:                *rval = STRING_TO_JSVAL(str);
        !           628:     return(JS_TRUE);
        !           629: }
        !           630: 
        !           631: static JSBool
        !           632: js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           633: {
        !           634:        sbbs_t*         sbbs;
        !           635: 
        !           636:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           637:                return(JS_FALSE);
        !           638: 
        !           639:        js_write(cx,obj,argc,argv,rval);
        !           640:        if(sbbs->online==ON_REMOTE)
        !           641:                sbbs->bputs(crlf);
        !           642: 
        !           643:     return(JS_TRUE);
        !           644: }
        !           645: 
        !           646: static JSBool
        !           647: js_printf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           648: {
        !           649:        char*           p;
        !           650:     uintN              i;
        !           651:        JSString *      fmt;
        !           652:     JSString * str;
        !           653:        sbbs_t*         sbbs;
        !           654:        va_list         arglist[64];
        !           655: 
        !           656:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           657:                return(JS_FALSE);
        !           658: 
        !           659:        if((fmt = JS_ValueToString(cx, argv[0]))==NULL)
        !           660:                return(JS_FALSE);
        !           661: 
        !           662:        memset(arglist,0,sizeof(arglist));      // Initialize arglist to NULLs
        !           663: 
        !           664:     for (i = 1; i < argc && i<sizeof(arglist)/sizeof(arglist[0]); i++) {
        !           665:                if(JSVAL_IS_DOUBLE(argv[i]))
        !           666:                        arglist[i-1]=(char*)(unsigned long)*JSVAL_TO_DOUBLE(argv[i]);
        !           667:                else if(JSVAL_IS_INT(argv[i]))
        !           668:                        arglist[i-1]=(char *)JSVAL_TO_INT(argv[i]);
        !           669:                else {
        !           670:                        if((str=JS_ValueToString(cx, argv[i]))==NULL) {
        !           671:                                JS_ReportError(cx,"JS_ValueToString failed");
        !           672:                            return(JS_FALSE);
        !           673:                        }
        !           674:                        arglist[i-1]=JS_GetStringBytes(str);
        !           675:                }
        !           676:        }
        !           677:        
        !           678:        if((p=JS_vsmprintf(JS_GetStringBytes(fmt),(char*)arglist))==NULL)
        !           679:                return(JS_FALSE);
        !           680: 
        !           681:        if(sbbs->online==ON_LOCAL)
        !           682:                eprintf(LOG_INFO,"%s",p);
        !           683:        else
        !           684:                sbbs->bputs(p);
        !           685: 
        !           686:        *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, p));
        !           687: 
        !           688:        JS_smprintf_free(p);
        !           689: 
        !           690:     return(JS_TRUE);
        !           691: }
        !           692: 
        !           693: static JSBool
        !           694: js_alert(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           695: {
        !           696:     JSString * str;
        !           697:        sbbs_t*         sbbs;
        !           698: 
        !           699:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           700:                return(JS_FALSE);
        !           701: 
        !           702:        if((str=JS_ValueToString(cx, argv[0]))==NULL)
        !           703:            return(JS_FALSE);
        !           704: 
        !           705:        sbbs->attr(sbbs->cfg.color[clr_err]);
        !           706:        sbbs->bputs(JS_GetStringBytes(str));
        !           707:        sbbs->attr(LIGHTGRAY);
        !           708:        sbbs->bputs(crlf);
        !           709: 
        !           710:        *rval = JSVAL_VOID;
        !           711:     return(JS_TRUE);
        !           712: }
        !           713: 
        !           714: static JSBool
        !           715: js_confirm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           716: {
        !           717:     JSString * str;
        !           718:        sbbs_t*         sbbs;
        !           719: 
        !           720:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           721:                return(JS_FALSE);
        !           722: 
        !           723:        if((str=JS_ValueToString(cx, argv[0]))==NULL)
        !           724:            return(JS_FALSE);
        !           725: 
        !           726:        *rval = BOOLEAN_TO_JSVAL(sbbs->yesno(JS_GetStringBytes(str)));
        !           727:        return(JS_TRUE);
        !           728: }
        !           729: 
        !           730: static JSBool
        !           731: js_prompt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
        !           732: {
        !           733:        char            instr[81];
        !           734:     JSString * prompt;
        !           735:     JSString * str;
        !           736:        sbbs_t*         sbbs;
        !           737: 
        !           738:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           739:                return(JS_FALSE);
        !           740: 
        !           741:        if((prompt=JS_ValueToString(cx, argv[0]))==NULL)
        !           742:            return(JS_FALSE);
        !           743: 
        !           744:        if(argc>1) {
        !           745:                if((str=JS_ValueToString(cx, argv[1]))==NULL)
        !           746:                    return(JS_FALSE);
        !           747:                SAFECOPY(instr,JS_GetStringBytes(str));
        !           748:        } else
        !           749:                instr[0]=0;
        !           750: 
        !           751:        sbbs->bprintf("\1n\1y\1h%s\1w: ",JS_GetStringBytes(prompt));
        !           752: 
        !           753:        if(!sbbs->getstr(instr,sizeof(instr)-1,K_EDIT)) {
        !           754:                *rval = JSVAL_NULL;
        !           755:                return(JS_TRUE);
        !           756:        }
        !           757: 
        !           758:        if((str=JS_NewStringCopyZ(cx, instr))==NULL)
        !           759:            return(JS_FALSE);
        !           760: 
        !           761:        *rval = STRING_TO_JSVAL(str);
        !           762:     return(JS_TRUE);
        !           763: }
        !           764: 
        !           765: static jsSyncMethodSpec js_global_functions[] = {
        !           766:        {"log",                         js_log,                         1,      JSTYPE_STRING,  JSDOCSTR("[level,] value [,value]")
        !           767:        ,JSDOCSTR("add a line of text to the server and/or system log, "
        !           768:                "<i>values</i> are typically string constants or variables, "
        !           769:                "<i>level</i> is the debug level/priority (default: <tt>LOG_INFO</tt>)")
        !           770:        ,311
        !           771:        },
        !           772:        {"read",                        js_read,                        0,      JSTYPE_STRING,  JSDOCSTR("[count]")
        !           773:        ,JSDOCSTR("read up to count characters from input stream")
        !           774:        ,311
        !           775:        },
        !           776:        {"readln",                      js_readln,                      0,      JSTYPE_STRING,  JSDOCSTR("[count]")
        !           777:        ,JSDOCSTR("read a single line, up to count characters, from input stream")
        !           778:        ,311
        !           779:        },
        !           780:        {"write",                       js_write,                       0,      JSTYPE_VOID,    JSDOCSTR("value [,value]")
        !           781:        ,JSDOCSTR("send one or more values (typically strings) to the server output")
        !           782:        ,311
        !           783:        },
        !           784:        {"print",                       js_writeln,                     0,      JSTYPE_ALIAS },
        !           785:     {"writeln",         js_writeln,         0, JSTYPE_VOID,    JSDOCSTR("value [,value]")
        !           786:        ,JSDOCSTR("send a line of text to the console or event log with automatic line termination (CRLF), "
        !           787:                "<i>values</i> are typically string constants or variables (AKA print)")
        !           788:        ,311
        !           789:        },
        !           790:     {"printf",          js_printf,          1, JSTYPE_STRING,  JSDOCSTR("string format [,value][,value]")
        !           791:        ,JSDOCSTR("print a formatted string - <small>CAUTION: for experienced C programmers ONLY</small>")
        !           792:        ,310
        !           793:        },      
        !           794:        {"alert",                       js_alert,                       1,      JSTYPE_VOID,    JSDOCSTR("value")
        !           795:        ,JSDOCSTR("print an alert message (ala client-side JS)")
        !           796:        ,310
        !           797:        },
        !           798:        {"prompt",                      js_prompt,                      1,      JSTYPE_STRING,  JSDOCSTR("[value]")
        !           799:        ,JSDOCSTR("displays a prompt (<i>value</i>) and returns a string of user input (ala clent-side JS)")
        !           800:        ,310
        !           801:        },
        !           802:        {"confirm",                     js_confirm,                     1,      JSTYPE_BOOLEAN, JSDOCSTR("value")
        !           803:        ,JSDOCSTR("displays a Yes/No prompt and returns <i>true</i> or <i>false</i> "
        !           804:                "based on users confirmation (ala client-side JS)")
        !           805:        ,310
        !           806:        },
        !           807:     {0}
        !           808: };
        !           809: 
        !           810: static void
        !           811: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
        !           812: {
        !           813:        char    line[64];
        !           814:        char    file[MAX_PATH+1];
        !           815:        sbbs_t* sbbs;
        !           816:        const char*     warning;
        !           817: 
        !           818:        if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL)
        !           819:                return;
        !           820:        
        !           821:        if(report==NULL) {
        !           822:                lprintf(LOG_ERR,"!JavaScript: %s", message);
        !           823:                return;
        !           824:     }
        !           825: 
        !           826:        if(report->filename)
        !           827:                sprintf(file," %s",report->filename);
        !           828:        else
        !           829:                file[0]=0;
        !           830: 
        !           831:        if(report->lineno)
        !           832:                sprintf(line," line %d",report->lineno);
        !           833:        else
        !           834:                line[0]=0;
        !           835: 
        !           836:        if(JSREPORT_IS_WARNING(report->flags)) {
        !           837:                if(JSREPORT_IS_STRICT(report->flags))
        !           838:                        warning="strict warning";
        !           839:                else
        !           840:                        warning="warning";
        !           841:        } else
        !           842:                warning=nulstr;
        !           843: 
        !           844:        if(sbbs->online==ON_LOCAL) 
        !           845:                eprintf(LOG_ERR,"!JavaScript %s%s%s: %s",warning,file,line,message);
        !           846:        else {
        !           847:                lprintf(LOG_ERR,"!JavaScript %s%s%s: %s",warning,file,line,message);
        !           848:                sbbs->bprintf("!JavaScript %s%s%s: %s\r\n",warning,file,line,message);
        !           849:        }
        !           850: }
        !           851: 
        !           852: bool sbbs_t::js_init()
        !           853: {
        !           854:        char            node[128];
        !           855: 
        !           856:     if(cfg.node_num)
        !           857:        sprintf(node,"Node %d",cfg.node_num);
        !           858:     else
        !           859:        strcpy(node,client_name);
        !           860: 
        !           861:        lprintf(LOG_DEBUG,"%s JavaScript: Creating runtime: %lu bytes"
        !           862:                ,node,startup->js_max_bytes);
        !           863: 
        !           864:        if((js_runtime = JS_NewRuntime(startup->js_max_bytes))==NULL)
        !           865:                return(false);
        !           866: 
        !           867:        lprintf(LOG_DEBUG,"%s JavaScript: Initializing context (stack: %lu bytes)"
        !           868:                ,node,startup->js_cx_stack);
        !           869: 
        !           870:     if((js_cx = JS_NewContext(js_runtime, startup->js_cx_stack))==NULL)
        !           871:                return(false);
        !           872:        
        !           873:        memset(&js_branch,0,sizeof(js_branch));
        !           874:        js_branch.limit = startup->js_branch_limit;
        !           875:        js_branch.gc_interval = startup->js_gc_interval;
        !           876:        js_branch.yield_interval = startup->js_yield_interval;
        !           877:        js_branch.terminated = &terminated;
        !           878:        js_branch.auto_terminate = TRUE;
        !           879: 
        !           880:        bool success=false;
        !           881: 
        !           882:        do {
        !           883: 
        !           884:                JS_SetErrorReporter(js_cx, js_ErrorReporter);
        !           885: 
        !           886:                JS_SetContextPrivate(js_cx, this);      /* Store a pointer to sbbs_t instance */
        !           887: 
        !           888:                /* Global Objects (including system, js, client, Socket, MsgBase, File, User, etc. */
        !           889:                if((js_glob=js_CreateCommonObjects(js_cx, &scfg, &cfg, js_global_functions
        !           890:                                        ,uptime, startup->host_name, SOCKLIB_DESC       /* system */
        !           891:                                        ,&js_branch                                                                     /* js */
        !           892:                                        ,&client, client_socket                                         /* client */
        !           893:                                        ,&js_server_props                                                       /* server */
        !           894:                        ))==NULL)
        !           895:                        break;
        !           896: 
        !           897: #ifdef _DEBUG
        !           898:                JS_DefineProperty(js_cx, js_glob, "_global", OBJECT_TO_JSVAL(js_glob)
        !           899:                        ,NULL,NULL,JSPROP_READONLY);
        !           900: #endif
        !           901: 
        !           902: 
        !           903:                /* BBS Object */
        !           904:                if(js_CreateBbsObject(js_cx, js_glob)==NULL)
        !           905:                        break;
        !           906: 
        !           907:                /* Console Object */
        !           908:                if(js_CreateConsoleObject(js_cx, js_glob)==NULL)
        !           909:                        break;
        !           910: 
        !           911:                success=true;
        !           912: 
        !           913:        } while(0);
        !           914: 
        !           915:        if(!success) {
        !           916:                JS_DestroyContext(js_cx);
        !           917:                js_cx=NULL;
        !           918:                return(false);
        !           919:        }
        !           920: 
        !           921:        return(true);
        !           922: }
        !           923: 
        !           924: void sbbs_t::js_create_user_objects(void)
        !           925: {
        !           926:        if(js_cx==NULL)
        !           927:                return;
        !           928: 
        !           929:        if(!js_CreateUserObjects(js_cx, js_glob, &cfg, &useron, NULL, subscan)) 
        !           930:                lprintf(LOG_ERR,"!JavaScript ERROR creating user objects");
        !           931: }
        !           932: 
        !           933: #endif /* JAVASCRIPT */
        !           934: 
        !           935: static BYTE* telnet_interpret(sbbs_t* sbbs, BYTE* inbuf, int inlen,
1.1       root      936:                                                                        BYTE* outbuf, int& outlen)
                    937: {
                    938:        BYTE*   first_iac=NULL;
                    939:        BYTE*   first_cr=NULL;
                    940:        int     i;
                    941: 
1.1.1.2 ! root      942:        if(inlen<1) {
        !           943:                outlen=0;
        !           944:                return(inbuf);  // no length? No interpretation
        !           945:        }
1.1       root      946: 
                    947:     first_iac=(BYTE*)memchr(inbuf, TELNET_IAC, inlen);
                    948: 
1.1.1.2 ! root      949:        if(!(sbbs->telnet_mode&TELNET_MODE_GATE) 
        !           950:                && sbbs->telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL
1.1       root      951:                && !(sbbs->console&CON_RAW_IN)) {
                    952:                if(sbbs->telnet_last_rxch==CR)
                    953:                        first_cr=inbuf;
                    954:                else
                    955:                        first_cr=(BYTE*)memchr(inbuf, CR, inlen);
                    956:        }
                    957: 
                    958:     if(!sbbs->telnet_cmdlen    && first_iac==NULL && first_cr==NULL) {
                    959:         outlen=inlen;
                    960:         return(inbuf); // no interpretation needed
                    961:     }
                    962: 
                    963:     if(first_iac!=NULL || first_cr!=NULL) {
                    964:                if(first_iac!=NULL && (first_cr==NULL || first_iac<first_cr))
                    965:                        outlen=first_iac-inbuf;
                    966:                else
                    967:                        outlen=first_cr-inbuf;
                    968:            memcpy(outbuf, inbuf, outlen);
                    969:     } else
                    970:        outlen=0;
                    971: 
                    972:     for(i=outlen;i<inlen;i++) {
1.1.1.2 ! root      973:                if(!(sbbs->telnet_mode&TELNET_MODE_GATE) 
        !           974:                        && sbbs->telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL
1.1       root      975:                        && !(sbbs->console&CON_RAW_IN)) {
                    976:                        if(sbbs->telnet_last_rxch==CR
                    977:                                && (inbuf[i]==LF || inbuf[i]==0)) { // CR/LF or CR/NUL, ignore 2nd char
1.1.1.2 ! root      978: #if 0 /* Debug CR/LF problems */
        !           979:                                lprintf(LOG_INFO,"Node %d CR/%02Xh detected and ignored"
        !           980:                                        ,sbbs->cfg.node_num, inbuf[i]);
        !           981: #endif
1.1       root      982:                                sbbs->telnet_last_rxch=inbuf[i];
                    983:                                continue;
                    984:                        }
                    985:                        sbbs->telnet_last_rxch=inbuf[i];
                    986:                }
                    987: 
                    988:         if(inbuf[i]==TELNET_IAC && sbbs->telnet_cmdlen==1) { /* escaped 255 */
                    989:             sbbs->telnet_cmdlen=0;
                    990:             outbuf[outlen++]=TELNET_IAC;
                    991:             continue;
                    992:         }
                    993:         if(inbuf[i]==TELNET_IAC || sbbs->telnet_cmdlen) {
1.1.1.2 ! root      994: 
        !           995:                        if(sbbs->telnet_cmdlen<sizeof(sbbs->telnet_cmd))
        !           996:                                sbbs->telnet_cmd[sbbs->telnet_cmdlen++]=inbuf[i];
        !           997: 
        !           998:                        uchar command   = sbbs->telnet_cmd[1];
        !           999:                        uchar option    = sbbs->telnet_cmd[2];
        !          1000: 
        !          1001:                        if(sbbs->telnet_cmdlen>=2 && command==TELNET_SB) {
        !          1002:                                if(inbuf[i]==TELNET_SE 
        !          1003:                                        && sbbs->telnet_cmd[sbbs->telnet_cmdlen-2]==TELNET_IAC) {
        !          1004:                                        /* sub-option terminated */
        !          1005:                                        if(option==TELNET_TERM_TYPE
        !          1006:                                                && sbbs->telnet_cmd[3]==TELNET_TERM_IS) {
        !          1007:                                                sprintf(sbbs->terminal,"%.*s",(int)sbbs->telnet_cmdlen-6,sbbs->telnet_cmd+4);
        !          1008:                                                lprintf(LOG_DEBUG,"Node %d %s telnet terminal type: %s"
        !          1009:                                        ,sbbs->cfg.node_num
        !          1010:                                                        ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !          1011:                                                        ,sbbs->terminal);
        !          1012: 
        !          1013:                                        } else if(option==TELNET_TERM_SPEED
        !          1014:                                                && sbbs->telnet_cmd[3]==TELNET_TERM_IS) {
        !          1015:                                                char speed[128];
        !          1016:                                                sprintf(speed,"%.*s",(int)sbbs->telnet_cmdlen-6,sbbs->telnet_cmd+4);
        !          1017:                                                lprintf(LOG_DEBUG,"Node %d %s telnet terminal speed: %s"
        !          1018:                                        ,sbbs->cfg.node_num
        !          1019:                                                        ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !          1020:                                                        ,speed);
        !          1021: 
        !          1022:                                        } else if(option==TELNET_NEGOTIATE_WINDOW_SIZE) {
        !          1023:                                                long cols = (sbbs->telnet_cmd[3]<<8) | sbbs->telnet_cmd[4];
        !          1024:                                                long rows = (sbbs->telnet_cmd[5]<<8) | sbbs->telnet_cmd[6];
        !          1025:                                                lprintf(LOG_DEBUG,"Node %d %s telnet window size: %ux%u"
        !          1026:                                        ,sbbs->cfg.node_num
        !          1027:                                                        ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !          1028:                                                        ,sbbs->cols
        !          1029:                                                        ,sbbs->rows);
        !          1030:                                                if(rows && !sbbs->useron.rows)  /* auto-detect rows */
        !          1031:                                                        sbbs->rows=rows;
        !          1032:                                                if(cols)
        !          1033:                                                        sbbs->cols=cols;
        !          1034: 
        !          1035:                                        } else if(startup->options&BBS_OPT_DEBUG_TELNET)
        !          1036:                                lprintf(LOG_DEBUG,"Node %d %s unsupported telnet sub-negotiation cmd: %s"
        !          1037:                                        ,sbbs->cfg.node_num
        !          1038:                                                        ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !          1039:                                        ,telnet_opt_desc(option));
        !          1040:                                        sbbs->telnet_cmdlen=0;
        !          1041:                                }
        !          1042:                        }
        !          1043:             else if(sbbs->telnet_cmdlen==2 && inbuf[i]<TELNET_WILL) {
1.1       root     1044:                                if(startup->options&BBS_OPT_DEBUG_TELNET)
1.1.1.2 ! root     1045:                        lprintf(LOG_DEBUG,"Node %d %s telnet cmd: %s"
1.1       root     1046:                                ,sbbs->cfg.node_num
                   1047:                                                ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
1.1.1.2 ! root     1048:                                ,telnet_cmd_desc(option));
1.1       root     1049:                 sbbs->telnet_cmdlen=0;
                   1050:             }
1.1.1.2 ! root     1051:             else if(sbbs->telnet_cmdlen>=3) {  /* telnet option negotiation */
        !          1052: 
        !          1053:                                if(startup->options&BBS_OPT_DEBUG_TELNET)
        !          1054:                                        lprintf(LOG_DEBUG,"Node %d %s telnet cmd: %s %s"
        !          1055:                                                ,sbbs->cfg.node_num
        !          1056:                                                ,sbbs->telnet_mode&TELNET_MODE_GATE ? "passed-through" : "received"
        !          1057:                                                ,telnet_cmd_desc(command)
        !          1058:                                                ,telnet_opt_desc(option));
        !          1059: 
        !          1060:                                if(!(sbbs->telnet_mode&TELNET_MODE_GATE)) {
        !          1061:                                        if(command==TELNET_DO || command==TELNET_DONT) {        /* local options */
        !          1062:                                                if(sbbs->telnet_local_option[option]!=command) {
        !          1063:                                                        sbbs->telnet_local_option[option]=command;
        !          1064:                                                        sbbs->send_telnet_cmd(telnet_opt_ack(command),option);
        !          1065:                                                }
        !          1066:                                        } else { /* WILL/WONT (remote options) */ 
        !          1067:                                                if(sbbs->telnet_remote_option[option]!=command) {       
        !          1068:                                                
        !          1069:                                                        switch(option) {
        !          1070:                                                                case TELNET_BINARY_TX:
        !          1071:                                                                case TELNET_ECHO:
        !          1072:                                                                case TELNET_TERM_TYPE:
        !          1073:                                                                case TELNET_TERM_SPEED:
        !          1074:                                                                case TELNET_SUP_GA:
        !          1075:                                                                case TELNET_NEGOTIATE_WINDOW_SIZE:
        !          1076:                                                                        sbbs->telnet_remote_option[option]=command;
        !          1077:                                                                        sbbs->send_telnet_cmd(telnet_opt_ack(command),option);
        !          1078:                                                                        break;
        !          1079:                                                                default: /* unsupported remote options */
        !          1080:                                                                        if(command==TELNET_WILL) /* NAK */
        !          1081:                                                                                sbbs->send_telnet_cmd(telnet_opt_nak(command),option);
        !          1082:                                                                        break;
        !          1083:                                                        }
        !          1084:                                                }
        !          1085: 
        !          1086:                                                if(command==TELNET_WILL && option==TELNET_TERM_TYPE) {
        !          1087:                                                        if(startup->options&BBS_OPT_DEBUG_TELNET)
        !          1088:                                                                lprintf(LOG_DEBUG,"Node %d requesting telnet terminal type"
        !          1089:                                                                        ,sbbs->cfg.node_num);
        !          1090: 
        !          1091:                                                        char    buf[64];
        !          1092:                                                        sprintf(buf,"%c%c%c%c%c%c"
        !          1093:                                                                ,TELNET_IAC,TELNET_SB
        !          1094:                                                                ,TELNET_TERM_TYPE,TELNET_TERM_SEND
        !          1095:                                                                ,TELNET_IAC,TELNET_SE);
        !          1096:                                                        sbbs->putcom(buf,6);
        !          1097:                                                }
        !          1098:                                                else if(command==TELNET_WILL && option==TELNET_TERM_SPEED) {
        !          1099:                                                        if(startup->options&BBS_OPT_DEBUG_TELNET)
        !          1100:                                                                lprintf(LOG_DEBUG,"Node %d requesting telnet terminal speed"
        !          1101:                                                                        ,sbbs->cfg.node_num);
        !          1102: 
        !          1103:                                                        char    buf[64];
        !          1104:                                                        sprintf(buf,"%c%c%c%c%c%c"
        !          1105:                                                                ,TELNET_IAC,TELNET_SB
        !          1106:                                                                ,TELNET_TERM_SPEED,TELNET_TERM_SEND
        !          1107:                                                                ,TELNET_IAC,TELNET_SE);
        !          1108:                                                        sbbs->putcom(buf,6);
1.1       root     1109:                                                }
                   1110:                                        }
                   1111:                                }
1.1.1.2 ! root     1112: 
1.1       root     1113:                 sbbs->telnet_cmdlen=0;
1.1.1.2 ! root     1114: 
1.1       root     1115:             }
                   1116:                        if(sbbs->telnet_mode&TELNET_MODE_GATE)  // Pass-through commads
                   1117:                                outbuf[outlen++]=inbuf[i];
                   1118:         } else
                   1119:                outbuf[outlen++]=inbuf[i];
                   1120:     }
                   1121:     return(outbuf);
                   1122: }
                   1123: 
1.1.1.2 ! root     1124: void sbbs_t::send_telnet_cmd(uchar cmd, uchar opt)
        !          1125: {
        !          1126:        char buf[16];
        !          1127:        
        !          1128:        if(telnet_mode&TELNET_MODE_OFF) 
        !          1129:                return;
        !          1130: 
        !          1131:        if(cmd<TELNET_WILL) {
        !          1132:                if(startup->options&BBS_OPT_DEBUG_TELNET)
        !          1133:             lprintf(LOG_DEBUG,"Node %d sending telnet cmd: %s"
        !          1134:                    ,cfg.node_num
        !          1135:                 ,telnet_cmd_desc(cmd));
        !          1136:                sprintf(buf,"%c%c",TELNET_IAC,cmd);
        !          1137:                putcom(buf,2);
        !          1138:        } else {
        !          1139:                if(startup->options&BBS_OPT_DEBUG_TELNET)
        !          1140:                        lprintf(LOG_DEBUG,"Node %d sending telnet cmd: %s %s"
        !          1141:                                ,cfg.node_num
        !          1142:                                ,telnet_cmd_desc(cmd)
        !          1143:                                ,telnet_opt_desc(opt));
        !          1144:                sprintf(buf,"%c%c%c",TELNET_IAC,cmd,opt);
        !          1145:                putcom(buf,3);
        !          1146:        }
        !          1147: }
        !          1148: 
        !          1149: void sbbs_t::request_telnet_opt(uchar cmd, uchar opt)
        !          1150: {
        !          1151:        if(cmd==TELNET_DO || cmd==TELNET_DONT) {        /* remote option */
        !          1152:                if(telnet_remote_option[opt]==telnet_opt_ack(cmd))
        !          1153:                        return; /* already set in this mode, do nothing */
        !          1154:                telnet_remote_option[opt]=telnet_opt_ack(cmd);
        !          1155:        } else {        /* local option */
        !          1156:                if(telnet_local_option[opt]==telnet_opt_ack(cmd))
        !          1157:                        return; /* already set in this mode, do nothing */
        !          1158:                telnet_local_option[opt]=telnet_opt_ack(cmd);
        !          1159:        }
        !          1160:        send_telnet_cmd(cmd,opt);
        !          1161: }
        !          1162: 
1.1       root     1163: void input_thread(void *arg)
                   1164: {
                   1165:        BYTE            inbuf[4000];
                   1166:        BYTE            telbuf[sizeof(inbuf)];
                   1167:     BYTE               *wrbuf;
                   1168:     int                        i,rd,wr,avail;
                   1169:        ulong           total_recv=0;
1.1.1.2 ! root     1170:        ulong           total_pkts=0;
1.1       root     1171:        fd_set          socket_set;
                   1172:        sbbs_t*         sbbs = (sbbs_t*) arg;
                   1173:        struct timeval  tv;
1.1.1.2 ! root     1174:        SOCKET          high_socket;
        !          1175:        SOCKET          sock;
1.1       root     1176: 
1.1.1.2 ! root     1177:        thread_up(TRUE /* setuid */);
1.1       root     1178: 
1.1.1.2 ! root     1179: #ifdef _DEBUG
        !          1180:        lprintf(LOG_DEBUG,"Node %d input thread started",sbbs->cfg.node_num);
        !          1181: #endif
1.1       root     1182: 
                   1183:        pthread_mutex_init(&sbbs->input_thread_mutex,NULL);
                   1184:     sbbs->input_thread_running = true;
                   1185:        sbbs->console|=CON_R_INPUT;
                   1186: 
1.1.1.2 ! root     1187:        while(sbbs->online && sbbs->client_socket!=INVALID_SOCKET
        !          1188:                && node_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET) {
1.1       root     1189: 
1.1.1.2 ! root     1190:                if(pthread_mutex_lock(&sbbs->input_thread_mutex)!=0)
        !          1191:                        sbbs->errormsg(WHERE,ERR_LOCK,"input_thread_mutex",0);
1.1       root     1192: 
                   1193:                FD_ZERO(&socket_set);
                   1194:                FD_SET(sbbs->client_socket,&socket_set);
1.1.1.2 ! root     1195:                high_socket=sbbs->client_socket;
        !          1196: #ifdef __unix__
        !          1197:                if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET)  {
        !          1198:                        FD_SET(uspy_socket[sbbs->cfg.node_num-1],&socket_set);
        !          1199:                        if(uspy_socket[sbbs->cfg.node_num-1] > high_socket)
        !          1200:                                high_socket=uspy_socket[sbbs->cfg.node_num-1];
        !          1201:                }
        !          1202: #endif
        !          1203: 
1.1       root     1204:                tv.tv_sec=1;
                   1205:                tv.tv_usec=0;
                   1206: 
1.1.1.2 ! root     1207:                if((i=select(high_socket+1,&socket_set,NULL,NULL,&tv))<1) {
        !          1208:                        if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0)
        !          1209:                                sbbs->errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0);
1.1       root     1210:                        if(i==0) {
1.1.1.2 ! root     1211:                                YIELD();        /* This kludge is necessary on some Linux distros */
        !          1212:                                continue;       /* to allow other threads to lock the input_thread_mutex */
        !          1213:                        }
        !          1214: 
        !          1215:                        if(sbbs->client_socket==INVALID_SOCKET)
        !          1216:                                break;
        !          1217: 
        !          1218:                        if(FD_ISSET(sbbs->client_socket,&socket_set))  {
        !          1219:                        if(ERROR_VALUE == ENOTSOCK)
        !          1220:                    lprintf(LOG_NOTICE,"Node %d socket closed by peer on input->select", sbbs->cfg.node_num);
        !          1221:                                else if(ERROR_VALUE==ESHUTDOWN)
        !          1222:                                        lprintf(LOG_NOTICE,"Node %d socket shutdown on input->select", sbbs->cfg.node_num);
        !          1223:                                else if(ERROR_VALUE==EINTR)
        !          1224:                                        lprintf(LOG_NOTICE,"Node %d input thread interrupted",sbbs->cfg.node_num);
        !          1225:                    else if(ERROR_VALUE==ECONNRESET) 
        !          1226:                                        lprintf(LOG_NOTICE,"Node %d connection reset by peer on input->select", sbbs->cfg.node_num);
        !          1227:                    else if(ERROR_VALUE==ECONNABORTED) 
        !          1228:                                        lprintf(LOG_NOTICE,"Node %d connection aborted by peer on input->select", sbbs->cfg.node_num);
        !          1229:                                else
        !          1230:                                        lprintf(LOG_WARNING,"Node %d !ERROR %d input->select socket %d"
        !          1231:                                ,sbbs->cfg.node_num, ERROR_VALUE, sbbs->client_socket);
        !          1232:                                break;
        !          1233:                        }
        !          1234: #ifdef __unix__
        !          1235:                        else if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET && 
        !          1236:                                        FD_ISSET(uspy_socket[sbbs->cfg.node_num-1],&socket_set))  {
        !          1237:                                if(ERROR_VALUE != EAGAIN)  {
        !          1238:                                        lprintf(LOG_ERR,"Node %d !ERROR %d on local spy socket %d input->select"
        !          1239:                                                , sbbs->cfg.node_num, errno, uspy_socket[sbbs->cfg.node_num-1]);
        !          1240:                                        close_socket(uspy_socket[sbbs->cfg.node_num-1]);
        !          1241:                                        uspy_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET;
        !          1242:                                }
1.1       root     1243:                                continue;
                   1244:                        }
1.1.1.2 ! root     1245: #endif
        !          1246:                }
1.1       root     1247: 
1.1.1.2 ! root     1248:                if(sbbs->client_socket==INVALID_SOCKET)
        !          1249:                        break;
        !          1250: 
        !          1251:                if(FD_ISSET(sbbs->client_socket,&socket_set))
        !          1252:                        sock=sbbs->client_socket;
        !          1253: #ifdef __unix__
        !          1254:                else if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET
        !          1255:                                && FD_ISSET(uspy_socket[sbbs->cfg.node_num-1],&socket_set))  {
        !          1256:                        if(!socket_check(uspy_socket[sbbs->cfg.node_num-1],NULL,NULL,0)) {
        !          1257:                                close_socket(uspy_socket[sbbs->cfg.node_num-1]);
        !          1258:                                lprintf(LOG_NOTICE,"Closing local spy socket: %d",uspy_socket[sbbs->cfg.node_num-1]);
        !          1259:                                uspy_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET;
        !          1260:                                continue;
        !          1261:                        }
        !          1262:                        sock=uspy_socket[sbbs->cfg.node_num-1];
        !          1263:                }
        !          1264: #endif
        !          1265:                else
        !          1266:                        continue;
        !          1267: 
        !          1268:                if(sbbs->client_socket==INVALID_SOCKET) {
        !          1269:                        if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0)
        !          1270:                                sbbs->errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0);
1.1       root     1271:                        break;
                   1272:                }
                   1273: 
                   1274:        rd=RingBufFree(&sbbs->inbuf);
                   1275: 
                   1276:                if(!rd) { // input buffer full
1.1.1.2 ! root     1277:                        lprintf(LOG_WARNING,"Node %d !WARNING input buffer full", sbbs->cfg.node_num);
1.1       root     1278:                // wait up to 5 seconds to empty (1 byte min)
                   1279:                        time_t start=time(NULL);
                   1280:             while((rd=RingBufFree(&sbbs->inbuf))==0) {
                   1281:                if(time(NULL)-start>=5) {
                   1282:                        rd=1;
                   1283:                        break;
                   1284:                 }
1.1.1.2 ! root     1285:                 YIELD();
1.1       root     1286:             }
                   1287:                }
                   1288:                
                   1289:            if(rd > (int)sizeof(inbuf))
                   1290:                rd=sizeof(inbuf);
                   1291: 
1.1.1.2 ! root     1292:        rd = recv(sock, (char*)inbuf, rd, 0);
1.1       root     1293: 
1.1.1.2 ! root     1294:                if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0)
        !          1295:                        sbbs->errormsg(WHERE,ERR_UNLOCK,"input_thread_mutex",0);
1.1       root     1296: 
                   1297:                if(rd == SOCKET_ERROR)
1.1.1.2 ! root     1298:                {
        !          1299: #ifdef __unix__
        !          1300:                        if(sock==sbbs->client_socket)  {
        !          1301: #endif
        !          1302:                        if(ERROR_VALUE == ENOTSOCK)
        !          1303:                    lprintf(LOG_NOTICE,"Node %d socket closed by peer on receive", sbbs->cfg.node_num);
        !          1304:                    else if(ERROR_VALUE==ECONNRESET) 
        !          1305:                                        lprintf(LOG_NOTICE,"Node %d connection reset by peer on receive", sbbs->cfg.node_num);
        !          1306:                                else if(ERROR_VALUE==ESHUTDOWN)
        !          1307:                                        lprintf(LOG_NOTICE,"Node %d socket shutdown on receive", sbbs->cfg.node_num);
        !          1308:                    else if(ERROR_VALUE==ECONNABORTED) 
        !          1309:                                        lprintf(LOG_NOTICE,"Node %d connection aborted by peer on receive", sbbs->cfg.node_num);
        !          1310:                                else
        !          1311:                                        lprintf(LOG_WARNING,"Node %d !ERROR %d receiving from socket %d"
        !          1312:                                ,sbbs->cfg.node_num, ERROR_VALUE, sock);
        !          1313:                                break;
        !          1314: #ifdef __unix__
        !          1315:                        } else  {
        !          1316:                                if(ERROR_VALUE != EAGAIN)  {
        !          1317:                                        lprintf(LOG_ERR,"Node %d !ERROR %d on local spy socket %d receive"
        !          1318:                                                , sbbs->cfg.node_num, errno, sock);
        !          1319:                                        close_socket(uspy_socket[sbbs->cfg.node_num-1]);
        !          1320:                                        uspy_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET;
        !          1321:                                }
        !          1322:                                continue;
        !          1323:                        }
        !          1324: #endif
1.1       root     1325:                }
                   1326: 
1.1.1.2 ! root     1327:                if(rd == 0 && sock==sbbs->client_socket)
1.1       root     1328:                {
1.1.1.2 ! root     1329:                        lprintf(LOG_NOTICE,"Node %d disconnected", sbbs->cfg.node_num);
1.1       root     1330:                        break;
                   1331:                }
                   1332: 
                   1333:                total_recv+=rd;
1.1.1.2 ! root     1334:                total_pkts++;
1.1       root     1335: 
                   1336:         // telbuf and wr are modified to reflect telnet escaped data
1.1.1.2 ! root     1337:                wr=rd;
        !          1338: #ifdef __unix__
        !          1339:                if(sock!=sbbs->client_socket)
        !          1340:                        wrbuf=inbuf;
        !          1341:                else
        !          1342: #endif
        !          1343:                if(sbbs->telnet_mode&TELNET_MODE_OFF)
        !          1344:                        wrbuf=inbuf;
        !          1345:                else
        !          1346:                        wrbuf=telnet_interpret(sbbs, inbuf, rd, telbuf, wr);
1.1       root     1347:                if(wr > (int)sizeof(telbuf)) 
1.1.1.2 ! root     1348:                        lprintf(LOG_ERR,"!TELBUF OVERFLOW (%d>%d)",wr,sizeof(telbuf));
        !          1349: 
        !          1350:                /* First level Ctrl-C checking */
        !          1351:                if(!(sbbs->cfg.ctrlkey_passthru&(1<<CTRL_C))
        !          1352:                        && sbbs->rio_abortable 
        !          1353:                        && !(sbbs->telnet_mode&TELNET_MODE_GATE)
        !          1354:                        && sbbs->telnet_remote_option[TELNET_BINARY_TX]!=TELNET_WILL
        !          1355:                        && memchr(wrbuf, CTRL_C, wr)) { 
        !          1356:                        if(RingBufFull(&sbbs->inbuf))
        !          1357:                        lprintf(LOG_DEBUG,"Node %d Ctrl-C hit with %lu bytes in input buffer"
        !          1358:                                        ,sbbs->cfg.node_num,RingBufFull(&sbbs->inbuf));
        !          1359:                        if(RingBufFull(&sbbs->outbuf))
        !          1360:                        lprintf(LOG_DEBUG,"Node %d Ctrl-C hit with %lu bytes in output buffer"
        !          1361:                                        ,sbbs->cfg.node_num,RingBufFull(&sbbs->outbuf));
        !          1362:                        sbbs->sys_status|=SS_ABORT;
        !          1363:                        RingBufReInit(&sbbs->inbuf);    /* Purge input buffer */
        !          1364:                RingBufReInit(&sbbs->outbuf);   /* Purge output buffer */
        !          1365:                        sem_post(&sbbs->inbuf.sem);
        !          1366:                        continue;       // Ignore the entire buffer
        !          1367:                }
1.1       root     1368: 
                   1369:                avail=RingBufFree(&sbbs->inbuf);
                   1370: 
                   1371:         if(avail<wr)
1.1.1.2 ! root     1372:                        lprintf(LOG_ERR,"!INPUT BUFFER FULL (%d free)", avail);
1.1       root     1373:         else
                   1374:                        RingBufWrite(&sbbs->inbuf, wrbuf, wr);
                   1375: //             if(wr>100)
                   1376: //                     mswait(500);    // Throttle sender
                   1377:        }
1.1.1.2 ! root     1378:        sbbs->online=0;
        !          1379:        sbbs->sys_status|=SS_ABORT;     /* as though Ctrl-C were hit */
1.1       root     1380: 
                   1381:     sbbs->input_thread_running = false;
1.1.1.2 ! root     1382:        if(node_socket[sbbs->cfg.node_num-1]==INVALID_SOCKET)   // Shutdown locally
        !          1383:                sbbs->terminated = true;        // Signal JS to stop execution
1.1       root     1384: 
                   1385:        pthread_mutex_destroy(&sbbs->input_thread_mutex);
                   1386: 
                   1387:        thread_down();
1.1.1.2 ! root     1388:        lprintf(LOG_DEBUG,"Node %d input thread terminated (received %lu bytes in %lu blocks)"
        !          1389:                ,sbbs->cfg.node_num, total_recv, total_pkts);
1.1       root     1390: }
                   1391: 
                   1392: void output_thread(void* arg)
                   1393: {
                   1394:        char            node[128];
1.1.1.2 ! root     1395:        char            stats[128];
1.1       root     1396:     BYTE               buf[IO_THREAD_BUF_SIZE];
                   1397:        int                     i;
                   1398:     ulong              avail;
                   1399:        ulong           total_sent=0;
1.1.1.2 ! root     1400:        ulong           total_pkts=0;
        !          1401:        ulong           short_sends=0;
1.1       root     1402:     ulong              bufbot=0;
                   1403:     ulong              buftop=0;
                   1404:        sbbs_t*         sbbs = (sbbs_t*) arg;
1.1.1.2 ! root     1405:        fd_set          socket_set;
        !          1406:        struct timeval tv;
1.1       root     1407: 
1.1.1.2 ! root     1408:        thread_up(TRUE /* setuid */);
1.1       root     1409: 
                   1410:     if(sbbs->cfg.node_num)
                   1411:        sprintf(node,"Node %d",sbbs->cfg.node_num);
                   1412:     else
                   1413:        strcpy(node,sbbs->client_name);
1.1.1.2 ! root     1414: #ifdef _DEBUG
        !          1415:        lprintf(LOG_DEBUG,"%s output thread started",node);
        !          1416: #endif
1.1       root     1417: 
                   1418:     sbbs->output_thread_running = true;
                   1419:        sbbs->console|=CON_R_ECHO;
                   1420: 
1.1.1.2 ! root     1421:        while(sbbs->client_socket!=INVALID_SOCKET && !terminate_server) {
        !          1422: 
1.1       root     1423:        if(bufbot==buftop)
                   1424:                avail=RingBufFull(&sbbs->outbuf);
                   1425:         else
                   1426:                avail=buftop-bufbot;
                   1427: 
                   1428:                if(!avail) {
1.1.1.2 ! root     1429:                        sem_wait(&sbbs->outbuf.sem);
        !          1430:                        if(sbbs->outbuf.highwater_mark)
        !          1431:                                sem_trywait_block(&sbbs->outbuf.highwater_sem,startup->outbuf_drain_timeout);
        !          1432:                        continue; 
        !          1433:                }
        !          1434: 
        !          1435:                /* Check socket for writability (using select) */
        !          1436:                tv.tv_sec=0;
        !          1437:                tv.tv_usec=1000;
        !          1438: 
        !          1439:                FD_ZERO(&socket_set);
        !          1440:                FD_SET(sbbs->client_socket,&socket_set);
        !          1441: 
        !          1442:                i=select(sbbs->client_socket+1,NULL,&socket_set,NULL,&tv);
        !          1443:                if(i==SOCKET_ERROR) {
        !          1444:                        lprintf(LOG_ERR,"!%s: ERROR %d selecting socket %u for send"
        !          1445:                                ,node,ERROR_VALUE,sbbs->client_socket);
        !          1446:                        if(sbbs->cfg.node_num)  /* Only break if node output (not server) */
        !          1447:                                break;
        !          1448:                        RingBufReInit(&sbbs->outbuf);   /* Flush output buffer */
        !          1449:                        continue;
        !          1450:                }
        !          1451:                if(i<1) {
        !          1452:                        continue;
        !          1453:                }
1.1       root     1454: 
                   1455:         if(bufbot==buftop) { // linear buf empty, read from ring buf
                   1456:             if(avail>sizeof(buf)) {
1.1.1.2 ! root     1457:                 lprintf(LOG_WARNING,"!%s: Insufficient linear output buffer (%lu > %lu)"
        !          1458:                                        ,node, avail, sizeof(buf));
1.1       root     1459:                 avail=sizeof(buf);
                   1460:             }
                   1461:             buftop=RingBufRead(&sbbs->outbuf, buf, avail);
                   1462:             bufbot=0;
                   1463:         }
1.1.1.2 ! root     1464:                i=sendsocket(sbbs->client_socket, (char*)buf+bufbot, buftop-bufbot);
        !          1465:                if(i==SOCKET_ERROR) {
1.1       root     1466:                if(ERROR_VALUE == ENOTSOCK)
1.1.1.2 ! root     1467:                 lprintf(LOG_NOTICE,"%s client socket closed on send", node);
1.1       root     1468:             else if(ERROR_VALUE==ECONNRESET) 
1.1.1.2 ! root     1469:                                lprintf(LOG_NOTICE,"%s connection reset by peer on send", node);
1.1       root     1470:             else if(ERROR_VALUE==ECONNABORTED) 
1.1.1.2 ! root     1471:                                lprintf(LOG_NOTICE,"%s connection aborted by peer on send", node);
1.1       root     1472:                        else
1.1.1.2 ! root     1473:                                lprintf(LOG_WARNING,"!%s: ERROR %d sending on socket %d"
1.1       root     1474:                        ,node, ERROR_VALUE, sbbs->client_socket);
                   1475:                        sbbs->online=0;
                   1476:                        /* was break; on 4/7/00 */
                   1477:                        i=buftop-bufbot;        // Pretend we sent it all
                   1478:                }
                   1479: 
1.1.1.2 ! root     1480:                if(sbbs->cfg.node_num>0 && !(sbbs->sys_status&SS_FILEXFER)) {
1.1       root     1481:                        /* Spy on the user locally */
                   1482:                        if(startup->node_spybuf!=NULL 
1.1.1.2 ! root     1483:                                && startup->node_spybuf[sbbs->cfg.node_num-1]!=NULL) {
1.1       root     1484:                                RingBufWrite(startup->node_spybuf[sbbs->cfg.node_num-1],buf+bufbot,i);
1.1.1.2 ! root     1485:                                /* Signal spy output semaphore? */
        !          1486:                                if(startup->node_spysem!=NULL 
        !          1487:                                        && startup->node_spysem[sbbs->cfg.node_num-1]!=NULL)
        !          1488:                                        sem_post(startup->node_spysem[sbbs->cfg.node_num-1]);
        !          1489:                        }
1.1       root     1490:                        /* Spy on the user remotely */
                   1491:                        if(spy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET) 
1.1.1.2 ! root     1492:                                sendsocket(spy_socket[sbbs->cfg.node_num-1],(char*)buf+bufbot,i);
        !          1493: #ifdef __unix__
        !          1494:                        if(uspy_socket[sbbs->cfg.node_num-1]!=INVALID_SOCKET)
        !          1495:                                sendsocket(uspy_socket[sbbs->cfg.node_num-1],(char*)buf+bufbot,i);
        !          1496: #endif
1.1       root     1497:                }
                   1498: 
1.1.1.2 ! root     1499:                if(i!=(int)(buftop-bufbot)) {
        !          1500:                        lprintf(LOG_WARNING,"!%s: Short socket send (%u instead of %u)"
        !          1501:                                ,node, i ,buftop-bufbot);
        !          1502:                        short_sends++;
        !          1503:                }
1.1       root     1504:                bufbot+=i;
                   1505:                total_sent+=i;
1.1.1.2 ! root     1506:                total_pkts++;
1.1       root     1507:     }
                   1508: 
                   1509:        sbbs->spymsg("Disconnected");
                   1510: 
                   1511:     sbbs->output_thread_running = false;
                   1512: 
1.1.1.2 ! root     1513:        if(total_sent)
        !          1514:                sprintf(stats,"(sent %lu bytes in %lu blocks, %lu average, %lu short)"
        !          1515:                        ,total_sent, total_pkts, total_sent/total_pkts, short_sends);
        !          1516:        else
        !          1517:                stats[0]=0;
1.1       root     1518: 
                   1519:        thread_down();
1.1.1.2 ! root     1520:        lprintf(LOG_DEBUG,"%s output thread terminated %s", node, stats);
1.1       root     1521: }
                   1522: 
                   1523: void event_thread(void* arg)
                   1524: {
1.1.1.2 ! root     1525:        char            str[MAX_PATH+1];
        !          1526:        char            bat_list[MAX_PATH+1];
        !          1527:        char            semfile[MAX_PATH+1];
1.1       root     1528:        int                     i,j,k;
                   1529:        int                     file;
                   1530:        int                     offset;
1.1.1.2 ! root     1531:        bool            check_semaphores;
        !          1532:        bool            packed_rep;
1.1       root     1533:        ulong           l;
                   1534:        time_t          now;
1.1.1.2 ! root     1535:        time_t          start;
        !          1536:        time_t          lastsemchk=0;
        !          1537:        time_t          lastnodechk=0;
1.1       root     1538:        time_t          lastprepack=0;
                   1539:        node_t          node;
                   1540:        glob_t          g;
                   1541:        sbbs_t*         sbbs = (sbbs_t*) arg;
1.1.1.2 ! root     1542:        struct tm       now_tm;
        !          1543:        struct tm       tm;
1.1       root     1544: 
1.1.1.2 ! root     1545:        eprintf(LOG_DEBUG,"BBS Events thread started");
1.1       root     1546: 
                   1547:        sbbs->event_thread_running = true;
                   1548: 
1.1.1.2 ! root     1549:        srand(time(NULL));      /* Seed random number generator */
        !          1550:        sbbs_random(10);        /* Throw away first number */
1.1       root     1551: 
1.1.1.2 ! root     1552:        thread_up(TRUE /* setuid */);
1.1       root     1553: 
1.1.1.2 ! root     1554: #ifdef JAVASCRIPT
        !          1555:        if(!(startup->options&BBS_OPT_NO_JAVASCRIPT)) {
        !          1556:                if(!sbbs->js_init())    /* This must be done in the context of the node thread */
        !          1557:                        lprintf(LOG_ERR,"!JavaScript Initialization FAILURE");
        !          1558:        }
        !          1559: #endif
1.1       root     1560: 
1.1.1.2 ! root     1561:        // Read TIME.DAB
        !          1562:        sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
        !          1563:        if((file=sbbs->nopen(str,O_RDWR|O_CREAT))==-1)
        !          1564:                sbbs->errormsg(WHERE,ERR_OPEN,str,0);
        !          1565:        else {
        !          1566:                for(i=0;i<sbbs->cfg.total_events;i++) {
        !          1567:                        sbbs->cfg.event[i]->last=0;
        !          1568:                        if(filelength(file)<(long)(sizeof(time_t)*(i+1))) {
        !          1569:                                eprintf(LOG_WARNING,"Initializing last run time for event: %s"
        !          1570:                                        ,sbbs->cfg.event[i]->code);
        !          1571:                                write(file,&sbbs->cfg.event[i]->last,sizeof(time_t));
        !          1572:                        } else {
        !          1573:                                if(read(file,&sbbs->cfg.event[i]->last,sizeof(time_t))!=sizeof(time_t))
        !          1574:                                        sbbs->errormsg(WHERE,ERR_READ,str,sizeof(time_t));
1.1       root     1575:                        }
1.1.1.2 ! root     1576:                        /* Event always runs after initialization? */
        !          1577:                        if(sbbs->cfg.event[i]->misc&EVENT_INIT)
        !          1578:                                sbbs->cfg.event[i]->last=-1;
        !          1579:                }
        !          1580:                lastprepack=0;
        !          1581:                read(file,&lastprepack,sizeof(time_t)); /* expected to fail first time */
        !          1582:                close(file);
        !          1583:        }
1.1       root     1584: 
1.1.1.2 ! root     1585:        // Read QNET.DAB
        !          1586:        sprintf(str,"%sqnet.dab",sbbs->cfg.ctrl_dir);
        !          1587:        if((file=sbbs->nopen(str,O_RDWR|O_CREAT))==-1)
        !          1588:                sbbs->errormsg(WHERE,ERR_OPEN,str,0);
        !          1589:        else {
        !          1590:                for(i=0;i<sbbs->cfg.total_qhubs;i++) {
        !          1591:                        sbbs->cfg.qhub[i]->last=0;
        !          1592:                        if(filelength(file)<(long)(sizeof(time_t)*(i+1))) {
        !          1593:                                eprintf(LOG_WARNING,"Initializing last call-out time for QWKnet hub: %s"
        !          1594:                                        ,sbbs->cfg.qhub[i]->id);
        !          1595:                                write(file,&sbbs->cfg.qhub[i]->last,sizeof(time_t));
        !          1596:                        } else {
        !          1597:                                if(read(file,&sbbs->cfg.qhub[i]->last,sizeof(time_t))!=sizeof(time_t))
        !          1598:                                        sbbs->errormsg(WHERE,ERR_READ,str,sizeof(time_t));
1.1       root     1599:                        }
1.1.1.2 ! root     1600:                }
        !          1601:                close(file);
        !          1602:        }
1.1       root     1603: 
1.1.1.2 ! root     1604:        // Read PNET.DAB
        !          1605:        sprintf(str,"%spnet.dab",sbbs->cfg.ctrl_dir);
        !          1606:        if((file=sbbs->nopen(str,O_RDWR|O_CREAT))==-1)
        !          1607:                sbbs->errormsg(WHERE,ERR_OPEN,str,0);
        !          1608:        else {
        !          1609:                for(i=0;i<sbbs->cfg.total_phubs;i++) {
        !          1610:                        sbbs->cfg.phub[i]->last=0;
        !          1611:                        if(filelength(file)<(long)(sizeof(time_t)*(i+1)))
        !          1612:                                write(file,&sbbs->cfg.phub[i]->last,sizeof(time_t));
        !          1613:                        else
        !          1614:                                read(file,&sbbs->cfg.phub[i]->last,sizeof(time_t)); 
        !          1615:                }
        !          1616:                close(file);
        !          1617:        }
1.1       root     1618: 
1.1.1.2 ! root     1619:        while(!sbbs->terminated && !terminate_server) {
        !          1620: 
        !          1621:                if(startup->options&BBS_OPT_NO_EVENTS) {
        !          1622:                        SLEEP(1000);
        !          1623:                        continue;
1.1       root     1624:                }
                   1625: 
                   1626:                now=time(NULL);
1.1.1.2 ! root     1627:                localtime_r(&now,&now_tm);
        !          1628: 
        !          1629:                if(now-lastsemchk>=sbbs->cfg.node_sem_check) {
        !          1630:                        check_semaphores=true;
        !          1631:                        lastsemchk=now;
        !          1632:                } else
        !          1633:                        check_semaphores=false;
        !          1634: 
        !          1635:                sbbs->online=0; /* reset this from ON_LOCAL */
1.1       root     1636: 
                   1637:                /* QWK events */
1.1.1.2 ! root     1638:                if(check_semaphores && !(startup->options&BBS_OPT_NO_QWK_EVENTS)) {
1.1       root     1639:                        /* Import any REP files that have magically appeared (via FTP perhaps) */
                   1640:                        sprintf(str,"%sfile/",sbbs->cfg.data_dir);
                   1641:                        offset=strlen(str);
                   1642:                        strcat(str,"*.rep");
                   1643:                        glob(str,0,NULL,&g);
                   1644:                        for(i=0;i<(int)g.gl_pathc;i++) {
                   1645:                                sbbs->useron.number=atoi(g.gl_pathv[i]+offset);
                   1646:                                getuserdat(&sbbs->cfg,&sbbs->useron);
                   1647:                                if(sbbs->useron.number && flength(g.gl_pathv[i])>0) {
1.1.1.2 ! root     1648:                                        sprintf(semfile,"%s.lock",g.gl_pathv[i]);
        !          1649:                                        if(!fmutex(semfile,startup->host_name))
        !          1650:                                                continue;
1.1       root     1651:                                        sbbs->online=ON_LOCAL;
1.1.1.2 ! root     1652:                                        eprintf(LOG_INFO,"Un-packing QWK Reply packet from %s",sbbs->useron.alias);
1.1       root     1653:                                        sbbs->getusrsubs();
                   1654:                                        sbbs->unpack_rep(g.gl_pathv[i]);
1.1.1.2 ! root     1655:                                        sbbs->batch_create_list();      /* FREQs? */
        !          1656:                                        sbbs->batdn_total=0;
        !          1657:                                        
1.1       root     1658:                                        /* putuserdat? */
                   1659:                                        remove(g.gl_pathv[i]);
1.1.1.2 ! root     1660:                                        remove(semfile);
1.1       root     1661:                                }
                   1662:                        }
                   1663:                        globfree(&g);
                   1664: 
                   1665:                        /* Create any QWK files that have magically appeared (via FTP perhaps) */
                   1666:                        sprintf(str,"%spack*.now",sbbs->cfg.data_dir);
                   1667:                        offset=strlen(sbbs->cfg.data_dir)+4;
                   1668:                        glob(str,0,NULL,&g);
                   1669:                        for(i=0;i<(int)g.gl_pathc;i++) {
                   1670:                                sbbs->useron.number=atoi(g.gl_pathv[i]+offset);
1.1.1.2 ! root     1671:                                sprintf(semfile,"%spack%04u.lock",sbbs->cfg.data_dir,sbbs->useron.number);
        !          1672:                                if(!fmutex(semfile,startup->host_name))
        !          1673:                                        continue;
1.1       root     1674:                                getuserdat(&sbbs->cfg,&sbbs->useron);
                   1675:                                if(sbbs->useron.number && !(sbbs->useron.misc&(DELETED|INACTIVE))) {
1.1.1.2 ! root     1676:                                        eprintf(LOG_INFO,"Packing QWK Message Packet for %s",sbbs->useron.alias);
1.1       root     1677:                                        sbbs->online=ON_LOCAL;
1.1.1.2 ! root     1678:                                        delfiles(sbbs->cfg.temp_dir,ALLFILES);
1.1       root     1679:                                        sbbs->getmsgptrs();
                   1680:                                        sbbs->getusrsubs();
                   1681:                                        sbbs->batdn_total=0;
1.1.1.2 ! root     1682: 
        !          1683:                                        sbbs->last_ns_time=sbbs->ns_time=sbbs->useron.ns_time;
        !          1684:                                        sprintf(bat_list,"%sfile/%04u.dwn",sbbs->cfg.data_dir,sbbs->useron.number);
        !          1685:                                        sbbs->batch_add_list(bat_list);
        !          1686: 
1.1       root     1687:                                        sprintf(str,"%sfile%c%04u.qwk"
1.1.1.2 ! root     1688:                                                ,sbbs->cfg.data_dir,PATH_DELIM,sbbs->useron.number);
        !          1689:                                        if(sbbs->pack_qwk(str,&l,true /* pre-pack/off-line */)) {
        !          1690:                                                eprintf(LOG_INFO,"Packing completed");
1.1       root     1691:                                                sbbs->qwk_success(l,0,1);
                   1692:                                                sbbs->putmsgptrs(); 
1.1.1.2 ! root     1693:                                                remove(bat_list);
1.1       root     1694:                                        } else
1.1.1.2 ! root     1695:                                                eprintf(LOG_INFO,"No packet created (no new messages)");
        !          1696:                                        delfiles(sbbs->cfg.temp_dir,ALLFILES);
1.1       root     1697:                                        sbbs->online=0;
                   1698:                                }
                   1699:                                remove(g.gl_pathv[i]);
1.1.1.2 ! root     1700:                                remove(semfile);
1.1       root     1701:                        }
                   1702:                        globfree(&g);
                   1703: 
                   1704:                        /* Create (pre-pack) QWK files for users configured as such */
                   1705:                        sprintf(semfile,"%sprepack.now",sbbs->cfg.data_dir);
                   1706:                        if(sbbs->cfg.preqwk_ar[0] 
1.1.1.2 ! root     1707:                                && (fexistcase(semfile) || (now-lastprepack)/60>(60*24))) {
1.1       root     1708:                                j=lastuser(&sbbs->cfg);
1.1.1.2 ! root     1709:                                eprintf(LOG_INFO,"Pre-packing QWK Message packets...");
1.1       root     1710:                                for(i=1;i<=j;i++) {
                   1711: 
                   1712:                                        sprintf(str,"%5u of %-5u",i,j);
1.1.1.2 ! root     1713:                                        //status(str);
1.1       root     1714:                                        sbbs->useron.number=i;
                   1715:                                        getuserdat(&sbbs->cfg,&sbbs->useron);
                   1716: 
                   1717:                                        if(sbbs->useron.number
                   1718:                                                && !(sbbs->useron.misc&(DELETED|INACTIVE))       /* Pre-QWK */
                   1719:                                                && sbbs->chk_ar(sbbs->cfg.preqwk_ar,&sbbs->useron)) { 
                   1720:                                                for(k=1;k<=sbbs->cfg.sys_nodes;k++) {
1.1.1.2 ! root     1721:                                                        if(sbbs->getnodedat(k,&node,0)!=0)
        !          1722:                                                                continue;
1.1       root     1723:                                                        if((node.status==NODE_INUSE || node.status==NODE_QUIET
                   1724:                                                                || node.status==NODE_LOGON) && node.useron==i)
                   1725:                                                                break; 
                   1726:                                                }
                   1727:                                                if(k<=sbbs->cfg.sys_nodes)      /* Don't pre-pack with user online */
                   1728:                                                        continue;
1.1.1.2 ! root     1729:                                                eprintf(LOG_INFO,"Pre-packing QWK for %s",sbbs->useron.alias);
1.1       root     1730:                                                sbbs->online=ON_LOCAL;
1.1.1.2 ! root     1731:                                                delfiles(sbbs->cfg.temp_dir,ALLFILES);
1.1       root     1732:                                                sbbs->getmsgptrs();
                   1733:                                                sbbs->getusrsubs();
                   1734:                                                sbbs->batdn_total=0;
                   1735:                                                sprintf(str,"%sfile%c%04u.qwk"
1.1.1.2 ! root     1736:                                                        ,sbbs->cfg.data_dir,PATH_DELIM,sbbs->useron.number);
        !          1737:                                                if(sbbs->pack_qwk(str,&l,true /* pre-pack */)) {
1.1       root     1738:                                                        sbbs->qwk_success(l,0,1);
                   1739:                                                        sbbs->putmsgptrs(); 
                   1740:                                                }
1.1.1.2 ! root     1741:                                                delfiles(sbbs->cfg.temp_dir,ALLFILES);
1.1       root     1742:                                                sbbs->online=0;
                   1743:                                        } 
                   1744:                                }
                   1745:                                lastprepack=now;
                   1746:                                sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
                   1747:                                if((file=sbbs->nopen(str,O_WRONLY))==-1) {
                   1748:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
1.1.1.2 ! root     1749:                                        break; 
        !          1750:                                }
1.1       root     1751:                                lseek(file,(long)sbbs->cfg.total_events*4L,SEEK_SET);
                   1752:                                write(file,&lastprepack,sizeof(time_t));
                   1753:                                close(file);
                   1754: 
                   1755:                                remove(semfile);
1.1.1.2 ! root     1756:                                //status(STATUS_WFC);
1.1       root     1757:                        }
                   1758:                }
                   1759: 
1.1.1.2 ! root     1760:                if(check_semaphores) {
        !          1761:                        /* Node Daily Events */
        !          1762:                        for(i=first_node;i<=last_node;i++) {
        !          1763:                                // Node Daily Event
        !          1764:                                node.status=NODE_INVALID_STATUS;
        !          1765:                                if(sbbs->getnodedat(i,&node,0)!=0)
        !          1766:                                        continue;
        !          1767:                                if(node.misc&NODE_EVENT && node.status==NODE_WFC) {
        !          1768:                                        sbbs->getnodedat(i,&node,1);
        !          1769:                                        node.status=NODE_EVENT_RUNNING;
        !          1770:                                        sbbs->putnodedat(i,&node);
        !          1771:                                        if(sbbs->cfg.node_daily[0]) {
        !          1772:                                                sbbs->cfg.node_num=i;
        !          1773:                                                strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[i-1]);
1.1       root     1774: 
1.1.1.2 ! root     1775:                                                eprintf(LOG_INFO,"Running node %d daily event",i);
        !          1776:                                                sbbs->online=ON_LOCAL;
        !          1777:                                                sbbs->logentry("!:","Run node daily event");
        !          1778:                                                sbbs->external(
        !          1779:                                                         sbbs->cmdstr(sbbs->cfg.node_daily,nulstr,nulstr,NULL)
        !          1780:                                                        ,EX_OFFLINE);
        !          1781:                                        }
        !          1782:                                        sbbs->getnodedat(i,&node,1);
        !          1783:                                        node.misc&=~NODE_EVENT;
        !          1784:                                        node.status=NODE_WFC;
        !          1785:                                        node.useron=0;
        !          1786:                                        sbbs->putnodedat(i,&node); 
        !          1787:                                }
1.1       root     1788:                        }
                   1789: 
1.1.1.2 ! root     1790:                        /* QWK Networking Call-out sempahores */
        !          1791:                        for(i=0;i<sbbs->cfg.total_qhubs;i++) {
        !          1792:                                if(sbbs->cfg.qhub[i]->node<first_node 
        !          1793:                                        || sbbs->cfg.qhub[i]->node>last_node)
        !          1794:                                        continue;
        !          1795:                                if(sbbs->cfg.qhub[i]->last==-1) // already signaled
        !          1796:                                        continue;
1.1       root     1797:                                sprintf(str,"%sqnet/%s.now",sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
1.1.1.2 ! root     1798:                                if(fexistcase(str)) {
        !          1799:                                        strcpy(str,sbbs->cfg.qhub[i]->id);
        !          1800:                                        eprintf(LOG_INFO,"Semaphore signaled for QWK Network Hub: %s",strupr(str));
1.1       root     1801:                                        sbbs->cfg.qhub[i]->last=-1; 
1.1.1.2 ! root     1802:                                }
1.1       root     1803:                        }
                   1804: 
1.1.1.2 ! root     1805:                        /* Timed Event sempahores */
        !          1806:                        for(i=0;i<sbbs->cfg.total_events;i++) {
        !          1807:                                if((sbbs->cfg.event[i]->node<first_node
        !          1808:                                        || sbbs->cfg.event[i]->node>last_node)
        !          1809:                                        && !(sbbs->cfg.event[i]->misc&EVENT_EXCL))
        !          1810:                                        continue;       // ignore non-exclusive events for other instances
        !          1811:                                if(sbbs->cfg.event[i]->misc&EVENT_DISABLED)
        !          1812:                                        continue;
        !          1813:                                if(sbbs->cfg.event[i]->last==-1) // already signaled
        !          1814:                                        continue;
1.1       root     1815:                                sprintf(str,"%s%s.now",sbbs->cfg.data_dir,sbbs->cfg.event[i]->code);
1.1.1.2 ! root     1816:                                if(fexistcase(str)) {
        !          1817:                                        strcpy(str,sbbs->cfg.event[i]->code);
        !          1818:                                        eprintf(LOG_INFO,"Semaphore signaled for Timed Event: %s",strupr(str));
1.1       root     1819:                                        sbbs->cfg.event[i]->last=-1; 
1.1.1.2 ! root     1820:                                }
1.1       root     1821:                        }
1.1.1.2 ! root     1822:                }
1.1       root     1823: 
                   1824:                /* QWK Networking Call-out Events */
                   1825:                for(i=0;i<sbbs->cfg.total_qhubs;i++) {
1.1.1.2 ! root     1826:                        if(sbbs->cfg.qhub[i]->node<first_node ||
        !          1827:                                sbbs->cfg.qhub[i]->node>last_node)
1.1       root     1828:                                continue;
                   1829: 
1.1.1.2 ! root     1830:                        if(check_semaphores) {
        !          1831:                                // See if any packets have come in
        !          1832:                                for(j=0;j<101;j++) {
        !          1833:                                        sprintf(str,"%s%s.q%c%c",sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id
        !          1834:                                                ,j>10 ? ((j-1)/10)+'0' : 'w'
        !          1835:                                                ,j ? ((j-1)%10)+'0' : 'k');
        !          1836:                                        if(fexistcase(str) && flength(str)>0) { /* silently ignore 0-byte QWK packets */
        !          1837:                                                delfiles(sbbs->cfg.temp_dir,ALLFILES);
        !          1838:                                                sbbs->online=ON_LOCAL;
        !          1839:                                                sbbs->console|=CON_L_ECHO;
        !          1840:                                                if(sbbs->unpack_qwk(str,i)==false) {
        !          1841:                                                        char newname[MAX_PATH+1];
        !          1842:                                                        sprintf(newname,"%s.%lx.bad",str,(long)now);
        !          1843:                                                        remove(newname);
        !          1844:                                                        if(rename(str,newname)==0) {
        !          1845:                                                                char logmsg[MAX_PATH*3];
        !          1846:                                                                sprintf(logmsg,"%s renamed to %s",str,newname);
        !          1847:                                                                sbbs->logline("Q!",logmsg);
        !          1848:                                                        }
1.1       root     1849:                                                }
1.1.1.2 ! root     1850:                                                sbbs->console&=~CON_L_ECHO;
        !          1851:                                                sbbs->online=0;
        !          1852:                                                remove(str);
        !          1853:                                        } 
        !          1854:                                }
1.1       root     1855:                        }
                   1856: 
1.1.1.2 ! root     1857:                        /* Qnet call out based on time */
        !          1858:                        if(localtime_r(&sbbs->cfg.qhub[i]->last,&tm)==NULL)
        !          1859:                                memset(&tm,0,sizeof(tm));
        !          1860:                        if((sbbs->cfg.qhub[i]->last==-1L                                        /* or frequency */
1.1       root     1861:                                || ((sbbs->cfg.qhub[i]->freq
                   1862:                                        && (now-sbbs->cfg.qhub[i]->last)/60>sbbs->cfg.qhub[i]->freq)
                   1863:                                        || (sbbs->cfg.qhub[i]->time
                   1864:                                                && (now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.qhub[i]->time
1.1.1.2 ! root     1865:                                                && (now_tm.tm_mday!=tm.tm_mday || now_tm.tm_mon!=tm.tm_mon)))
1.1       root     1866:                                                && sbbs->cfg.qhub[i]->days&(1<<now_tm.tm_wday))) {
                   1867:                                sprintf(str,"%sqnet/%s.now"
                   1868:                                        ,sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
1.1.1.2 ! root     1869:                                if(fexistcase(str))
        !          1870:                                        remove(str);                                    /* Remove semaphore file */
1.1       root     1871:                                sprintf(str,"%sqnet/%s.ptr"
                   1872:                                        ,sbbs->cfg.data_dir,sbbs->cfg.qhub[i]->id);
                   1873:                                file=sbbs->nopen(str,O_RDONLY);
                   1874:                                for(j=0;j<sbbs->cfg.qhub[i]->subs;j++) {
1.1.1.2 ! root     1875:                                        sbbs->subscan[sbbs->cfg.qhub[i]->sub[j]].ptr=0;
        !          1876:                                        if(file!=-1) {
        !          1877:                                                lseek(file,sbbs->cfg.sub[sbbs->cfg.qhub[i]->sub[j]]->ptridx*sizeof(long),SEEK_SET);
        !          1878:                                                read(file,&sbbs->subscan[sbbs->cfg.qhub[i]->sub[j]].ptr,sizeof(long)); 
        !          1879:                                        }
1.1       root     1880:                                }
                   1881:                                if(file!=-1)
                   1882:                                        close(file);
1.1.1.2 ! root     1883:                                sbbs->console|=CON_L_ECHO;
        !          1884:                                packed_rep=sbbs->pack_rep(i);
        !          1885:                                sbbs->console&=~CON_L_ECHO;
        !          1886:                                if(packed_rep) {
1.1       root     1887:                                        if((file=sbbs->nopen(str,O_WRONLY|O_CREAT))==-1)
                   1888:                                                sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT);
                   1889:                                        else {
                   1890:                                                for(j=l=0;j<sbbs->cfg.qhub[i]->subs;j++) {
                   1891:                                                        while(filelength(file)<
                   1892:                                                                sbbs->cfg.sub[sbbs->cfg.qhub[i]->sub[j]]->ptridx*4L)
                   1893:                                                                write(file,&l,4);               /* initialize ptrs to null */
1.1.1.2 ! root     1894:                                                        lseek(file
        !          1895:                                                                ,sbbs->cfg.sub[sbbs->cfg.qhub[i]->sub[j]]->ptridx*sizeof(long)
        !          1896:                                                                ,SEEK_SET);
        !          1897:                                                        write(file,&sbbs->subscan[sbbs->cfg.qhub[i]->sub[j]].ptr,sizeof(long)); 
        !          1898:                                                }
        !          1899:                                                close(file); 
        !          1900:                                        } 
        !          1901:                                }
        !          1902:                                delfiles(sbbs->cfg.temp_dir,ALLFILES);
1.1       root     1903: 
                   1904:                                sbbs->cfg.qhub[i]->last=time(NULL);
                   1905:                                sprintf(str,"%sqnet.dab",sbbs->cfg.ctrl_dir);
                   1906:                                if((file=sbbs->nopen(str,O_WRONLY))==-1) {
                   1907:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
                   1908:                                        break; 
                   1909:                                }
                   1910:                                lseek(file,sizeof(time_t)*i,SEEK_SET);
                   1911:                                write(file,&sbbs->cfg.qhub[i]->last,sizeof(time_t));
                   1912:                                close(file);
                   1913: 
                   1914:                                if(sbbs->cfg.qhub[i]->call[0]) {
                   1915:                                        sbbs->cfg.node_num=sbbs->cfg.qhub[i]->node;
1.1.1.2 ! root     1916:                                        if(sbbs->cfg.node_num<1) 
        !          1917:                                                sbbs->cfg.node_num=1;
1.1       root     1918:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[sbbs->cfg.node_num-1]);
1.1.1.2 ! root     1919:                                        eprintf(LOG_INFO,"QWK Network call-out: %s",sbbs->cfg.qhub[i]->id); 
        !          1920:                                        sbbs->online=ON_LOCAL;
1.1       root     1921:                                        sbbs->external(
                   1922:                                                 sbbs->cmdstr(sbbs->cfg.qhub[i]->call,nulstr,nulstr,NULL)
1.1.1.2 ! root     1923:                                                ,EX_OFFLINE|EX_SH);     /* sh for Unix perl scripts */
1.1       root     1924:                                }
                   1925:                        } 
                   1926:                }
                   1927: 
                   1928:                /* PostLink Networking Call-out Events */
                   1929:                for(i=0;i<sbbs->cfg.total_phubs;i++) {
1.1.1.2 ! root     1930:                        if(sbbs->cfg.phub[i]->node<first_node 
        !          1931:                                || sbbs->cfg.phub[i]->node>last_node)
1.1       root     1932:                                continue;
1.1.1.2 ! root     1933:                        /* PostLink call out based on time */
        !          1934:                        if(localtime_r(&sbbs->cfg.phub[i]->last,&tm)==NULL)
        !          1935:                                memset(&tm,0,sizeof(tm));
        !          1936:                        if(sbbs->cfg.phub[i]->last==-1
        !          1937:                                || (((sbbs->cfg.phub[i]->freq                                                           /* or frequency */
1.1       root     1938:                                        && (now-sbbs->cfg.phub[i]->last)/60>sbbs->cfg.phub[i]->freq)
                   1939:                                || (sbbs->cfg.phub[i]->time
                   1940:                                        && (now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.phub[i]->time
1.1.1.2 ! root     1941:                                && (now_tm.tm_mday!=tm.tm_mday || now_tm.tm_mon!=tm.tm_mon)))
        !          1942:                                && sbbs->cfg.phub[i]->days&(1<<now_tm.tm_wday))) {
1.1       root     1943: 
                   1944:                                sbbs->cfg.phub[i]->last=time(NULL);
                   1945:                                sprintf(str,"%spnet.dab",sbbs->cfg.ctrl_dir);
                   1946:                                if((file=sbbs->nopen(str,O_WRONLY))==-1) {
                   1947:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
                   1948:                                        break; 
                   1949:                                }
                   1950:                                lseek(file,sizeof(time_t)*i,SEEK_SET);
                   1951:                                write(file,&sbbs->cfg.phub[i]->last,sizeof(time_t));
                   1952:                                close(file);
                   1953: 
                   1954:                                if(sbbs->cfg.phub[i]->call[0]) {
1.1.1.2 ! root     1955:                                        sbbs->cfg.node_num=sbbs->cfg.phub[i]->node;
        !          1956:                                        if(sbbs->cfg.node_num<1) 
        !          1957:                                                sbbs->cfg.node_num=1;
1.1       root     1958:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[sbbs->cfg.node_num-1]);
1.1.1.2 ! root     1959:                                        eprintf(LOG_INFO,"PostLink Network call-out: %s",sbbs->cfg.phub[i]->name); 
        !          1960:                                        sbbs->online=ON_LOCAL;
1.1       root     1961:                                        sbbs->external(
                   1962:                                                 sbbs->cmdstr(sbbs->cfg.phub[i]->call,nulstr,nulstr,NULL)
1.1.1.2 ! root     1963:                                                ,EX_OFFLINE|EX_SH);     /* sh for Unix perl scripts */
1.1       root     1964:                                } 
                   1965:                        }
                   1966:                }
                   1967: 
                   1968:                /* Timed Events */
                   1969:                for(i=0;i<sbbs->cfg.total_events;i++) {
1.1.1.2 ! root     1970:                        if(!sbbs->cfg.event[i]->node 
        !          1971:                                || sbbs->cfg.event[i]->node>sbbs->cfg.sys_nodes)
        !          1972:                                continue;       // ignore events for invalid nodes
        !          1973: 
        !          1974:                        if(sbbs->cfg.event[i]->misc&EVENT_DISABLED)
1.1       root     1975:                                continue;
                   1976: 
1.1.1.2 ! root     1977:                        if((sbbs->cfg.event[i]->node<first_node
        !          1978:                                || sbbs->cfg.event[i]->node>last_node)
        !          1979:                                && !(sbbs->cfg.event[i]->misc&EVENT_EXCL))
        !          1980:                                continue;       // ignore non-exclusive events for other instances
        !          1981: 
        !          1982:                        if(localtime_r(&sbbs->cfg.event[i]->last,&tm)==NULL)
        !          1983:                                memset(&tm,0,sizeof(tm));
        !          1984:                        if(sbbs->cfg.event[i]->last==-1 ||
        !          1985:                                (((sbbs->cfg.event[i]->freq 
        !          1986:                                        && (now-sbbs->cfg.event[i]->last)/60>sbbs->cfg.event[i]->freq)
        !          1987:                                ||      (!sbbs->cfg.event[i]->freq 
        !          1988:                                        && (now_tm.tm_hour*60)+now_tm.tm_min>=sbbs->cfg.event[i]->time
        !          1989:                                && (now_tm.tm_mday!=tm.tm_mday || now_tm.tm_mon!=tm.tm_mon)))
        !          1990:                                && sbbs->cfg.event[i]->days&(1<<now_tm.tm_wday)
        !          1991:                                && (sbbs->cfg.event[i]->mdays==0 
        !          1992:                                        || sbbs->cfg.event[i]->mdays&(1<<now_tm.tm_mday)))) 
        !          1993:                        {
1.1       root     1994:                                if(sbbs->cfg.event[i]->misc&EVENT_EXCL) { /* exclusive event */
                   1995: 
1.1.1.2 ! root     1996:                                        if(sbbs->cfg.event[i]->node<first_node
        !          1997:                                                || sbbs->cfg.event[i]->node>last_node) {
        !          1998:                                                eprintf(LOG_INFO,"Waiting for node %d to run timed event: %s"
        !          1999:                                                        ,sbbs->cfg.event[i]->node,sbbs->cfg.event[i]->code);
        !          2000:                                                eprintf(LOG_DEBUG,"%s event last run: %s (0x%08lx)"
        !          2001:                                                        ,sbbs->cfg.event[i]->code
        !          2002:                                                        ,timestr(&sbbs->cfg, &sbbs->cfg.event[i]->last, str)
        !          2003:                                                        ,sbbs->cfg.event[i]->last);
1.1       root     2004:                                                lastnodechk=0;   /* really last event time check */
1.1.1.2 ! root     2005:                                                start=time(NULL);
1.1       root     2006:                                                while(!sbbs->terminated) {
                   2007:                                                        mswait(1000);
                   2008:                                                        now=time(NULL);
1.1.1.2 ! root     2009:                                                        if(now-start>10 && now-lastnodechk<10)
1.1       root     2010:                                                                continue;
1.1.1.2 ! root     2011:                                                        for(j=first_node;j<=last_node;j++) {
        !          2012:                                                                if(sbbs->getnodedat(j,&node,1)!=0)
        !          2013:                                                                        continue;
1.1       root     2014:                                                                if(node.status==NODE_WFC)
                   2015:                                                                        node.status=NODE_EVENT_LIMBO;
                   2016:                                                                node.aux=sbbs->cfg.event[i]->node;
                   2017:                                                                sbbs->putnodedat(j,&node);
                   2018:                                                        }
                   2019: 
                   2020:                                                        lastnodechk=now;
                   2021:                                                        sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
                   2022:                                                        if((file=sbbs->nopen(str,O_RDONLY))==-1) {
                   2023:                                                                sbbs->errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
                   2024:                                                                sbbs->cfg.event[i]->last=now;
1.1.1.2 ! root     2025:                                                                continue; 
        !          2026:                                                        }
1.1       root     2027:                                                        lseek(file,(long)i*4L,SEEK_SET);
                   2028:                                                        read(file,&sbbs->cfg.event[i]->last,sizeof(time_t));
                   2029:                                                        close(file);
                   2030:                                                        if(now-sbbs->cfg.event[i]->last<(60*60))        /* event is done */
1.1.1.2 ! root     2031:                                                                break; 
        !          2032:                                                        if(now-start>(90*60)) {
        !          2033:                                                                eprintf(LOG_WARNING,"!TIMEOUT waiting for event to complete");
        !          2034:                                                                break;
        !          2035:                                                        }
        !          2036:                                                }
1.1       root     2037:                                                sprintf(str,"%s%s.now",sbbs->cfg.data_dir,sbbs->cfg.event[i]->code);
1.1.1.2 ! root     2038:                                                if(fexistcase(str))
        !          2039:                                                        remove(str);
1.1       root     2040:                                                sbbs->cfg.event[i]->last=now;
                   2041:                                        } else {        // Exclusive event to run on a node under our control
1.1.1.2 ! root     2042:                                                eprintf(LOG_INFO,"Waiting for all nodes to become inactive before "
        !          2043:                                                        "running timed event: %s",sbbs->cfg.event[i]->code);
1.1       root     2044:                                                lastnodechk=0;
1.1.1.2 ! root     2045:                                                start=time(NULL);
1.1       root     2046:                                                while(!sbbs->terminated) {
                   2047:                                                        mswait(1000);
                   2048:                                                        now=time(NULL);
1.1.1.2 ! root     2049:                                                        if(now-start>10 && now-lastnodechk<10)
1.1       root     2050:                                                                continue;
                   2051:                                                        lastnodechk=now;
                   2052:                                                        // Check/change the status of the nodes that we're in control of
1.1.1.2 ! root     2053:                                                        for(j=first_node;j<=last_node;j++) {
        !          2054:                                                                if(sbbs->getnodedat(j,&node,1)!=0)
        !          2055:                                                                        continue;
1.1       root     2056:                                                                if(node.status==NODE_WFC) {
                   2057:                                                                        if(j==sbbs->cfg.event[i]->node)
                   2058:                                                                                node.status=NODE_EVENT_WAITING;
                   2059:                                                                        else
                   2060:                                                                                node.status=NODE_EVENT_LIMBO;
                   2061:                                                                        node.aux=sbbs->cfg.event[i]->node;
                   2062:                                                                }
                   2063:                                                                sbbs->putnodedat(j,&node);
                   2064:                                                        }
                   2065: 
                   2066:                                                        for(j=1;j<=sbbs->cfg.sys_nodes;j++) {
1.1.1.2 ! root     2067:                                                                if(sbbs->getnodedat(j,&node,0)!=0)
        !          2068:                                                                        continue;
1.1       root     2069:                                                                if(j==sbbs->cfg.event[i]->node) {
                   2070:                                                                        if(node.status!=NODE_EVENT_WAITING)
                   2071:                                                                                break;
                   2072:                                                                } else {
                   2073:                                                                        if(node.status!=NODE_OFFLINE
                   2074:                                                                                && node.status!=NODE_EVENT_LIMBO)
                   2075:                                                                                break; 
                   2076:                                                                }
                   2077:                                                        }
                   2078:                                                        if(j>sbbs->cfg.sys_nodes) /* all nodes either offline or in limbo */
                   2079:                                                                break;
1.1.1.2 ! root     2080:                                                        eprintf(LOG_DEBUG,"Waiting for node %d (status=%d)",j,node.status);
        !          2081:                                                        if(now-start>(90*60)) {
        !          2082:                                                                eprintf(LOG_WARNING,"!TIMEOUT waiting for node %d to become inactive",j);
        !          2083:                                                                break;
        !          2084:                                                        }
1.1       root     2085:                                                } 
                   2086:                                        } 
                   2087:                                }
1.1.1.2 ! root     2088: #if 0 // removed Jun-23-2002
1.1       root     2089:                                else {  /* non-exclusive */
                   2090:                                        sbbs->getnodedat(sbbs->cfg.event[i]->node,&node,0);
                   2091:                                        if(node.status!=NODE_WFC)
                   2092:                                                continue;
                   2093:                                }
1.1.1.2 ! root     2094: #endif
        !          2095:                                if(sbbs->cfg.event[i]->node<first_node 
        !          2096:                                        || sbbs->cfg.event[i]->node>last_node) {
        !          2097:                                        eprintf(LOG_NOTICE,"Changing node status for nodes %d through %d to WFC"
        !          2098:                                                ,first_node,last_node);
1.1       root     2099:                                        sbbs->cfg.event[i]->last=now;
1.1.1.2 ! root     2100:                                        for(j=first_node;j<=last_node;j++) {
        !          2101:                                                node.status=NODE_INVALID_STATUS;
        !          2102:                                                if(sbbs->getnodedat(j,&node,1)!=0)
        !          2103:                                                        continue;
1.1       root     2104:                                                node.status=NODE_WFC;
                   2105:                                                sbbs->putnodedat(j,&node);
                   2106:                                        }
                   2107:                                }
                   2108:                                else {
                   2109:                                        sbbs->cfg.node_num=sbbs->cfg.event[i]->node;
1.1.1.2 ! root     2110:                                        if(sbbs->cfg.node_num<1) 
        !          2111:                                                sbbs->cfg.node_num=1;
1.1       root     2112:                                        strcpy(sbbs->cfg.node_dir, sbbs->cfg.node_path[sbbs->cfg.node_num-1]);
                   2113:                                
                   2114:                                        sprintf(str,"%s%s.now",sbbs->cfg.data_dir,sbbs->cfg.event[i]->code);
1.1.1.2 ! root     2115:                                        if(fexistcase(str))
        !          2116:                                                remove(str);
1.1       root     2117:                                        if(sbbs->cfg.event[i]->misc&EVENT_EXCL) {
                   2118:                                                sbbs->getnodedat(sbbs->cfg.event[i]->node,&node,1);
                   2119:                                                node.status=NODE_EVENT_RUNNING;
                   2120:                                                sbbs->putnodedat(sbbs->cfg.event[i]->node,&node);
                   2121:                                        }
1.1.1.2 ! root     2122:                                        strcpy(str,sbbs->cfg.event[i]->code);
        !          2123:                                        eprintf(LOG_INFO,"Running timed event: %s",strupr(str));
        !          2124:                                        int ex_mode = EX_OFFLINE;
        !          2125:                                        if(!(sbbs->cfg.event[i]->misc&EVENT_EXCL)
        !          2126:                                                && sbbs->cfg.event[i]->misc&EX_BG)
        !          2127:                                                ex_mode |= EX_BG;
        !          2128:                                        if(sbbs->cfg.event[i]->misc&XTRN_SH)
        !          2129:                                                ex_mode |= EX_SH;
        !          2130:                                        ex_mode|=(sbbs->cfg.event[i]->misc&EX_NATIVE);
        !          2131:                                        sbbs->online=ON_LOCAL;
1.1       root     2132:                                        sbbs->external(
1.1.1.2 ! root     2133:                                                 sbbs->cmdstr(sbbs->cfg.event[i]->cmd,nulstr,sbbs->cfg.event[i]->dir,NULL)
        !          2134:                                                ,ex_mode
1.1       root     2135:                                                ,sbbs->cfg.event[i]->dir);
                   2136:                                        sbbs->cfg.event[i]->last=time(NULL);
                   2137:                                        sprintf(str,"%stime.dab",sbbs->cfg.ctrl_dir);
                   2138:                                        if((file=sbbs->nopen(str,O_WRONLY))==-1) {
                   2139:                                                sbbs->errormsg(WHERE,ERR_OPEN,str,O_WRONLY);
1.1.1.2 ! root     2140:                                                break; 
        !          2141:                                        }
1.1       root     2142:                                        lseek(file,(long)i*4L,SEEK_SET);
                   2143:                                        write(file,&sbbs->cfg.event[i]->last,sizeof(time_t));
                   2144:                                        close(file);
                   2145: 
                   2146:                                        if(sbbs->cfg.event[i]->misc&EVENT_EXCL) { /* exclusive event */
                   2147:                                                // Check/change the status of the nodes that we're in control of
1.1.1.2 ! root     2148:                                                for(j=first_node;j<=last_node;j++) {
        !          2149:                                                        node.status=NODE_INVALID_STATUS;
        !          2150:                                                        if(sbbs->getnodedat(j,&node,1)!=0)
        !          2151:                                                                continue;
1.1       root     2152:                                                        node.status=NODE_WFC;
                   2153:                                                        sbbs->putnodedat(j,&node);
                   2154:                                                }
                   2155:                                        }
                   2156:                                } 
                   2157:                        } 
                   2158:                }
                   2159:                mswait(1000);
                   2160:        }
1.1.1.2 ! root     2161:        sbbs->cfg.node_num=0;
1.1       root     2162:     sbbs->event_thread_running = false;
                   2163: 
                   2164:        thread_down();
1.1.1.2 ! root     2165:        eprintf(LOG_DEBUG,"BBS Event thread terminated (%u threads remain)", thread_count);
1.1       root     2166: }
                   2167: 
                   2168: 
                   2169: //****************************************************************************
                   2170: sbbs_t::sbbs_t(ushort node_num, DWORD addr, char* name, SOCKET sd,
1.1.1.2 ! root     2171:                           scfg_t* global_cfg, char* global_text[], client_t* client_info)
1.1       root     2172: {
                   2173:        char    nodestr[32];
                   2174:        uint    i;
                   2175: 
                   2176:     if(node_num)
1.1.1.2 ! root     2177:        sprintf(nodestr,"Node %d",node_num);
1.1       root     2178:     else
                   2179:        strcpy(nodestr,name);
                   2180: 
1.1.1.2 ! root     2181:        lprintf(LOG_DEBUG,"%s constructor using socket %d (settings=%lx)"
        !          2182:                , nodestr, sd, global_cfg->node_misc);
        !          2183: 
        !          2184:        startup = ::startup;    // Convert from global to class member
1.1       root     2185: 
                   2186:        memcpy(&cfg, global_cfg, sizeof(cfg));
                   2187: 
                   2188:        cfg.node_num=node_num;
1.1.1.2 ! root     2189:        if(node_num>0) {
1.1       root     2190:                strcpy(cfg.node_dir, cfg.node_path[node_num-1]);
1.1.1.2 ! root     2191:                prep_dir(cfg.node_dir, cfg.temp_dir, sizeof(cfg.temp_dir));
        !          2192:        } else if(startup->temp_dir[0]) {
        !          2193:                SAFECOPY(cfg.temp_dir,startup->temp_dir);
1.1       root     2194:        } else
1.1.1.2 ! root     2195:        prep_dir(cfg.data_dir, cfg.temp_dir, sizeof(cfg.temp_dir));
1.1       root     2196: 
                   2197:        terminated = false;
                   2198:        event_thread_running = false;
                   2199:     input_thread_running = false;
                   2200:     output_thread_running = false;
1.1.1.2 ! root     2201:        input_thread_mutex_locked = false;
1.1       root     2202: 
1.1.1.2 ! root     2203:        if(client_info==NULL)
        !          2204:                memset(&client,0,sizeof(client));
        !          2205:        else
        !          2206:                memcpy(&client,client_info,sizeof(client));
1.1       root     2207:        client_addr = addr;
                   2208:        client_socket = sd;
1.1.1.2 ! root     2209:        SAFECOPY(client_name, name);
1.1       root     2210:        client_socket_dup=INVALID_SOCKET;
1.1.1.2 ! root     2211:        client_ident[0]=0;
        !          2212: 
        !          2213:        terminal[0]=0;
1.1       root     2214: 
                   2215:        /* Init some important variables */
                   2216: 
                   2217:        rio_abortable=false;
                   2218: 
                   2219:        console = 0;
                   2220:        online = 0;
                   2221:        outchar_esc = 0;
                   2222:        nodemsg_inside = 0;     /* allows single nest */
1.1.1.2 ! root     2223:        hotkey_inside = 0;      /* allows single nest */
        !          2224:        event_time = 0;
        !          2225:        event_code = nulstr;
1.1       root     2226:        nodesync_inside = false;
                   2227:        errorlog_inside = false;
                   2228:        errormsg_inside = false;
                   2229:        gettimeleft_inside = false;
                   2230:        uselect_total = 0;
                   2231:        lbuflen = 0;
                   2232:        connection="Telnet";
1.1.1.2 ! root     2233: 
        !          2234:        ZERO_VAR(telnet_local_option);
        !          2235:        ZERO_VAR(telnet_remote_option);
        !          2236: 
1.1       root     2237:     telnet_cmdlen=0;
                   2238:        telnet_mode=0;
                   2239:        telnet_last_rxch=0;
1.1.1.2 ! root     2240: 
1.1       root     2241:        sys_status=lncntr=tos=criterrs=keybufbot=keybuftop=lbuflen=slcnt=0L;
                   2242:        curatr=LIGHTGRAY;
1.1.1.2 ! root     2243:        attr_sp=0;      /* attribute stack pointer */
1.1       root     2244:        errorlevel=0;
                   2245:        logcol=1;
                   2246:        logfile_fp=NULL;
                   2247:        nodefile=-1;
                   2248:        node_ext=-1;
                   2249:        nodefile_fp=NULL;
                   2250:        node_ext_fp=NULL;
1.1.1.2 ! root     2251:        current_msg=NULL;
        !          2252: 
        !          2253: #ifdef JAVASCRIPT
        !          2254:        js_runtime=NULL;        /* runtime */
        !          2255:        js_cx=NULL;                     /* context */
        !          2256: #endif
1.1       root     2257: 
                   2258:        for(i=0;i<TOTAL_TEXT;i++)
                   2259:                text[i]=text_sav[i]=global_text[i];
                   2260: 
                   2261:        memset(&main_csi,0,sizeof(main_csi));
                   2262:        memset(&thisnode,0,sizeof(thisnode));
                   2263:        memset(&useron,0,sizeof(useron));
                   2264:        memset(&inbuf,0,sizeof(inbuf));
                   2265:        memset(&outbuf,0,sizeof(outbuf));
                   2266:        memset(&smb,0,sizeof(smb));
                   2267: 
                   2268:        global_str_vars=0;
                   2269:        global_str_var=NULL;
                   2270:        global_str_var_name=NULL;
                   2271:        global_int_vars=0;
                   2272:        global_int_var=NULL;
                   2273:        global_int_var_name=NULL;
                   2274:        sysvar_li=0;
                   2275:        sysvar_pi=0;
                   2276: 
                   2277:        cursub=NULL;
                   2278:        usrgrp=NULL;
                   2279:        usrsubs=NULL;
                   2280:        usrsub=NULL;
1.1.1.2 ! root     2281:        usrgrp_total=0;
1.1       root     2282: 
1.1.1.2 ! root     2283:        subscan=NULL;
1.1       root     2284: 
                   2285:        curdir=NULL;
                   2286:        usrlib=NULL;
                   2287:        usrdirs=NULL;
                   2288:        usrdir=NULL;
1.1.1.2 ! root     2289:        usrlib_total=0;
1.1       root     2290: 
                   2291:        batup_desc=NULL;
                   2292:        batup_name=NULL;
                   2293:        batup_misc=NULL;
                   2294:        batup_dir=NULL;
                   2295:        batup_alt=NULL;
                   2296: 
                   2297:        batdn_name=NULL;
                   2298:        batdn_dir=NULL;
                   2299:        batdn_offset=NULL;
                   2300:        batdn_size=NULL;
                   2301:        batdn_alt=NULL;
                   2302:        batdn_cdt=NULL;
                   2303: 
                   2304:        spymsg("Connected");
                   2305: }
                   2306: 
                   2307: //****************************************************************************
                   2308: bool sbbs_t::init()
                   2309: {
1.1.1.2 ! root     2310:        char            str[MAX_PATH+1];
        !          2311:        char            tmp[128];
1.1       root     2312:        int                     result;
                   2313:        uint            i,j,k,l;
                   2314:        node_t          node;
                   2315:        socklen_t       addr_len;
                   2316:        SOCKADDR_IN     addr;
                   2317: 
1.1.1.2 ! root     2318:        if(cfg.node_num>0) {
1.1       root     2319:                RingBufInit(&inbuf, IO_THREAD_BUF_SIZE);
                   2320:                node_inbuf[cfg.node_num-1]=&inbuf;
                   2321:        }
                   2322: 
                   2323:     RingBufInit(&outbuf, IO_THREAD_BUF_SIZE);
1.1.1.2 ! root     2324:        outbuf.highwater_mark=startup->outbuf_highwater_mark;
1.1       root     2325: 
                   2326:        if(cfg.node_num && client_socket!=INVALID_SOCKET) {
                   2327: 
                   2328: #ifdef _WIN32
                   2329:                if(!DuplicateHandle(GetCurrentProcess(),
                   2330:                        (HANDLE)client_socket,
                   2331:                        GetCurrentProcess(),
                   2332:                        (HANDLE*)&client_socket_dup,
                   2333:                        0,
                   2334:                        TRUE, // Inheritable
                   2335:                        DUPLICATE_SAME_ACCESS)) {
                   2336:                        errormsg(WHERE,ERR_CREATE,"duplicate socket handle",client_socket);
                   2337:                        return(false);
                   2338:                }
                   2339: #endif
                   2340: 
                   2341:                addr_len=sizeof(addr);
                   2342:                if((result=getsockname(client_socket, (struct sockaddr *)&addr,&addr_len))!=0) {
1.1.1.2 ! root     2343:                        lprintf(LOG_ERR,"Node %d !ERROR %d (%d) getting address/port"
1.1       root     2344:                                ,cfg.node_num, result, ERROR_VALUE);
                   2345:                        return(false);
                   2346:                } 
1.1.1.2 ! root     2347:                lprintf(LOG_INFO,"Node %d attached to local interface %s port %d"
1.1       root     2348:                        ,cfg.node_num, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
                   2349: 
                   2350:                local_addr=addr.sin_addr.s_addr;
                   2351:        }
                   2352: 
                   2353:        comspec=getenv(
                   2354: #ifdef __unix__
                   2355:                "SHELL"
                   2356: #else
                   2357:                "COMSPEC"
                   2358: #endif
                   2359:                );
                   2360:        if(comspec==NULL) {
1.1.1.2 ! root     2361:                errormsg(WHERE, ERR_CHK, 
        !          2362: #ifdef __unix__
        !          2363:                "SHELL"
        !          2364: #else
        !          2365:                "COMSPEC"
        !          2366: #endif
        !          2367:                " environment variable", 0);
        !          2368: #if defined(__unix__)
        !          2369:        #if defined(_PATH_BSHELL)
        !          2370:                comspec =  _PATH_BSHELL;
        !          2371:        #else
        !          2372:                comspec = "/bin/sh";
        !          2373:        #endif
        !          2374: #else
1.1       root     2375:                return(false);
                   2376: #endif
1.1.1.2 ! root     2377:        }
1.1       root     2378: 
1.1.1.2 ! root     2379:        md(cfg.temp_dir);
1.1       root     2380: 
                   2381:        /* Shared NODE files */
                   2382:        sprintf(str,"%s%s",cfg.ctrl_dir,"node.dab");
                   2383:        if((nodefile=nopen(str,O_DENYNONE|O_RDWR|O_CREAT))==-1) {
                   2384:                errormsg(WHERE, ERR_OPEN, str, cfg.node_num);
                   2385:                return(false); 
                   2386:        }
                   2387:        memset(&node,0,sizeof(node_t));  /* write NULL to node struct */
                   2388:        node.status=NODE_OFFLINE;
                   2389:        while(filelength(nodefile)<(long)(cfg.sys_nodes*sizeof(node_t))) {
                   2390:                lseek(nodefile,0L,SEEK_END);
1.1.1.2 ! root     2391:                if(write(nodefile,&node,sizeof(node_t))!=sizeof(node_t)) {
        !          2392:                        errormsg(WHERE,ERR_WRITE,str,sizeof(node_t));
        !          2393:                        break; 
        !          2394:                }
1.1       root     2395:        }
1.1.1.2 ! root     2396:        for(i=0; cfg.node_num>0 && i<LOOP_NODEDAB; i++) {
        !          2397:                if(lock(nodefile,(cfg.node_num-1)*sizeof(node_t),sizeof(node_t))==0) {
        !          2398:                        unlock(nodefile,(cfg.node_num-1)*sizeof(node_t),sizeof(node_t));
        !          2399:                        break;
1.1       root     2400:                }
1.1.1.2 ! root     2401:                mswait(100);
        !          2402:        }
        !          2403:        if(cfg.node_misc&NM_CLOSENODEDAB) {
        !          2404:                close(nodefile);
        !          2405:                nodefile=-1;
1.1       root     2406:        }
                   2407: 
1.1.1.2 ! root     2408:        if(i>=LOOP_NODEDAB) {
        !          2409:                errormsg(WHERE, ERR_LOCK, str, cfg.node_num);
1.1       root     2410:                return(false); 
                   2411:        }
                   2412: 
                   2413:        if(cfg.node_num) {
                   2414:                sprintf(str,"%snode.log",cfg.node_dir);
                   2415:                if((logfile_fp=fopen(str,"a+b"))==NULL) {
                   2416:                        errormsg(WHERE, ERR_OPEN, str, 0);
1.1.1.2 ! root     2417:                        lprintf(LOG_ERR,"Perhaps this node is already running");
        !          2418:                        return(false); 
        !          2419:                }
1.1       root     2420: 
                   2421:                if(filelength(fileno(logfile_fp))) {
                   2422:                        log(crlf);
                   2423:                        now=time(NULL);
1.1.1.2 ! root     2424:                        struct tm tm;
        !          2425:                        localtime_r(&now,&tm);
        !          2426:                        sprintf(str,"%s  %s %s %02d %u  "
1.1       root     2427:                                "End of preexisting log entry (possible crash)"
1.1.1.2 ! root     2428:                                ,hhmmtostr(&cfg,&tm,tmp)
        !          2429:                                ,wday[tm.tm_wday]
        !          2430:                                ,mon[tm.tm_mon],tm.tm_mday,tm.tm_year+1900);
1.1       root     2431:                        logline("L!",str);
                   2432:                        log(crlf);
                   2433:                        catsyslog(1); 
                   2434:                }
                   2435: 
                   2436:                getnodedat(cfg.node_num,&thisnode,1);
                   2437:                /* thisnode.status=0; */
                   2438:                thisnode.action=0;
                   2439:                thisnode.useron=0;
                   2440:                thisnode.aux=0;
1.1.1.2 ! root     2441:                thisnode.misc&=(NODE_EVENT|NODE_LOCK|NODE_RRUN);
1.1       root     2442:                criterrs=thisnode.errors;
                   2443:                putnodedat(cfg.node_num,&thisnode);
                   2444:        }
                   2445: 
                   2446: /** Put in if(cfg.node_num) ? (not needed for server and event threads) */
                   2447:        backout();
                   2448: 
                   2449:        /* Reset COMMAND SHELL */
                   2450: 
                   2451:        main_csi.str=(char *)MALLOC(1024);
                   2452:        if(main_csi.str==NULL) {
                   2453:                errormsg(WHERE,ERR_ALLOC,"main_csi.str",1024);
                   2454:                return(false); 
                   2455:        }
                   2456:        memset(main_csi.str,0,1024);
                   2457: /***/
                   2458: 
                   2459:        if(cfg.total_grps) {
                   2460: 
1.1.1.2 ! root     2461:                usrgrp_total = cfg.total_grps;
1.1       root     2462: 
1.1.1.2 ! root     2463:                if((cursub=(uint *)MALLOC(sizeof(uint)*usrgrp_total))==NULL) {
        !          2464:                        errormsg(WHERE, ERR_ALLOC, "cursub", sizeof(uint)*usrgrp_total);
1.1       root     2465:                        return(false);
                   2466:                }
                   2467: 
1.1.1.2 ! root     2468:                if((usrgrp=(uint *)MALLOC(sizeof(uint)*usrgrp_total))==NULL) {
        !          2469:                        errormsg(WHERE, ERR_ALLOC, "usrgrp", sizeof(uint)*usrgrp_total);
1.1       root     2470:                        return(false);
                   2471:                }
                   2472: 
1.1.1.2 ! root     2473:                if((usrsubs=(uint *)MALLOC(sizeof(uint)*usrgrp_total))==NULL) {
        !          2474:                        errormsg(WHERE, ERR_ALLOC, "usrsubs", sizeof(uint)*usrgrp_total);
1.1       root     2475:                        return(false);
                   2476:                }
                   2477: 
1.1.1.2 ! root     2478:                if((usrsub=(uint **)calloc(usrgrp_total,sizeof(uint *)))==NULL) {
        !          2479:                        errormsg(WHERE, ERR_ALLOC, "usrsub", sizeof(uint)*usrgrp_total);
1.1       root     2480:                        return(false);
                   2481:                }
1.1.1.2 ! root     2482:  
        !          2483:                if((subscan=(subscan_t *)MALLOC(sizeof(subscan_t)*cfg.total_subs))==NULL) {
        !          2484:                        errormsg(WHERE, ERR_ALLOC, "subscan", sizeof(subscan_t)*cfg.total_subs);
1.1       root     2485:                        return(false);
                   2486:                }
                   2487:        }
                   2488: 
                   2489:        for(i=l=0;i<(uint)cfg.total_grps;i++) {
                   2490:                for(j=k=0;j<cfg.total_subs;j++)
                   2491:                        if(cfg.sub[j]->grp==i)
                   2492:                                k++;    /* k = number of subs per grp[i] */
                   2493:                if(k>l) l=k;    /* l = the largest number of subs per grp */
                   2494:        }
                   2495:        if(l)
                   2496:                for(i=0;i<cfg.total_grps;i++)
                   2497:                        if((usrsub[i]=(uint *)MALLOC(sizeof(uint)*l))==NULL) {
                   2498:                                errormsg(WHERE, ERR_ALLOC, "usrsub[x]", sizeof(uint)*l);
                   2499:                                return(false);
                   2500:                        }
                   2501: 
                   2502:        if(cfg.total_libs) {
                   2503: 
1.1.1.2 ! root     2504:                usrlib_total = cfg.total_libs;
        !          2505: 
        !          2506:                if((curdir=(uint *)MALLOC(sizeof(uint)*usrlib_total))==NULL) {
        !          2507:                        errormsg(WHERE, ERR_ALLOC, "curdir", sizeof(uint)*usrlib_total);
1.1       root     2508:                        return(false);
                   2509:                }
                   2510: 
1.1.1.2 ! root     2511:                if((usrlib=(uint *)MALLOC(sizeof(uint)*usrlib_total))==NULL) {
        !          2512:                        errormsg(WHERE, ERR_ALLOC, "usrlib", sizeof(uint)*usrlib_total);
1.1       root     2513:                        return(false);
                   2514:                }
                   2515: 
1.1.1.2 ! root     2516:                if((usrdirs=(uint *)MALLOC(sizeof(uint)*usrlib_total))==NULL) {
        !          2517:                        errormsg(WHERE, ERR_ALLOC, "usrdirs", sizeof(uint)*usrlib_total);
1.1       root     2518:                        return(false);
                   2519:                }
                   2520: 
1.1.1.2 ! root     2521:                if((usrdir=(uint **)calloc(usrlib_total,sizeof(uint *)))==NULL) {
        !          2522:                        errormsg(WHERE, ERR_ALLOC, "usrdir", sizeof(uint)*usrlib_total);
1.1       root     2523:                        return(false);
                   2524:                }
                   2525:        }
                   2526: 
                   2527:        for(i=l=0;i<cfg.total_libs;i++) {
                   2528:                for(j=k=0;j<cfg.total_dirs;j++)
                   2529:                        if(cfg.dir[j]->lib==i)
                   2530:                                k++;
                   2531:                if(k>l) l=k;    /* l = largest number of dirs in a lib */
                   2532:        }
                   2533:        if(l) {
                   2534:                l++;    /* for temp dir */
                   2535:                for(i=0;i<cfg.total_libs;i++)
                   2536:                        if((usrdir[i]=(uint *)MALLOC(sizeof(uint)*l))==NULL) {
                   2537:                                errormsg(WHERE, ERR_ALLOC, "usrdir[x]", sizeof(uint)*l);
                   2538:                                return(false);
                   2539:                        }
                   2540:        }
                   2541:  
                   2542:        if(cfg.max_batup) {
                   2543: 
                   2544:                if((batup_desc=(char **)MALLOC(sizeof(char *)*cfg.max_batup))==NULL) {
                   2545:                        errormsg(WHERE, ERR_ALLOC, "batup_desc", sizeof(char *)*cfg.max_batup);
                   2546:                        return(false);
                   2547:                }
                   2548:                if((batup_name=(char **)MALLOC(sizeof(char *)*cfg.max_batup))==NULL) {
                   2549:                        errormsg(WHERE, ERR_ALLOC, "batup_name", sizeof(char *)*cfg.max_batup);
                   2550:                        return(false);
                   2551:                }
                   2552:                if((batup_misc=(long *)MALLOC(sizeof(long)*cfg.max_batup))==NULL) {
                   2553:                        errormsg(WHERE, ERR_ALLOC, "batup_misc", sizeof(char *)*cfg.max_batup);
                   2554:                        return(false);
                   2555:                }
                   2556:                if((batup_dir=(uint *)MALLOC(sizeof(uint)*cfg.max_batup))==NULL) {
                   2557:                        errormsg(WHERE, ERR_ALLOC, "batup_dir", sizeof(char *)*cfg.max_batup);
                   2558:                        return(false);
                   2559:                }
                   2560:                if((batup_alt=(ushort *)MALLOC(sizeof(ushort)*cfg.max_batup))==NULL) {
                   2561:                        errormsg(WHERE, ERR_ALLOC, "batup_alt", sizeof(char *)*cfg.max_batup);
                   2562:                        return(false);
                   2563:                }
                   2564:                for(i=0;i<cfg.max_batup;i++) {
                   2565:                        if((batup_desc[i]=(char *)MALLOC(59))==NULL) {
                   2566:                                errormsg(WHERE, ERR_ALLOC, "batup_desc[x]", 59);
                   2567:                                return(false);
                   2568:                        }
                   2569:                        if((batup_name[i]=(char *)MALLOC(13))==NULL) {
                   2570:                                errormsg(WHERE, ERR_ALLOC, "batup_name[x]", 13);
                   2571:                                return(false);
                   2572:                        } 
                   2573:                } 
                   2574:        }
                   2575: 
                   2576:        if(cfg.max_batdn) {
                   2577: 
                   2578:                if((batdn_name=(char **)MALLOC(sizeof(char *)*cfg.max_batdn))==NULL) {
                   2579:                        errormsg(WHERE, ERR_ALLOC, "batdn_name", sizeof(char *)*cfg.max_batdn);
                   2580:                        return(false);
                   2581:                }
                   2582:                if((batdn_dir=(uint *)MALLOC(sizeof(uint)*cfg.max_batdn))==NULL)  {
                   2583:                        errormsg(WHERE, ERR_ALLOC, "batdn_dir", sizeof(uint)*cfg.max_batdn);
                   2584:                        return(false);
                   2585:                }
                   2586:                if((batdn_offset=(long *)MALLOC(sizeof(long)*cfg.max_batdn))==NULL)  {
                   2587:                        errormsg(WHERE, ERR_ALLOC, "batdn_offset", sizeof(long)*cfg.max_batdn);
                   2588:                        return(false);
                   2589:                }
                   2590:                if((batdn_size=(ulong *)MALLOC(sizeof(ulong)*cfg.max_batdn))==NULL) {
                   2591:                        errormsg(WHERE, ERR_ALLOC, "batdn_size", sizeof(ulong)*cfg.max_batdn);
                   2592:                        return(false);
                   2593:                }
                   2594:                if((batdn_cdt=(ulong *)MALLOC(sizeof(ulong)*cfg.max_batdn))==NULL) {
                   2595:                        errormsg(WHERE, ERR_ALLOC, "batdn_cdt", sizeof(long)*cfg.max_batdn);
                   2596:                        return(false);
                   2597:                }
                   2598:                if((batdn_alt=(ushort *)MALLOC(sizeof(ushort)*cfg.max_batdn))==NULL) {
                   2599:                        errormsg(WHERE, ERR_ALLOC, "batdn_alt", sizeof(ushort)*cfg.max_batdn);
                   2600:                        return(false);
                   2601:                }
                   2602:                for(i=0;i<cfg.max_batdn;i++)
                   2603:                        if((batdn_name[i]=(char *)MALLOC(13))==NULL) {
                   2604:                                errormsg(WHERE, ERR_ALLOC, "batdn_name[x]", 13);
                   2605:                                return(false);
                   2606:                        } 
                   2607:        }
                   2608: 
                   2609:        reset_logon_vars();
                   2610: 
                   2611:        online=ON_REMOTE;
                   2612: 
                   2613:        return(true);
                   2614: }
                   2615: 
                   2616: //****************************************************************************
                   2617: sbbs_t::~sbbs_t()
                   2618: {
                   2619:        uint i;
                   2620:        char node[32];
                   2621: 
                   2622:     if(cfg.node_num)
                   2623:        sprintf(node,"Node %d", cfg.node_num);
                   2624:     else
                   2625:        strcpy(node,client_name);
1.1.1.2 ! root     2626: #ifdef _DEBUG
        !          2627:        lprintf(LOG_DEBUG,"%s destructor begin", node);
        !          2628: #endif
1.1       root     2629: 
1.1.1.2 ! root     2630: //     if(!cfg.node_num)
        !          2631: //             rmdir(cfg.temp_dir);
1.1       root     2632: 
                   2633:        if(client_socket_dup!=INVALID_SOCKET)
                   2634:                closesocket(client_socket_dup); /* close duplicate handle */
                   2635: 
1.1.1.2 ! root     2636:        if(cfg.node_num>0)
1.1       root     2637:                node_inbuf[cfg.node_num-1]=NULL;
1.1.1.2 ! root     2638:        if(cfg.node_num>0 && !input_thread_running)
1.1       root     2639:                RingBufDispose(&inbuf);
                   2640:        if(!output_thread_running)
                   2641:                RingBufDispose(&outbuf);
                   2642: 
                   2643:        /* Close all open files */
                   2644:        if(nodefile!=-1) {
                   2645:                close(nodefile);
                   2646:                nodefile=-1;
                   2647:        }
                   2648:        if(node_ext!=-1) {
                   2649:                close(node_ext);
                   2650:                node_ext=-1;
                   2651:        }
                   2652:        if(logfile_fp!=NULL) {
                   2653:                fclose(logfile_fp);
                   2654:                logfile_fp=NULL;
                   2655:        }
                   2656: 
                   2657:        /********************************/
                   2658:        /* Free allocated class members */
                   2659:        /********************************/
                   2660: 
1.1.1.2 ! root     2661: #ifdef JAVASCRIPT
        !          2662:        /* Free Context */
        !          2663:        if(js_cx!=NULL) {       
        !          2664:                lprintf(LOG_DEBUG,"%s JavaScript: Destroying context",node);
        !          2665:                JS_DestroyContext(js_cx);
        !          2666:                js_cx=NULL;
        !          2667:        }
        !          2668: 
        !          2669:        if(js_runtime!=NULL) {
        !          2670:                lprintf(LOG_DEBUG,"%s JavaScript: Destroying runtime",node);
        !          2671:                JS_DestroyRuntime(js_runtime);
        !          2672:                js_runtime=NULL;
        !          2673:        }
        !          2674: #endif
        !          2675: 
1.1       root     2676:        /* Reset text.dat */
                   2677: 
                   2678:        for(i=0;i<TOTAL_TEXT && text!=NULL;i++)
                   2679:                if(text[i]!=text_sav[i]) {
                   2680:                        if(text[i]!=nulstr)
                   2681:                                FREE(text[i]); 
                   2682:                }
                   2683: 
                   2684:        /* Global command shell vars */
                   2685: 
                   2686:        freevars(&main_csi);
                   2687:        clearvars(&main_csi);
                   2688:        FREE_AND_NULL(main_csi.str);    /* crash */
                   2689:        FREE_AND_NULL(main_csi.cs);
                   2690: 
                   2691:        for(i=0;i<global_str_vars && global_str_var!=NULL;i++)
                   2692:                FREE_AND_NULL(global_str_var[i]);
                   2693: 
                   2694:        FREE_AND_NULL(global_str_var);
                   2695:        FREE_AND_NULL(global_str_var_name);
                   2696:        global_str_vars=0;
                   2697: 
                   2698:        FREE_AND_NULL(global_int_var);
                   2699:        FREE_AND_NULL(global_int_var_name);
                   2700:        global_int_vars=0;
                   2701: 
                   2702:        /* Sub-board variables */
1.1.1.2 ! root     2703:        for(i=0;i<usrgrp_total && usrsub!=NULL;i++)
        !          2704:                FREE_AND_NULL(usrsub[i]);       /* exception here (ptr=0xfdfdfdfd) on exit July-10-2002 */
1.1       root     2705: 
                   2706:        FREE_AND_NULL(cursub);
                   2707:        FREE_AND_NULL(usrgrp);
                   2708:        FREE_AND_NULL(usrsubs);
                   2709:        FREE_AND_NULL(usrsub);
1.1.1.2 ! root     2710:        FREE_AND_NULL(subscan);
1.1       root     2711: 
                   2712:        /* File Directory variables */
1.1.1.2 ! root     2713:        for(i=0;i<usrlib_total && usrdir!=NULL;i++)
1.1       root     2714:                FREE_AND_NULL(usrdir[i]);
                   2715: 
                   2716:        FREE_AND_NULL(curdir);
                   2717:        FREE_AND_NULL(usrlib);
                   2718:        FREE_AND_NULL(usrdirs);
                   2719:        FREE_AND_NULL(usrdir);
                   2720: 
                   2721:        /* Batch upload vars */
                   2722:        for(i=0;i<cfg.max_batup && batup_desc!=NULL && batup_name!=NULL;i++) {
                   2723:                FREE_AND_NULL(batup_desc[i]);
                   2724:                FREE_AND_NULL(batup_name[i]);
                   2725:        }
                   2726: 
                   2727:        FREE_AND_NULL(batup_desc);
                   2728:        FREE_AND_NULL(batup_name);
                   2729:        FREE_AND_NULL(batup_misc);
                   2730:        FREE_AND_NULL(batup_dir);
                   2731:        FREE_AND_NULL(batup_alt);
                   2732: 
                   2733:        /* Batch download vars */
                   2734:        for(i=0;i<cfg.max_batdn && batdn_name!=NULL;i++)
                   2735:                FREE_AND_NULL(batdn_name[i]); 
                   2736: 
                   2737:        FREE_AND_NULL(batdn_name);
                   2738:        FREE_AND_NULL(batdn_dir);
                   2739:        FREE_AND_NULL(batdn_offset);
                   2740:        FREE_AND_NULL(batdn_size);
                   2741:        FREE_AND_NULL(batdn_cdt);
                   2742:        FREE_AND_NULL(batdn_alt);
                   2743: 
1.1.1.2 ! root     2744: #if 0 && defined(_WIN32) && defined(_DEBUG) && defined(_MSC_VER)
        !          2745:        if(!_CrtCheckMemory())
        !          2746:                lprintf(LOG_ERR,"!MEMORY ERRORS REPORTED IN DATA/DEBUG.LOG!");
        !          2747: #endif
        !          2748: 
        !          2749: #ifdef _DEBUG
        !          2750:        lprintf(LOG_DEBUG,"%s destructor end", node);
        !          2751: #endif
1.1       root     2752: }
                   2753: 
                   2754: /****************************************************************************/
                   2755: /* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
                   2756: /* number of times if the attempted file is already open or denying access  */
1.1.1.2 ! root     2757: /* for some other reason.                                                                                                      */
        !          2758: /* All files are opened in BINARY mode, unless O_TEXT access bit is set.       */
1.1       root     2759: /****************************************************************************/
                   2760: int sbbs_t::nopen(char *str, int access)
                   2761: {
                   2762:        char logstr[256];
                   2763:        int file,share,count=0;
                   2764: 
                   2765:     if(access&O_DENYNONE) {
                   2766:         share=SH_DENYNO;
1.1.1.2 ! root     2767:         access&=~O_DENYNONE; 
        !          2768:        }
1.1       root     2769:     else if(access==O_RDONLY) share=SH_DENYWR;
                   2770:     else share=SH_DENYRW;
1.1.1.2 ! root     2771:        if(!(access&O_TEXT))
        !          2772:                access|=O_BINARY;
        !          2773:     while(((file=sopen(str,access,share,S_IREAD|S_IWRITE))==-1)
        !          2774:         && (errno==EACCES || errno==EAGAIN) && count++<LOOP_NOPEN)
        !          2775:            mswait(100);
1.1       root     2776:     if(count>(LOOP_NOPEN/2) && count<=LOOP_NOPEN) {
1.1.1.2 ! root     2777:         sprintf(logstr,"NOPEN COLLISION - File: \"%s\" Count: %d"
1.1       root     2778:             ,str,count);
1.1.1.2 ! root     2779:         logline("!!",logstr); 
        !          2780:        }
        !          2781:     if(file==-1 && (errno==EACCES || errno==EAGAIN)) {
        !          2782:         sprintf(logstr,"NOPEN ACCESS DENIED - File: \"%s\" errno: %d"
        !          2783:                        ,str,errno);
        !          2784:                logline("!!",logstr);
        !          2785:                bputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
        !          2786:        }
1.1       root     2787:     return(file);
                   2788: }
                   2789: 
1.1.1.2 ! root     2790: void sbbs_t::spymsg(char* msg)
1.1       root     2791: {
                   2792:        char str[512];
                   2793:        struct in_addr addr;
                   2794: 
1.1.1.2 ! root     2795:        if(cfg.node_num<1)
1.1       root     2796:                return;
                   2797: 
                   2798:        addr.s_addr=client_addr;
                   2799:        sprintf(str,"\r\n\r\n*** Spy Message ***\r\nNode %d: %s [%s]\r\n*** %s ***\r\n\r\n"
                   2800:                ,cfg.node_num,client_name,inet_ntoa(addr),msg);
                   2801:        if(startup->node_spybuf!=NULL 
1.1.1.2 ! root     2802:                && startup->node_spybuf[cfg.node_num-1]!=NULL) {
1.1       root     2803:                RingBufWrite(startup->node_spybuf[cfg.node_num-1],(uchar*)str,strlen(str));
1.1.1.2 ! root     2804:                /* Signal spy output semaphore? */
        !          2805:                if(startup->node_spysem!=NULL 
        !          2806:                        && startup->node_spysem[sbbs->cfg.node_num-1]!=NULL)
        !          2807:                        sem_post(startup->node_spysem[sbbs->cfg.node_num-1]);
        !          2808:        }
1.1       root     2809: 
                   2810:        if(cfg.node_num && spy_socket[cfg.node_num-1]!=INVALID_SOCKET) 
1.1.1.2 ! root     2811:                sendsocket(spy_socket[cfg.node_num-1],str,strlen(str));
        !          2812: #ifdef __unix__
        !          2813:        if(cfg.node_num && uspy_socket[cfg.node_num-1]!=INVALID_SOCKET) 
        !          2814:                sendsocket(uspy_socket[cfg.node_num-1],str,strlen(str));
        !          2815: #endif
1.1       root     2816: }
                   2817: 
                   2818: #define MV_BUFLEN      4096
                   2819: 
                   2820: /****************************************************************************/
                   2821: /* Moves or copies a file from one dir to another                           */
                   2822: /* both 'src' and 'dest' must contain full path and filename                */
                   2823: /* returns 0 if successful, -1 if error                                     */
                   2824: /****************************************************************************/
                   2825: int sbbs_t::mv(char *src, char *dest, char copy)
                   2826: {
1.1.1.2 ! root     2827:        char    str[MAX_PATH+1],*buf,atr=curatr;
1.1       root     2828:        int             ind,outd;
                   2829:        uint    chunk=MV_BUFLEN;
                   2830:        ulong   length,l;
                   2831:        /* struct ftime ftime; */
                   2832:        FILE *inp,*outp;
                   2833: 
                   2834:     if(!stricmp(src,dest))      /* source and destination are the same! */
                   2835:         return(0);
1.1.1.2 ! root     2836:     if(!fexistcase(src)) {
1.1       root     2837:         bprintf("\r\n\7MV ERROR: Source doesn't exist\r\n'%s'\r\n"
                   2838:             ,src);
1.1.1.2 ! root     2839:         return(-1); 
        !          2840:        }
        !          2841:     if(!copy && fexistcase(dest)) {
1.1       root     2842:         bprintf("\r\n\7MV ERROR: Destination already exists\r\n'%s'\r\n"
                   2843:             ,dest);
1.1.1.2 ! root     2844:         return(-1); 
        !          2845:        }
        !          2846: #ifndef __unix__       /* need to determine if on same mount device */
1.1       root     2847:     if(!copy && ((src[1]!=':' && dest[1]!=':')
                   2848:         || (src[1]==':' && dest[1]==':' && toupper(src[0])==toupper(dest[0])))) {
                   2849:         if(rename(src,dest)) {                                         /* same drive, so move */
                   2850:             bprintf("\r\nMV ERROR: Error renaming '%s'"
                   2851:                     "\r\n                      to '%s'\r\n\7",src,dest);
1.1.1.2 ! root     2852:             return(-1); 
        !          2853:                }
        !          2854:         return(0)        !          2855:        }
        !          2856: #endif
1.1       root     2857:     attr(WHITE);
                   2858:     if((ind=nopen(src,O_RDONLY))==-1) {
                   2859:         errormsg(WHERE,ERR_OPEN,src,O_RDONLY);
1.1.1.2 ! root     2860:         return(-1); 
        !          2861:        }
1.1       root     2862:     if((inp=fdopen(ind,"rb"))==NULL) {
                   2863:         close(ind);
                   2864:         errormsg(WHERE,ERR_FDOPEN,str,O_RDONLY);
1.1.1.2 ! root     2865:         return(-1); 
        !          2866:        }
1.1       root     2867:     setvbuf(inp,NULL,_IOFBF,32*1024);
                   2868:     if((outd=nopen(dest,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
                   2869:         fclose(inp);
                   2870:         errormsg(WHERE,ERR_OPEN,dest,O_WRONLY|O_CREAT|O_TRUNC);
1.1.1.2 ! root     2871:         return(-1); 
        !          2872:        }
1.1       root     2873:     if((outp=fdopen(outd,"wb"))==NULL) {
                   2874:         close(outd);
                   2875:         fclose(inp);
                   2876:         errormsg(WHERE,ERR_FDOPEN,dest,O_WRONLY|O_CREAT|O_TRUNC);
1.1.1.2 ! root     2877:         return(-1); 
        !          2878:        }
1.1       root     2879:     setvbuf(outp,NULL,_IOFBF,8*1024);
                   2880:     length=filelength(ind);
                   2881:     if(!length) {
                   2882:         fclose(inp);
                   2883:         fclose(outp);
                   2884:         errormsg(WHERE,ERR_LEN,src,0);
1.1.1.2 ! root     2885:         return(-1); 
        !          2886:        }
1.1       root     2887:     if((buf=(char *)MALLOC(MV_BUFLEN))==NULL) {
                   2888:         fclose(inp);
                   2889:         fclose(outp);
                   2890:         errormsg(WHERE,ERR_ALLOC,nulstr,MV_BUFLEN);
1.1.1.2 ! root     2891:         return(-1); 
        !          2892:        }
1.1       root     2893:     l=0L;
                   2894:     while(l<length) {
                   2895:         bprintf("%2lu%%",l ? (long)(100.0/((float)length/l)) : 0L);
                   2896:         if(l+chunk>length)
                   2897:             chunk=length-l;
                   2898:         if(fread(buf,1,chunk,inp)!=chunk) {
                   2899:             FREE(buf);
                   2900:             fclose(inp);
                   2901:             fclose(outp);
                   2902:             errormsg(WHERE,ERR_READ,src,chunk);
1.1.1.2 ! root     2903:             return(-1); 
        !          2904:                }
1.1       root     2905:         if(fwrite(buf,1,chunk,outp)!=chunk) {
                   2906:             FREE(buf);
                   2907:             fclose(inp);
                   2908:             fclose(outp);
                   2909:             errormsg(WHERE,ERR_WRITE,dest,chunk);
1.1.1.2 ! root     2910:             return(-1); 
        !          2911:                }
1.1       root     2912:         l+=chunk;
1.1.1.2 ! root     2913:         bputs("\b\b\b"); 
        !          2914:        }
1.1       root     2915:     bputs("   \b\b\b");  /* erase it */
                   2916:     attr(atr);
                   2917:     /* getftime(ind,&ftime);
                   2918:     setftime(outd,&ftime); */
                   2919:     FREE(buf);
                   2920:     fclose(inp);
                   2921:     fclose(outp);
                   2922:     if(!copy && remove(src)) {
                   2923:         errormsg(WHERE,ERR_REMOVE,src,0);
1.1.1.2 ! root     2924:         return(-1); 
        !          2925:        }
1.1       root     2926:     return(0);
                   2927: }
                   2928: 
                   2929: void sbbs_t::hangup(void)
                   2930: {
                   2931:        if(client_socket!=INVALID_SOCKET) {
1.1.1.2 ! root     2932:                mswait(1000);   /* Give socket output buffer time to flush */
        !          2933:                riosync(0);
        !          2934:                client_off(client_socket);
1.1       root     2935:                close_socket(client_socket);
                   2936:                client_socket=INVALID_SOCKET;
1.1.1.2 ! root     2937:        }
        !          2938:        if(client_socket_dup!=INVALID_SOCKET) {
1.1       root     2939:                closesocket(client_socket_dup);
                   2940:                client_socket_dup=INVALID_SOCKET;
                   2941:        }
1.1.1.2 ! root     2942:        sem_post(&outbuf.sem);
1.1       root     2943:        online=0;
                   2944: }
                   2945: 
1.1.1.2 ! root     2946: int sbbs_t::incom(unsigned long timeout)
1.1       root     2947: {
                   2948:        uchar   ch;
                   2949: 
1.1.1.2 ! root     2950: #if 0  /* looping version */
        !          2951:        while(!RingBufRead(&inbuf, &ch, 1))
        !          2952:                if(sem_trywait_block(&inbuf.sem,timeout)!=0 || sys_status&SS_ABORT)
        !          2953:                        return(NOINP);
        !          2954: #else
        !          2955:        if(!RingBufRead(&inbuf, &ch, 1)) {
        !          2956:                if(sem_trywait_block(&inbuf.sem,timeout)!=0)
        !          2957:                        return(NOINP);
        !          2958:                if(!RingBufRead(&inbuf, &ch, 1))
        !          2959:                        return(NOINP);
        !          2960:        }
        !          2961: #endif
1.1       root     2962:        return(ch);
                   2963: }
                   2964: 
                   2965: int sbbs_t::outcom(uchar ch)
                   2966: {
                   2967:        if(!RingBufFree(&outbuf))
                   2968:                return(TXBOF);
1.1.1.2 ! root     2969:     if(!RingBufWrite(&outbuf, &ch, 1))
        !          2970:                return(TXBOF);
1.1       root     2971:        return(0);
                   2972: }
                   2973: 
                   2974: void sbbs_t::putcom(char *str, int len)
                   2975: {
                   2976:        int i;
                   2977: 
                   2978:     if(!len)
                   2979:        len=strlen(str);
                   2980:     for(i=0;i<len && online; i++)
                   2981:         outcom(str[i]);
                   2982: }
                   2983: 
                   2984: void sbbs_t::riosync(char abortable)
                   2985: {
1.1.1.2 ! root     2986:        if(useron.misc&(RIP|WIP|HTML))  /* don't allow abort with RIP or WIP */
        !          2987:                abortable=0;                    /* mainly because of ANSI cursor position response */
        !          2988:        if(sys_status&SS_ABORT)         /* no need to sync if already aborting */
1.1       root     2989:                return;
                   2990:        time_t start=time(NULL);
                   2991:        while(online && rioctl(TXBC)) {                         /* wait up to three minutes for tx buf empty */
1.1.1.2 ! root     2992:                if(sys_status&SS_ABORT)
        !          2993:                        break;
        !          2994: #if 0  /* this isn't necessary (or desired) on a TCP/IP connection */
1.1       root     2995:                if(abortable && rioctl(RXBC)) {                 /* incoming characer */
                   2996:                        rioctl(IOFO);                                           /* flush output */
                   2997:                        sys_status|=SS_ABORT;                           /* set abort flag so no pause */
                   2998:                        break;                                                          /* abort sync */
                   2999:                }
1.1.1.2 ! root     3000: #endif
1.1       root     3001:                if(time(NULL)-start>180) {                              /* timeout */
1.1.1.2 ! root     3002:                        logline("!!","riosync timeout"); 
1.1       root     3003:                        break;
                   3004:                }
                   3005:                mswait(100);
                   3006:        }
                   3007: }
                   3008: 
                   3009: /* Legacy Remote I/O Control Interface */
                   3010: int sbbs_t::rioctl(ushort action)
                   3011: {
                   3012:        int             mode;
                   3013:        int             state;
                   3014: 
                   3015:        switch(action) {
                   3016:                case GVERS:     /* Get version */
                   3017:                        return(0x200);
                   3018:                case GUART:     /* Get UART I/O address, not available */
                   3019:                        return(0xffff);
                   3020:                case GIRQN:     /* Get IRQ number, not available */
                   3021:                        return((int)client_socket);
                   3022:                case GBAUD:     /* Get current bit rate */
                   3023:                        return(0xffff);
                   3024:                case RXBC:              /* Get receive buffer count */
                   3025:                        // ulong        cnt;
                   3026:                        // ioctlsocket (client_socket,FIONREAD,&cnt);
                   3027:                        return(/* cnt+ */RingBufFull(&inbuf));
                   3028:                case RXBS:              /* Get receive buffer size */
1.1.1.2 ! root     3029:                        return(inbuf.size);
1.1       root     3030:                case TXBC:              /* Get transmit buffer count */
                   3031:                        return(RingBufFull(&outbuf));
                   3032:                case TXBS:              /* Get transmit buffer size */
1.1.1.2 ! root     3033:                        return(outbuf.size);
1.1       root     3034:                case TXBF:              /* Get transmit buffer free space */
                   3035:                        return(RingBufFree(&outbuf));
                   3036:                case IOMODE:
                   3037:                        mode=0;
                   3038:                        if(rio_abortable)
                   3039:                                mode|=ABORT;
                   3040:                        return(mode);
                   3041:                case IOSTATE:
                   3042:                        state=0;
                   3043:                        if(sys_status&SS_ABORT)
                   3044:                                state|=ABORT;
                   3045:                        return(state);
                   3046:                case IOFI:              /* Flush input buffer */
                   3047:                        RingBufReInit(&inbuf);
                   3048:                        break;
                   3049:                case IOFO:              /* Flush output buffer */
                   3050:                RingBufReInit(&outbuf);
                   3051:                        break;
                   3052:                case IOFB:              /* Flush both buffers */
                   3053:                        RingBufReInit(&inbuf);
                   3054:                        RingBufReInit(&outbuf);
                   3055:                        break;
                   3056:                case LFN81:
                   3057:                case LFE71:
                   3058:                case FIFOCTL:
                   3059:                        return(0);
                   3060:                }
                   3061: 
                   3062:        if((action&0xff)==IOSM) {       /* Get/Set/Clear mode */
                   3063:                if(action&ABORT)
                   3064:                        rio_abortable=true;
1.1.1.2 ! root     3065:                return(0)        !          3066:        }
1.1       root     3067: 
                   3068:        if((action&0xff)==IOCM) {       /* Get/Set/Clear mode */
                   3069:                if(action&ABORT)
                   3070:                        rio_abortable=false;
1.1.1.2 ! root     3071:                return(0)        !          3072:        }
1.1       root     3073: 
                   3074:        if((action&0xff)==IOSS) {       /* Set state */
                   3075:                if(action&ABORT)
                   3076:                        sys_status|=SS_ABORT;
1.1.1.2 ! root     3077:                return(0)        !          3078:        }
1.1       root     3079: 
                   3080:        if((action&0xff)==IOCS) {       /* Clear state */
                   3081:                if(action&ABORT)
                   3082:                        sys_status&=~SS_ABORT;
1.1.1.2 ! root     3083:                return(0)        !          3084:        }
1.1       root     3085: 
                   3086:        return(0);
                   3087: }
                   3088: 
                   3089: void sbbs_t::reset_logon_vars(void)
                   3090: {
                   3091:        int i;
                   3092: 
                   3093:     /* bools */
                   3094:     qwklogon=false;
                   3095: 
                   3096:     sys_status&=~(SS_USERON|SS_TMPSYSOP|SS_LCHAT|SS_ABORT
                   3097:         |SS_PAUSEON|SS_PAUSEOFF|SS_EVENT|SS_NEWUSER|SS_NEWDAY);
                   3098:     cid[0]=0;
                   3099:     wordwrap[0]=0;
                   3100:     question[0]=0;
                   3101:     menu_dir[0]=0;
                   3102:     menu_file[0]=0;
1.1.1.2 ! root     3103:     rows=24;
        !          3104:        cols=80;
1.1       root     3105:     lncntr=0;
                   3106:     autoterm=0;
                   3107:     keybufbot=keybuftop=lbuflen=0;
                   3108:     slcnt=0;
                   3109:     altul=0;
                   3110:     timeleft_warn=0;
                   3111:     logon_uls=logon_ulb=logon_dls=logon_dlb=0;
                   3112:     logon_posts=logon_emails=logon_fbacks=0;
                   3113:     batdn_total=batup_total=0;
                   3114:     usrgrps=usrlibs=0;
                   3115:     curgrp=curlib=0;
                   3116:     for(i=0;i<cfg.total_libs;i++)
                   3117:         curdir[i]=0;
                   3118:     for(i=0;i<cfg.total_grps;i++)
                   3119:         cursub[i]=0;
                   3120:        cur_cps=3000;
                   3121:     cur_rate=30000;
                   3122:     dte_rate=38400;
                   3123:        main_cmds=xfer_cmds=posts_read=0;
                   3124:        lastnodemsg=0;
                   3125:        lastnodemsguser[0]=0;
                   3126: }
                   3127: 
                   3128: /****************************************************************************/
                   3129: /* Writes NODE.LOG at end of SYSTEM.LOG                                                                                */
                   3130: /****************************************************************************/
                   3131: void sbbs_t::catsyslog(int crash)
                   3132: {
1.1.1.2 ! root     3133:        char str[MAX_PATH+1];
1.1       root     3134:        char HUGE16 *buf;
                   3135:        int  i,file;
                   3136:        long length;
1.1.1.2 ! root     3137:        struct tm tm;
1.1       root     3138: 
                   3139:        if(logfile_fp==NULL) {
                   3140:                sprintf(str,"%snode.log",cfg.node_dir);
                   3141:                if((logfile_fp=fopen(str,"rb"))==NULL) {
                   3142:                        errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
                   3143:                        return; 
                   3144:                }
                   3145:        }
                   3146:        length=ftell(logfile_fp);
                   3147:        if(length) {
                   3148:                if((buf=(char HUGE16 *)LMALLOC(length))==NULL) {
                   3149:                        errormsg(WHERE,ERR_ALLOC,str,length);
1.1.1.2 ! root     3150:                        return; 
        !          3151:                }
1.1       root     3152:                rewind(logfile_fp);
                   3153:                if(fread(buf,1,length,logfile_fp)!=(size_t)length) {
                   3154:                        errormsg(WHERE,ERR_READ,"log file",length);
                   3155:                        FREE((char *)buf);
                   3156:                        return; 
                   3157:                }
                   3158:                now=time(NULL);
1.1.1.2 ! root     3159:                localtime_r(&now,&tm);
        !          3160:                sprintf(str,"%slogs/%2.2d%2.2d%2.2d.log",cfg.logs_dir,tm.tm_mon+1,tm.tm_mday
        !          3161:                        ,TM_YEAR(tm.tm_year));
1.1       root     3162:                if((file=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
                   3163:                        errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
                   3164:                        FREE((char *)buf);
1.1.1.2 ! root     3165:                        return; 
        !          3166:                }
1.1       root     3167:                if(lwrite(file,buf,length)!=length) {
                   3168:                        close(file);
                   3169:                        errormsg(WHERE,ERR_WRITE,str,length);
                   3170:                        FREE((char *)buf);
1.1.1.2 ! root     3171:                        return; 
        !          3172:                }
1.1       root     3173:                close(file);
                   3174:                if(crash) {
                   3175:                        for(i=0;i<2;i++) {
1.1.1.2 ! root     3176:                                sprintf(str,"%scrash.log",i ? cfg.logs_dir : cfg.node_dir);
1.1       root     3177:                                if((file=nopen(str,O_WRONLY|O_APPEND|O_CREAT))==-1) {
                   3178:                                        errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_APPEND|O_CREAT);
                   3179:                                        FREE((char *)buf);
1.1.1.2 ! root     3180:                                        return; 
        !          3181:                                }
1.1       root     3182:                                if(lwrite(file,buf,length)!=length) {
                   3183:                                        close(file);
                   3184:                                        errormsg(WHERE,ERR_WRITE,str,length);
                   3185:                                        FREE((char *)buf);
1.1.1.2 ! root     3186:                                        return; 
        !          3187:                                }
        !          3188:                                close(file); 
        !          3189:                        } 
        !          3190:                }
        !          3191:                FREE((char *)buf); 
        !          3192:        }
1.1       root     3193: 
                   3194:        fclose(logfile_fp);
                   3195: 
                   3196:        sprintf(str,"%snode.log",cfg.node_dir);
                   3197:        if((logfile_fp=fopen(str,"w+b"))==NULL) /* Truncate NODE.LOG */
                   3198:                errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_TRUNC);
                   3199: }
                   3200: 
                   3201: 
                   3202: void sbbs_t::logoffstats()
                   3203: {
1.1.1.2 ! root     3204:     char str[MAX_PATH+1];
1.1       root     3205:     int i,file;
                   3206:     stats_t stats;
                   3207: 
                   3208:        if(REALSYSOP && !(cfg.sys_misc&SM_SYSSTAT))
                   3209:                return;
                   3210:        
                   3211:        for(i=0;i<2;i++) {
                   3212:                sprintf(str,"%sdsts.dab",i ? cfg.ctrl_dir : cfg.node_dir);
                   3213:                if((file=nopen(str,O_RDWR))==-1) {
                   3214:                        errormsg(WHERE,ERR_OPEN,str,O_RDWR);
1.1.1.2 ! root     3215:                        return; 
        !          3216:                }
        !          3217:                memset(&stats,0,sizeof(stats));
        !          3218:                lseek(file,4L,SEEK_SET);   /* Skip timestamp, logons and logons today */
        !          3219:                read(file,&stats,sizeof(stats));  
1.1       root     3220: 
                   3221:                if(!(useron.rest&FLAG('Q'))) {  /* Don't count QWKnet nodes */
                   3222:                        stats.timeon+=(now-logontime)/60;
                   3223:                        stats.ttoday+=(now-logontime)/60;
                   3224:                        stats.ptoday+=logon_posts;
                   3225:                }
                   3226:                stats.uls+=logon_uls;
                   3227:                stats.ulb+=logon_ulb;
                   3228:                stats.dls+=logon_dls;
                   3229:                stats.dlb+=logon_dlb;
                   3230:                stats.etoday+=logon_emails;
                   3231:                stats.ftoday+=logon_fbacks;
1.1.1.2 ! root     3232: 
        !          3233: #if 0 // This is now handled in newuserdat()
1.1       root     3234:                if(sys_status&SS_NEWUSER)
                   3235:                        stats.nusers++;
1.1.1.2 ! root     3236: #endif
1.1       root     3237: 
1.1.1.2 ! root     3238:                lseek(file,4L,SEEK_SET);
        !          3239:                write(file,&stats,sizeof(stats));
1.1       root     3240:                close(file); 
                   3241:        }
                   3242: }
                   3243: 
                   3244: void node_thread(void* arg)
                   3245: {
                   3246:        char                    str[128];
                   3247:        char                    uname[LEN_ALIAS+1];
                   3248:        int                             file;
1.1.1.2 ! root     3249:        uint                    i;
        !          3250:        uint                    usernum;
        !          3251:        uint                    lastusernum;
1.1       root     3252:        uint                    curshell=0;
                   3253:        time_t                  now;
                   3254:        node_t                  node;
                   3255:        user_t                  user;
                   3256:        sbbs_t*                 sbbs = (sbbs_t*) arg;
                   3257: 
                   3258:        update_clients();
1.1.1.2 ! root     3259:        thread_up(TRUE /* setuid */);
        !          3260: 
        !          3261: #ifdef _DEBUG
        !          3262:        lprintf(LOG_DEBUG,"Node %d thread started",sbbs->cfg.node_num);
        !          3263: #endif
        !          3264: 
        !          3265:        srand(time(NULL));      /* Seed random number generator */
        !          3266:        sbbs_random(10);        /* Throw away first number */
        !          3267: 
        !          3268: #ifdef JAVASCRIPT
        !          3269:        if(!(startup->options&BBS_OPT_NO_JAVASCRIPT)) {
        !          3270:                if(!sbbs->js_init())    /* This must be done in the context of the node thread */
        !          3271:                        lprintf(LOG_ERR,"!Node %d !JavaScript Initialization FAILURE",sbbs->cfg.node_num);
        !          3272:        }
        !          3273: #endif
1.1       root     3274: 
                   3275:        if(sbbs->answer()) {
                   3276: 
                   3277:                if(sbbs->qwklogon) {
                   3278:                        sbbs->getsmsg(sbbs->useron.number);
                   3279:                        sbbs->qwk_sec();
                   3280:                } else while(sbbs->useron.number 
                   3281:                        && (sbbs->main_csi.misc&CS_OFFLINE_EXEC || sbbs->online)) {
                   3282: 
                   3283:                        if(!sbbs->main_csi.cs || curshell!=sbbs->useron.shell) {
                   3284:                                if(sbbs->useron.shell>=sbbs->cfg.total_shells)
                   3285:                                        sbbs->useron.shell=0;
1.1.1.2 ! root     3286:                                sprintf(str,"%s%s.bin",sbbs->cfg.mods_dir
1.1       root     3287:                                        ,sbbs->cfg.shell[sbbs->useron.shell]->code);
1.1.1.2 ! root     3288:                                if(sbbs->cfg.mods_dir[0]==0 || !fexistcase(str))
        !          3289:                                        sprintf(str,"%s%s.bin",sbbs->cfg.exec_dir
        !          3290:                                                ,sbbs->cfg.shell[sbbs->useron.shell]->code);
1.1       root     3291:                                if((file=sbbs->nopen(str,O_RDONLY))==-1) {
                   3292:                                        sbbs->errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
                   3293:                                        sbbs->hangup();
1.1.1.2 ! root     3294:                                        break; 
        !          3295:                                }
1.1       root     3296:                                FREE_AND_NULL(sbbs->main_csi.cs);
                   3297:                                sbbs->freevars(&sbbs->main_csi);
                   3298:                                sbbs->clearvars(&sbbs->main_csi);
                   3299: 
                   3300:                                sbbs->main_csi.length=filelength(file);
                   3301:                                if((sbbs->main_csi.cs=(uchar *)MALLOC(sbbs->main_csi.length))==NULL) {
                   3302:                                        close(file);
                   3303:                                        sbbs->errormsg(WHERE,ERR_ALLOC,str,sbbs->main_csi.length);
                   3304:                                        sbbs->hangup();
1.1.1.2 ! root     3305:                                        break; 
        !          3306:                                }
1.1       root     3307: 
                   3308:                                if(lread(file,sbbs->main_csi.cs,sbbs->main_csi.length)
                   3309:                                        !=(int)sbbs->main_csi.length) {
                   3310:                                        sbbs->errormsg(WHERE,ERR_READ,str,sbbs->main_csi.length);
                   3311:                                        close(file);
                   3312:                                        FREE(sbbs->main_csi.cs);
                   3313:                                        sbbs->main_csi.cs=NULL;
                   3314:                                        sbbs->hangup();
1.1.1.2 ! root     3315:                                        break; 
        !          3316:                                }
1.1       root     3317:                                close(file);
                   3318: 
                   3319:                                curshell=sbbs->useron.shell;
                   3320:                                sbbs->main_csi.ip=sbbs->main_csi.cs;
                   3321:                                sbbs->menu_dir[0]=0;
                   3322:                                sbbs->menu_file[0]=0;
                   3323:                                }
                   3324:                        if(sbbs->exec(&sbbs->main_csi))
                   3325:                                break;
                   3326:                }
                   3327:        }
                   3328: 
                   3329: #ifdef _WIN32
                   3330:        if(startup->hangup_sound[0] && !(startup->options&BBS_OPT_MUTE)) 
                   3331:                PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
                   3332: #endif
                   3333: 
1.1.1.2 ! root     3334:        sbbs->hangup(); /* closes sockets, calls client_off, and shuts down the output_thread */
1.1       root     3335:     node_socket[sbbs->cfg.node_num-1]=INVALID_SOCKET;
                   3336: 
                   3337:        sbbs->logout();
                   3338:        sbbs->logoffstats();    /* Updates both system and node dsts.dab files */
                   3339: 
                   3340:        if(sbbs->sys_status&SS_DAILY) { // New day, run daily events/maintenance
                   3341: 
                   3342:                now=time(NULL);
                   3343: 
                   3344:                sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
                   3345:                node.status=NODE_EVENT_RUNNING;
                   3346:                sbbs->putnodedat(sbbs->cfg.node_num,&node);
                   3347: 
                   3348:                sbbs->logentry("!:","Ran system daily maintenance");
                   3349: 
1.1.1.2 ! root     3350:                if(sbbs->cfg.user_backup_level) {
        !          3351:                        lprintf(LOG_INFO,"Node %d Backing-up user data..."
        !          3352:                                ,sbbs->cfg.node_num);
        !          3353:                        sprintf(str,"%suser/user.dat",sbbs->cfg.data_dir);
        !          3354:                        backup(str,sbbs->cfg.user_backup_level,FALSE);
        !          3355:                        sprintf(str,"%suser/name.dat",sbbs->cfg.data_dir);
        !          3356:                        backup(str,sbbs->cfg.user_backup_level,FALSE);
        !          3357:                }
        !          3358: 
        !          3359:                if(sbbs->cfg.mail_backup_level) {
        !          3360:                        lprintf(LOG_INFO,"Node %d Backing-up mail data..."
        !          3361:                                ,sbbs->cfg.node_num);
        !          3362:                        sprintf(str,"%smail.shd",sbbs->cfg.data_dir);
        !          3363:                        backup(str,sbbs->cfg.mail_backup_level,FALSE);
        !          3364:                        sprintf(str,"%smail.sha",sbbs->cfg.data_dir);
        !          3365:                        backup(str,sbbs->cfg.mail_backup_level,FALSE);
        !          3366:                        sprintf(str,"%smail.sdt",sbbs->cfg.data_dir);
        !          3367:                        backup(str,sbbs->cfg.mail_backup_level,FALSE);
        !          3368:                        sprintf(str,"%smail.sda",sbbs->cfg.data_dir);
        !          3369:                        backup(str,sbbs->cfg.mail_backup_level,FALSE);
        !          3370:                        sprintf(str,"%smail.sid",sbbs->cfg.data_dir);
        !          3371:                        backup(str,sbbs->cfg.mail_backup_level,FALSE);
        !          3372:                        sprintf(str,"%smail.sch",sbbs->cfg.data_dir);
        !          3373:                        backup(str,sbbs->cfg.mail_backup_level,FALSE);
        !          3374:                }
        !          3375: 
        !          3376:                lprintf(LOG_INFO,"Node %d Checking for inactive/expired user records..."
        !          3377:                        ,sbbs->cfg.node_num);
        !          3378:                lastusernum=lastuser(&sbbs->cfg);
        !          3379:                for(usernum=2;usernum<=lastusernum;usernum++) {
        !          3380: 
        !          3381:                        sprintf(str,"%5u of %-5u",usernum,lastusernum);
1.1       root     3382:                        status(str);
1.1.1.2 ! root     3383:                        user.number=usernum;
        !          3384:                        if((i=getuserdat(&sbbs->cfg,&user))!=0) {
        !          3385:                                sprintf(str,"user record %u",usernum);
        !          3386:                                sbbs->errormsg(WHERE,ERR_READ,str,i);
        !          3387:                                continue;
        !          3388:                        }
1.1       root     3389: 
                   3390:                        /***********************************************/
                   3391:                        /* Fix name (name.dat and user.dat) mismatches */
                   3392:                        /***********************************************/
1.1.1.2 ! root     3393:                        username(&sbbs->cfg,user.number,uname);
1.1       root     3394:                        if(user.misc&DELETED) {
                   3395:                                if(strcmp(uname,"DELETED USER"))
1.1.1.2 ! root     3396:                                        putusername(&sbbs->cfg,user.number,nulstr);
        !          3397:                                continue; 
        !          3398:                        }
1.1       root     3399: 
                   3400:                        if(strcmp(user.alias,uname))
1.1.1.2 ! root     3401:                                putusername(&sbbs->cfg,user.number,user.alias);
1.1       root     3402: 
                   3403:                        if(!(user.misc&(DELETED|INACTIVE))
                   3404:                                && user.expire && (ulong)user.expire<=(ulong)now) {
1.1.1.2 ! root     3405:                                putsmsg(&sbbs->cfg,user.number,sbbs->text[AccountHasExpired]);
1.1       root     3406:                                sprintf(str,"%s #%u Expired",user.alias,user.number);
                   3407:                                sbbs->logentry("!%",str);
                   3408:                                if(sbbs->cfg.level_misc[user.level]&LEVEL_EXPTOVAL
                   3409:                                        && sbbs->cfg.level_expireto[user.level]<10) {
                   3410:                                        user.flags1=sbbs->cfg.val_flags1[sbbs->cfg.level_expireto[user.level]];
                   3411:                                        user.flags2=sbbs->cfg.val_flags2[sbbs->cfg.level_expireto[user.level]];
                   3412:                                        user.flags3=sbbs->cfg.val_flags3[sbbs->cfg.level_expireto[user.level]];
                   3413:                                        user.flags4=sbbs->cfg.val_flags4[sbbs->cfg.level_expireto[user.level]];
                   3414:                                        user.exempt=sbbs->cfg.val_exempt[sbbs->cfg.level_expireto[user.level]];
                   3415:                                        user.rest=sbbs->cfg.val_rest[sbbs->cfg.level_expireto[user.level]];
                   3416:                                        if(sbbs->cfg.val_expire[sbbs->cfg.level_expireto[user.level]])
                   3417:                                                user.expire=now
                   3418:                                                        +(sbbs->cfg.val_expire[sbbs->cfg.level_expireto[user.level]]*24*60*60);
                   3419:                                        else
                   3420:                                                user.expire=0;
1.1.1.2 ! root     3421:                                        user.level=sbbs->cfg.val_level[sbbs->cfg.level_expireto[user.level]]; 
        !          3422:                                }
1.1       root     3423:                                else {
                   3424:                                        if(sbbs->cfg.level_misc[user.level]&LEVEL_EXPTOLVL)
                   3425:                                                user.level=sbbs->cfg.level_expireto[user.level];
                   3426:                                        else
                   3427:                                                user.level=sbbs->cfg.expired_level;
                   3428:                                        user.flags1&=~sbbs->cfg.expired_flags1; /* expired status */
                   3429:                                        user.flags2&=~sbbs->cfg.expired_flags2; /* expired status */
                   3430:                                        user.flags3&=~sbbs->cfg.expired_flags3; /* expired status */
                   3431:                                        user.flags4&=~sbbs->cfg.expired_flags4; /* expired status */
                   3432:                                        user.exempt&=~sbbs->cfg.expired_exempt;
                   3433:                                        user.rest|=sbbs->cfg.expired_rest;
1.1.1.2 ! root     3434:                                        user.expire=0; 
        !          3435:                                }
        !          3436:                                putuserrec(&sbbs->cfg,user.number,U_LEVEL,2,ultoa(user.level,str,10));
        !          3437:                                putuserrec(&sbbs->cfg,user.number,U_FLAGS1,8,ultoa(user.flags1,str,16));
        !          3438:                                putuserrec(&sbbs->cfg,user.number,U_FLAGS2,8,ultoa(user.flags2,str,16));
        !          3439:                                putuserrec(&sbbs->cfg,user.number,U_FLAGS3,8,ultoa(user.flags3,str,16));
        !          3440:                                putuserrec(&sbbs->cfg,user.number,U_FLAGS4,8,ultoa(user.flags4,str,16));
        !          3441:                                putuserrec(&sbbs->cfg,user.number,U_EXPIRE,8,ultoa(user.expire,str,16));
        !          3442:                                putuserrec(&sbbs->cfg,user.number,U_EXEMPT,8,ultoa(user.exempt,str,16));
        !          3443:                                putuserrec(&sbbs->cfg,user.number,U_REST,8,ultoa(user.rest,str,16));
1.1       root     3444:                                if(sbbs->cfg.expire_mod[0]) {
                   3445:                                        sbbs->useron=user;
                   3446:                                        sbbs->online=ON_LOCAL;
                   3447:                                        sbbs->exec_bin(sbbs->cfg.expire_mod,&sbbs->main_csi);
1.1.1.2 ! root     3448:                                        sbbs->online=0; 
1.1       root     3449:                                }
1.1.1.2 ! root     3450:                        }
1.1       root     3451: 
                   3452:                        /***********************************************************/
                   3453:                        /* Auto deletion based on expiration date or days inactive */
                   3454:                        /***********************************************************/
                   3455:                        if(!(user.exempt&FLAG('P'))     /* Not a permanent account */
                   3456:                                && !(user.misc&(DELETED|INACTIVE))       /* alive */
                   3457:                                && (sbbs->cfg.sys_autodel && (now-user.laston)/(long)(24L*60L*60L)
                   3458:                                > sbbs->cfg.sys_autodel)) {                     /* Inactive too long */
                   3459:                                sprintf(str,"Auto-Deleted %s #%u",user.alias,user.number);
                   3460:                                sbbs->logentry("!*",str);
1.1.1.2 ! root     3461:                                sbbs->delallmail(user.number);
        !          3462:                                putusername(&sbbs->cfg,user.number,nulstr);
        !          3463:                                putuserrec(&sbbs->cfg,user.number,U_MISC,8,ultoa(user.misc|DELETED,str,16)); 
        !          3464:                        }
1.1       root     3465:                }
                   3466: 
1.1.1.2 ! root     3467:                lprintf(LOG_INFO,"Node %d Purging deleted/expired e-mail",sbbs->cfg.node_num);
1.1       root     3468:                sprintf(sbbs->smb.file,"%smail",sbbs->cfg.data_dir);
                   3469:                sbbs->smb.retry_time=sbbs->cfg.smb_retry_time;
1.1.1.2 ! root     3470:                sbbs->smb.subnum=INVALID_SUB;
1.1       root     3471:                if((i=smb_open(&sbbs->smb))!=0)
                   3472:                        sbbs->errormsg(WHERE,ERR_OPEN,sbbs->smb.file,i,sbbs->smb.last_error);
                   3473:                else {
1.1.1.2 ! root     3474:                        if(filelength(fileno(sbbs->smb.shd_fp))>0) {
        !          3475:                                if((i=smb_locksmbhdr(&sbbs->smb))!=0)
        !          3476:                                        sbbs->errormsg(WHERE,ERR_LOCK,sbbs->smb.file,i,sbbs->smb.last_error);
        !          3477:                                else
        !          3478:                                        sbbs->delmail(0,MAIL_ALL);
        !          3479:                        }
1.1       root     3480:                        smb_close(&sbbs->smb); 
                   3481:                }
                   3482: 
                   3483:                sbbs->sys_status&=~SS_DAILY;
                   3484:                if(sbbs->cfg.sys_daily[0]) {
                   3485: //                     status("Running system daily event");
                   3486:                        sbbs->logentry("!:","Ran system daily event");
                   3487:                        sbbs->external(sbbs->cmdstr(sbbs->cfg.sys_daily,nulstr,nulstr,NULL)
                   3488:                                ,EX_OFFLINE); 
                   3489:                }
                   3490:        }
                   3491: 
1.1.1.2 ! root     3492: #if 0  /* this is handled in the event_thread now */
1.1       root     3493:        // Node Daily Event
                   3494:        sbbs->getnodedat(sbbs->cfg.node_num,&node,0);
                   3495:        if(node.misc&NODE_EVENT) {
                   3496:                sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
                   3497:                node.status=NODE_EVENT_RUNNING;
                   3498:                sbbs->putnodedat(sbbs->cfg.node_num,&node);
                   3499:                if(sbbs->cfg.node_daily[0]) {
                   3500:                        sbbs->logentry("!:","Run node daily event");
                   3501:                        sbbs->external(
                   3502:                                 sbbs->cmdstr(sbbs->cfg.node_daily,nulstr,nulstr,NULL)
                   3503:                                ,EX_OFFLINE);
                   3504:                }
                   3505:                sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
                   3506:                node.misc&=~NODE_EVENT;
                   3507:                sbbs->putnodedat(sbbs->cfg.node_num,&node); 
                   3508:        }
1.1.1.2 ! root     3509: #endif
1.1       root     3510: 
                   3511:     // Wait for all node threads to terminate
                   3512:        if(sbbs->input_thread_running || sbbs->output_thread_running) {
1.1.1.2 ! root     3513:                lprintf(LOG_INFO,"Node %d Waiting for %s to terminate..."
1.1       root     3514:                        ,sbbs->cfg.node_num
                   3515:                        ,(sbbs->input_thread_running && sbbs->output_thread_running) ?
                   3516:                        "I/O threads" : sbbs->input_thread_running
                   3517:                                ? "input thread" : "output thread");
                   3518:                time_t start=time(NULL);
                   3519:                while(sbbs->input_thread_running
                   3520:                || sbbs->output_thread_running) {
                   3521:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
1.1.1.2 ! root     3522:                                lprintf(LOG_NOTICE,"Node %d !TIMEOUT waiting for %s to terminate"
        !          3523:                                        , sbbs->cfg.node_num
1.1       root     3524:                                        ,(sbbs->input_thread_running && sbbs->output_thread_running) ?
                   3525:                                "I/O threads"
                   3526:                                        : sbbs->input_thread_running
                   3527:                                ? "input thread" : "output thread");
                   3528:                                break;
                   3529:                        }
                   3530:                        mswait(100);
                   3531:                }
                   3532:        }
                   3533: 
                   3534:        sbbs->catsyslog(0);
                   3535: 
                   3536:        status(STATUS_WFC);
                   3537: 
                   3538:        sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
                   3539:        if(node.misc&NODE_DOWN)
                   3540:                node.status=NODE_OFFLINE;
                   3541:        else
                   3542:                node.status=NODE_WFC;
1.1.1.2 ! root     3543:        node.misc&=~(NODE_DOWN|NODE_INTR|NODE_MSGW|NODE_NMSG
        !          3544:                                |NODE_UDAT|NODE_POFF|NODE_AOFF|NODE_EXT);
        !          3545: /*     node.useron=0; needed for hang-ups while in multinode chat */
1.1       root     3546:        sbbs->putnodedat(sbbs->cfg.node_num,&node);
                   3547: 
1.1.1.2 ! root     3548:        if(node_threads_running>0)
        !          3549:                node_threads_running--;
        !          3550:        lprintf(LOG_DEBUG,"Node %d thread terminated (%u node threads remain, %lu clients served)"
        !          3551:                ,sbbs->cfg.node_num, node_threads_running, served);
        !          3552:     if(!sbbs->input_thread_running && !sbbs->output_thread_running)
1.1       root     3553:                delete sbbs;
1.1.1.2 ! root     3554:     else
        !          3555:                lprintf(LOG_WARNING,"Node %d !ORPHANED I/O THREAD(s)",sbbs->cfg.node_num);
        !          3556: 
        !          3557:        update_clients();
        !          3558:        thread_down();
1.1       root     3559: }
                   3560: 
                   3561: time_t checktime(void)
                   3562: {
                   3563:        struct tm tm;
                   3564: 
                   3565:     memset(&tm,0,sizeof(tm));
                   3566:     tm.tm_year=94;
                   3567:     tm.tm_mday=1;
                   3568:     return(mktime(&tm)-0x2D24BD00L);
                   3569: }
                   3570: 
1.1.1.2 ! root     3571: const char* DLLCALL js_ver(void)
        !          3572: {
        !          3573: #ifdef JAVASCRIPT
        !          3574:        return(JS_GetImplementationVersion());
        !          3575: #else
        !          3576:        return("");
        !          3577: #endif
        !          3578: }
        !          3579: 
        !          3580: /* Returns char string of version and revision */
        !          3581: const char* DLLCALL bbs_ver(void)
1.1       root     3582: {
                   3583:        static char ver[256];
                   3584:        char compiler[32];
                   3585: 
1.1.1.2 ! root     3586:        if(ver[0]==0) { /* uninitialized */
        !          3587:                DESCRIBE_COMPILER(compiler);
1.1       root     3588: 
1.1.1.2 ! root     3589:                sprintf(ver,"%s %s%c%s  SMBLIB %s  Compiled %s %s with %s"
        !          3590:                        ,TELNET_SERVER
        !          3591:                        ,VERSION, REVISION
1.1       root     3592: #ifdef _DEBUG
1.1.1.2 ! root     3593:                        ," Debug"
1.1       root     3594: #else
1.1.1.2 ! root     3595:                        ,""
1.1       root     3596: #endif
1.1.1.2 ! root     3597:                        ,smb_lib_ver()
        !          3598:                        ,__DATE__, __TIME__, compiler
        !          3599:                        );
        !          3600:        }
1.1       root     3601:        return(ver);
                   3602: }
                   3603: 
1.1.1.2 ! root     3604: /* Returns binary-coded version and revision (e.g. 0x31000 == 3.10a) */
        !          3605: long DLLCALL bbs_ver_num(void)
        !          3606: {
        !          3607:        char*   minor;
        !          3608: 
        !          3609:        if((minor=(char *)strchr(VERSION,'.'))==NULL)
        !          3610:                return(0);
        !          3611:        minor++;
        !          3612: 
        !          3613:        return((strtoul(VERSION,NULL,16)<<16)|(strtoul(minor,NULL,16)<<8)|(REVISION-'A'));
        !          3614: }
        !          3615: 
1.1       root     3616: void DLLCALL bbs_terminate(void)
                   3617: {
1.1.1.2 ! root     3618:        lprintf(LOG_DEBUG,"BBS Server terminate",telnet_socket);
        !          3619:        terminate_server=true;
1.1       root     3620: }
                   3621: 
                   3622: static void cleanup(int code)
                   3623: {
1.1.1.2 ! root     3624:     lputs(LOG_INFO,"BBS System thread terminating");
        !          3625: 
1.1       root     3626:        if(telnet_socket!=INVALID_SOCKET) {
                   3627:                close_socket(telnet_socket);
                   3628:                telnet_socket=INVALID_SOCKET;
                   3629:        }
                   3630:        if(rlogin_socket!=INVALID_SOCKET) {
                   3631:                close_socket(rlogin_socket);
                   3632:                rlogin_socket=INVALID_SOCKET;
                   3633:        }
                   3634: 
                   3635: 
                   3636: #ifdef _WINSOCKAPI_
                   3637:        if(WSAInitialized && WSACleanup()!=0) 
1.1.1.2 ! root     3638:                lprintf(LOG_ERR,"!WSACleanup ERROR %d",ERROR_VALUE);
1.1       root     3639: #endif
                   3640: 
                   3641:        free_cfg(&scfg);
                   3642:        free_text(text);
                   3643: 
1.1.1.2 ! root     3644:        semfile_list_free(&recycle_semfiles);
        !          3645:        semfile_list_free(&shutdown_semfiles);
        !          3646: 
1.1       root     3647: #ifdef _WIN32
1.1.1.2 ! root     3648:        if(exec_mutex!=NULL) {
        !          3649:                CloseHandle(exec_mutex);
        !          3650:                exec_mutex=NULL;
        !          3651:        }
        !          3652: 
        !          3653:        if(hK32!=NULL) {
        !          3654:                FreeLibrary(hK32);
        !          3655:                hK32=NULL;
        !          3656:        }
        !          3657: 
        !          3658: #if 0 && defined(_DEBUG) && defined(_MSC_VER)
        !          3659:        _CrtMemDumpAllObjectsSince(&mem_chkpoint);
        !          3660: 
        !          3661:        if(debug_log!=INVALID_HANDLE_VALUE) {
        !          3662:                CloseHandle(debug_log);
        !          3663:                debug_log=INVALID_HANDLE_VALUE;
        !          3664:        }
        !          3665: #endif // _DEBUG && _MSC_VER
        !          3666: #endif // _WIN32
1.1       root     3667: 
                   3668:        status("Down");
                   3669:        thread_down();
1.1.1.2 ! root     3670:        if(terminate_server || code)
        !          3671:                lprintf(LOG_INFO,"BBS System thread terminated (%u threads remain, %lu clients served)"
        !          3672:                        ,thread_count, served);
        !          3673:        if(startup->terminated!=NULL)
        !          3674:                startup->terminated(startup->cbdata,code);
1.1       root     3675: }
                   3676: 
                   3677: void DLLCALL bbs_thread(void* arg)
                   3678: {
1.1.1.2 ! root     3679:        char*                   host_name;
        !          3680:        char*                   identity;
        !          3681:        char*                   p;
        !          3682:     char                       str[MAX_PATH+1];
1.1       root     3683:        char                    logstr[256];
                   3684:        SOCKADDR_IN             server_addr={0};
                   3685:        SOCKADDR_IN             client_addr;
                   3686:        socklen_t               client_addr_len;
1.1.1.2 ! root     3687:        SOCKET                  client_socket=INVALID_SOCKET;
1.1       root     3688:        fd_set                  socket_set;
                   3689:        SOCKET                  high_socket_set;
                   3690:        int                             i;
                   3691:     int                                file;
                   3692:        int                             result;
                   3693:        time_t                  t;
                   3694:        time_t                  start;
1.1.1.2 ! root     3695:        time_t                  initialized=0;
1.1       root     3696:        node_t                  node;
1.1.1.2 ! root     3697:        sbbs_t*                 events=NULL;
1.1       root     3698:        client_t                client;
                   3699:        startup=(bbs_startup_t*)arg;
1.1.1.2 ! root     3700:        BOOL                    is_client=FALSE;
        !          3701: #ifdef __unix__
        !          3702:        SOCKET  uspy_listen_socket[MAX_NODES];
        !          3703:        struct sockaddr_un uspy_addr;
        !          3704:        socklen_t               uspy_addr_len;
        !          3705: #endif
1.1       root     3706: 
                   3707:     if(startup==NULL) {
                   3708:        sbbs_beep(100,500);
                   3709:        fprintf(stderr, "No startup structure passed!\n");
                   3710:        return;
                   3711:     }
                   3712: 
                   3713:        if(startup->size!=sizeof(bbs_startup_t)) {      // verify size
                   3714:                sbbs_beep(100,500);
                   3715:                sbbs_beep(300,500);
                   3716:                sbbs_beep(100,500);
                   3717:                fprintf(stderr, "Invalid startup structure!\n");
                   3718:                return;
                   3719:        }
                   3720: 
1.1.1.2 ! root     3721: #ifdef _THREAD_SUID_BROKEN
        !          3722:        startup->seteuid(TRUE);
        !          3723: #endif
        !          3724: 
        !          3725:        /* Setup intelligent defaults */
        !          3726:        if(startup->telnet_port==0)                             startup->telnet_port=IPPORT_TELNET;
        !          3727:        if(startup->rlogin_port==0)                             startup->rlogin_port=513;
        !          3728:        if(startup->xtrn_polls_before_yield==0) startup->xtrn_polls_before_yield=10;
        !          3729: #ifdef JAVASCRIPT
        !          3730:        if(startup->js_max_bytes==0)                    startup->js_max_bytes=JAVASCRIPT_MAX_BYTES;
        !          3731:        if(startup->js_cx_stack==0)                             startup->js_cx_stack=JAVASCRIPT_CONTEXT_STACK;
        !          3732: #endif
        !          3733:        if(startup->outbuf_drain_timeout==0)    startup->outbuf_drain_timeout=10;
        !          3734:        if(startup->sem_chk_freq==0)                    startup->sem_chk_freq=2;
        !          3735:        if(startup->temp_dir[0])                                backslash(startup->temp_dir);
        !          3736: 
        !          3737:        sprintf(js_server_props.version,"%s %s%c",TELNET_SERVER,VERSION,REVISION);
        !          3738:        js_server_props.version_detail=bbs_ver();
        !          3739:        js_server_props.clients=&node_threads_running;
        !          3740:        js_server_props.options=&startup->options;
        !          3741:        js_server_props.interface_addr=&startup->telnet_interface;
        !          3742: 
        !          3743:        uptime=0;
        !          3744:        served=0;
        !          3745:        startup->recycle_now=FALSE;
        !          3746:        startup->shutdown_now=FALSE;
        !          3747:        terminate_server=false;
        !          3748: 
        !          3749:        do {
        !          3750: 
        !          3751:        thread_up(FALSE /* setuid */);
1.1       root     3752: 
                   3753:        status("Initializing");
                   3754: 
1.1.1.2 ! root     3755:        /* Defeat the lameo hex0rs - the name and copyright must remain intact */
        !          3756:        if(crc32(COPYRIGHT_NOTICE,0)!=COPYRIGHT_CRC 
        !          3757:                || crc32(VERSION_NOTICE,10)!=SYNCHRONET_CRC) {
        !          3758:                lprintf(LOG_ERR,"!CORRUPTED LIBRARY FILE");
        !          3759:                cleanup(1);
        !          3760:                return;
        !          3761:        }
1.1       root     3762: 
                   3763:        memset(text, 0, sizeof(text));
                   3764:     memset(&scfg, 0, sizeof(scfg));
                   3765: 
                   3766:        node_threads_running=0;
1.1.1.2 ! root     3767:        lastuseron[0]=0;
1.1       root     3768: 
                   3769:        char compiler[32];
1.1.1.2 ! root     3770:        DESCRIBE_COMPILER(compiler);
1.1       root     3771: 
1.1.1.2 ! root     3772:        lprintf(LOG_INFO,"%s Version %s Revision %c%s"
        !          3773:                ,TELNET_SERVER
        !          3774:                ,VERSION
        !          3775:                ,toupper(REVISION)
1.1       root     3776: #ifdef _DEBUG
                   3777:                ," Debug"
                   3778: #else
                   3779:                ,""
                   3780: #endif
                   3781:                );
1.1.1.2 ! root     3782:        lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler);
        !          3783:        lprintf(LOG_INFO,"SMBLIB %s (format %x.%02x)",smb_lib_ver(),smb_ver()>>8,smb_ver()&0xff);
1.1       root     3784: 
                   3785:     if(startup->first_node<1 || startup->first_node>startup->last_node) {
1.1.1.2 ! root     3786:        lprintf(LOG_ERR,"!ILLEGAL node configuration (first: %d, last: %d)"
1.1       root     3787:                ,startup->first_node, startup->last_node);
                   3788:                cleanup(1);
                   3789:         return;
                   3790:     }
                   3791: 
1.1.1.2 ! root     3792: #ifdef __BORLANDC__
        !          3793:        #pragma warn -8008      /* Disable "Condition always false" warning */
        !          3794:        #pragma warn -8066      /* Disable "Unreachable code" warning */
        !          3795: #endif
1.1       root     3796:        if(sizeof(node_t)!=SIZEOF_NODE_T) {
1.1.1.2 ! root     3797:                lprintf(LOG_ERR,"!COMPILER ERROR: sizeof(node_t)=%d instead of %d"
1.1       root     3798:                        ,sizeof(node_t),SIZEOF_NODE_T);
                   3799:                cleanup(1);
                   3800:                return;
                   3801:        }
                   3802: 
                   3803: #ifdef _WIN32
                   3804:     if((exec_mutex=CreateMutex(NULL,false,NULL))==NULL) {
1.1.1.2 ! root     3805:        lprintf(LOG_ERR,"!ERROR %d creating exec_mutex", GetLastError());
1.1       root     3806:                cleanup(1);
                   3807:         return;
                   3808:     }
1.1.1.2 ! root     3809:        hK32 = LoadLibrary("KERNEL32");
        !          3810: #endif // _WIN32
1.1       root     3811: 
                   3812:        if(!winsock_startup()) {
                   3813:                cleanup(1);
                   3814:                return;
                   3815:        }
                   3816: 
                   3817:        t=time(NULL);
1.1.1.2 ! root     3818:        lprintf(LOG_INFO,"Initializing on %.24s with options: %lx"
        !          3819:                ,CTIME_R(&t,str),startup->options);
        !          3820: 
        !          3821:        if(chdir(startup->ctrl_dir)!=0)
        !          3822:                lprintf(LOG_ERR,"!ERROR %d changing directory to: %s", errno, startup->ctrl_dir);
1.1       root     3823: 
                   3824:        /* Initial configuration and load from CNF files */
1.1.1.2 ! root     3825:     SAFECOPY(scfg.ctrl_dir,startup->ctrl_dir);
        !          3826:     lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir);
        !          3827:        scfg.size=sizeof(scfg);
1.1       root     3828:        scfg.node_num=startup->first_node;
1.1.1.2 ! root     3829:        SAFECOPY(logstr,UNKNOWN_LOAD_ERROR);
        !          3830:        if(!load_cfg(&scfg, text, TRUE, logstr)) {
        !          3831:                lprintf(LOG_ERR,"!ERROR %s",logstr);
        !          3832:                lprintf(LOG_ERR,"!FAILED to load configuration files");
1.1       root     3833:                cleanup(1);
                   3834:                return;
                   3835:        }
1.1.1.2 ! root     3836:        
        !          3837:        if(startup->host_name[0]==0)
        !          3838:                SAFECOPY(startup->host_name,scfg.sys_inetaddr);
        !          3839: 
        !          3840:        if(!(scfg.sys_misc&SM_LOCAL_TZ) && !(startup->options&BBS_OPT_LOCAL_TIMEZONE)) {
        !          3841:                if(putenv("TZ=UTC0"))
        !          3842:                        lprintf(LOG_ERR,"!putenv() FAILED");
        !          3843:                tzset();
        !          3844: 
        !          3845:                if((t=checktime())!=0) {   /* Check binary time */
        !          3846:                        lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t);
        !          3847:                        cleanup(1);
        !          3848:                        return;
        !          3849:                }
        !          3850:        }
        !          3851: 
        !          3852:        if(uptime==0)
        !          3853:                uptime=time(NULL);      /* this must be done *after* setting the timezone */
1.1       root     3854: 
                   3855:     if(startup->last_node>scfg.sys_nodes) {
1.1.1.2 ! root     3856:        lprintf(LOG_NOTICE,"Specified last_node (%d) > sys_nodes (%d), auto-corrected"
1.1       root     3857:                ,startup->last_node, scfg.sys_nodes);
                   3858:         startup->last_node=scfg.sys_nodes;
                   3859:     }
                   3860: 
                   3861:        /* Create missing directories */
1.1.1.2 ! root     3862:        lprintf(LOG_INFO,"Verifying/creating data directories");
1.1       root     3863:        make_data_dirs(&scfg);
                   3864: 
                   3865:        /* Create missing node directories and dsts.dab files */
1.1.1.2 ! root     3866:        lprintf(LOG_INFO,"Verifying/creating node directories");
1.1       root     3867:        for(i=0;i<=scfg.sys_nodes;i++) {
                   3868:                if(i)
                   3869:                        md(scfg.node_path[i-1]);
                   3870:                sprintf(str,"%sdsts.dab",i ? scfg.node_path[i-1] : scfg.ctrl_dir);
                   3871:                if(flength(str)<DSTSDABLEN) {
1.1.1.2 ! root     3872:                        if((file=sopen(str,O_WRONLY|O_CREAT|O_APPEND, SH_DENYNO, S_IREAD|S_IWRITE))==-1) {
        !          3873:                                lprintf(LOG_ERR,"!ERROR %d creating %s",errno, str);
1.1       root     3874:                                cleanup(1);
1.1.1.2 ! root     3875:                                return; 
        !          3876:                        }
1.1       root     3877:                        while(filelength(file)<DSTSDABLEN)
                   3878:                                if(write(file,"\0",1)!=1)
                   3879:                                        break;                          /* Create NULL system dsts.dab */
                   3880:                        close(file); 
                   3881:                } 
                   3882:        }
                   3883: 
                   3884:        /* Initial global node variables */
                   3885:        for(i=0;i<MAX_NODES;i++) {
                   3886:                node_inbuf[i]=NULL;
                   3887:        node_socket[i]=INVALID_SOCKET;
                   3888:                spy_socket[i]=INVALID_SOCKET;
1.1.1.2 ! root     3889: #ifdef __unix__
        !          3890:                uspy_socket[i]=INVALID_SOCKET;
        !          3891:                uspy_listen_socket[i]=INVALID_SOCKET;
        !          3892: #endif
1.1       root     3893:        }
                   3894: 
                   3895:        startup->node_inbuf=node_inbuf;
                   3896: 
                   3897:     /* open a socket and wait for a client */
                   3898: 
                   3899:     telnet_socket = open_socket(SOCK_STREAM);
                   3900: 
                   3901:        if(telnet_socket == INVALID_SOCKET) {
1.1.1.2 ! root     3902:                lprintf(LOG_ERR,"!ERROR %d creating Telnet socket", ERROR_VALUE);
1.1       root     3903:                cleanup(1);
                   3904:                return;
                   3905:        }
                   3906: 
1.1.1.2 ! root     3907:     lprintf(LOG_INFO,"Telnet socket %d opened",telnet_socket);
1.1       root     3908: 
                   3909:        /*****************************/
                   3910:        /* Listen for incoming calls */
                   3911:        /*****************************/
                   3912:     memset(&server_addr, 0, sizeof(server_addr));
                   3913: 
                   3914:        server_addr.sin_addr.s_addr = htonl(startup->telnet_interface);
                   3915:     server_addr.sin_family = AF_INET;
                   3916:     server_addr.sin_port   = htons(startup->telnet_port);
                   3917: 
1.1.1.2 ! root     3918:        if(startup->seteuid!=NULL)
        !          3919:                startup->seteuid(FALSE);
        !          3920:     result = retry_bind(telnet_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
        !          3921:                ,startup->bind_retry_count,startup->bind_retry_delay,"Telnet Server",lprintf);
        !          3922:        if(startup->seteuid!=NULL)
        !          3923:                startup->seteuid(TRUE);
1.1       root     3924:        if(result != 0) {
1.1.1.2 ! root     3925:                lprintf(LOG_NOTICE,"%s",BIND_FAILURE_HELP);
1.1       root     3926:                cleanup(1);
                   3927:                return;
                   3928:        }
                   3929: 
                   3930:     result = listen(telnet_socket, 1);
                   3931: 
                   3932:        if(result != 0) {
1.1.1.2 ! root     3933:                lprintf(LOG_ERR,"!ERROR %d (%d) listening on Telnet socket", result, ERROR_VALUE);
1.1       root     3934:                cleanup(1);
                   3935:                return;
                   3936:        }
1.1.1.2 ! root     3937:        lprintf(LOG_INFO,"Telnet server listening on port %d",startup->telnet_port);
1.1       root     3938: 
                   3939:        if(startup->options&BBS_OPT_ALLOW_RLOGIN) {
                   3940: 
                   3941:                /* open a socket and wait for a client */
                   3942: 
                   3943:                rlogin_socket = open_socket(SOCK_STREAM);
                   3944: 
                   3945:                if(rlogin_socket == INVALID_SOCKET) {
1.1.1.2 ! root     3946:                        lprintf(LOG_ERR,"!ERROR %d creating RLogin socket", ERROR_VALUE);
1.1       root     3947:                        cleanup(1);
                   3948:                        return;
                   3949:                }
                   3950: 
1.1.1.2 ! root     3951:                lprintf(LOG_INFO,"RLogin socket %d opened",rlogin_socket);
1.1       root     3952: 
                   3953:                /*****************************/
                   3954:                /* Listen for incoming calls */
                   3955:                /*****************************/
                   3956:                memset(&server_addr, 0, sizeof(server_addr));
                   3957: 
                   3958:                server_addr.sin_addr.s_addr = htonl(startup->rlogin_interface);
                   3959:                server_addr.sin_family = AF_INET;
                   3960:                server_addr.sin_port   = htons(startup->rlogin_port);
                   3961: 
1.1.1.2 ! root     3962:                if(startup->seteuid!=NULL)
        !          3963:                        startup->seteuid(FALSE);
        !          3964:                result = retry_bind(rlogin_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
        !          3965:                        ,startup->bind_retry_count,startup->bind_retry_delay,"RLogin Server",lprintf);
        !          3966:                if(startup->seteuid!=NULL)
        !          3967:                        startup->seteuid(TRUE);
1.1       root     3968:                if(result != 0) {
1.1.1.2 ! root     3969:                        lprintf(LOG_NOTICE,"%s",BIND_FAILURE_HELP);
1.1       root     3970:                        cleanup(1);
                   3971:                        return;
                   3972:                }
                   3973: 
                   3974:                result = listen(rlogin_socket, 1);
                   3975: 
                   3976:                if(result != 0) {
1.1.1.2 ! root     3977:                        lprintf(LOG_ERR,"!ERROR %d (%d) listening on RLogin socket", result, ERROR_VALUE);
1.1       root     3978:                        cleanup(1);
                   3979:                        return;
                   3980:                }
1.1.1.2 ! root     3981:                lprintf(LOG_INFO,"RLogin server listening on port %d",startup->rlogin_port);
1.1       root     3982:        }
                   3983: 
                   3984:        sbbs = new sbbs_t(0, server_addr.sin_addr.s_addr
1.1.1.2 ! root     3985:                ,"BBS System", telnet_socket, &scfg, text, NULL);
1.1       root     3986:     sbbs->online = 0;
                   3987:        if(sbbs->init()==false) {
1.1.1.2 ! root     3988:                lputs(LOG_ERR,"!BBS initialization failed");
1.1       root     3989:                cleanup(1);
                   3990:                return;
                   3991:        }
                   3992:        _beginthread(output_thread, 0, sbbs);
                   3993: 
1.1.1.2 ! root     3994:        if(!(startup->options&BBS_OPT_NO_EVENTS)) {
        !          3995:                events = new sbbs_t(0, server_addr.sin_addr.s_addr
        !          3996:                        ,"BBS Events", INVALID_SOCKET, &scfg, text, NULL);
        !          3997:                events->online = 0;
        !          3998:                if(events->init()==false) {
        !          3999:                        lputs(LOG_ERR,"!Events initialization failed");
        !          4000:                        cleanup(1);
        !          4001:                        return;
        !          4002:                }
        !          4003:                _beginthread(event_thread, 0, events);
1.1       root     4004:        }
                   4005: 
1.1.1.2 ! root     4006:        /* Save these values incase they're changed dynamically */
        !          4007:        first_node=startup->first_node;
        !          4008:        last_node=startup->last_node;
        !          4009: 
        !          4010:        for(i=first_node;i<=last_node;i++) {
1.1       root     4011:                sbbs->getnodedat(i,&node,1);
                   4012:                node.status=NODE_WFC;
                   4013:                node.misc&=NODE_EVENT;
                   4014:                node.action=0;
                   4015:                sbbs->putnodedat(i,&node);
                   4016:        }
                   4017: 
1.1.1.2 ! root     4018:        lprintf(LOG_INFO,"BBS System thread started for nodes %d through %d", first_node, last_node);
1.1       root     4019:        status(STATUS_WFC);
                   4020: 
1.1.1.2 ! root     4021: #if defined(_WIN32) && defined(_DEBUG) && defined(_MSC_VER)
        !          4022:        
        !          4023:        sprintf(str,"%sDEBUG.LOG",scfg.logs_dir);
        !          4024:        if((debug_log=CreateFile(
        !          4025:                str,                            // pointer to name of the file
        !          4026:                GENERIC_READ|GENERIC_WRITE,
        !          4027:                FILE_SHARE_READ|FILE_SHARE_WRITE,
        !          4028:                NULL,               // pointer to security attributes
        !          4029:                OPEN_ALWAYS,            // how to create
        !          4030:                FILE_ATTRIBUTE_NORMAL, // file attributes
        !          4031:                NULL                            // handle to file with attributes to 
        !          4032:                ))==INVALID_HANDLE_VALUE) {
        !          4033:                lprintf(LOG_ERR,"!ERROR %ld creating %s",GetLastError(),str);
        !          4034:                cleanup(1);
        !          4035:                return;
        !          4036:        }
        !          4037: 
        !          4038:        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
        !          4039:        _CrtSetReportFile(_CRT_WARN, debug_log);
        !          4040:        _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE|_CRTDBG_MODE_WNDW);
        !          4041:        _CrtSetReportFile(_CRT_ERROR, debug_log);
        !          4042:        _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE|_CRTDBG_MODE_WNDW);
        !          4043:        _CrtSetReportFile(_CRT_ASSERT, debug_log);
        !          4044: 
        !          4045:        /* Turns on memory leak checking during program termination */
        !          4046: //     _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
        !          4047: 
        !          4048:        /* Save this allocation point for comparison */
        !          4049:        _CrtMemCheckpoint(&mem_chkpoint);
        !          4050: 
        !          4051: #endif // _WIN32 && _DEBUG && _MSC_VER
        !          4052: 
        !          4053:        /* Setup recycle/shutdown semaphore file lists */
        !          4054:        semfile_list_init(&shutdown_semfiles,scfg.ctrl_dir,"shutdown","telnet");
        !          4055:        semfile_list_init(&recycle_semfiles,scfg.ctrl_dir,"recycle","telnet");
        !          4056:        SAFEPRINTF(str,"%stelnet.rec",scfg.ctrl_dir);   /* legacy */
        !          4057:        semfile_list_add(&recycle_semfiles,str);
        !          4058:        if(!initialized) {
        !          4059:                semfile_list_check(&initialized,&recycle_semfiles);
        !          4060:                semfile_list_check(&initialized,&shutdown_semfiles);
        !          4061:        }
        !          4062: 
        !          4063: #ifdef __unix__        //      unix-domain spy sockets
        !          4064:        for(i=first_node;i<=last_node && !(startup->options&BBS_OPT_NO_SPY_SOCKETS);i++)  {
        !          4065:            if((uspy_listen_socket[i-1]=socket(PF_UNIX,SOCK_STREAM,0))==INVALID_SOCKET)
        !          4066:                lprintf(LOG_ERR,"Node %d !ERROR %d creating local spy socket"
        !          4067:                    , i, errno);
        !          4068:            else {
        !          4069:                lprintf(LOG_INFO,"Node %d local spy using socket %d", i, uspy_listen_socket[i-1]);
        !          4070:                if(startup!=NULL && startup->socket_open!=NULL)
        !          4071:                    startup->socket_open(startup->cbdata,TRUE);
        !          4072:            }
        !          4073:        
        !          4074:            uspy_addr.sun_family=AF_UNIX;
        !          4075:            if((unsigned int)snprintf(str,sizeof(uspy_addr.sun_path),
        !          4076:                    "%slocalspy%d.sock", startup->temp_dir, i)
        !          4077:                    >=sizeof(uspy_addr.sun_path))
        !          4078:                uspy_listen_socket[i-1]=INVALID_SOCKET;
        !          4079:            else  {
        !          4080:                strcpy(uspy_addr.sun_path,str);
        !          4081:                if(fexist(str))
        !          4082:                    unlink(str);
        !          4083:            }
        !          4084:            if(uspy_listen_socket[i-1]!=INVALID_SOCKET) {
        !          4085:                uspy_addr_len=SUN_LEN(&uspy_addr);
        !          4086:                if(bind(uspy_listen_socket[i-1], (struct sockaddr *) &uspy_addr, uspy_addr_len)) {
        !          4087:                    lprintf(LOG_ERR,"!Node %d !ERROR %d binding local spy socket %d to %s"
        !          4088:                        , i, errno, uspy_listen_socket[i-1], uspy_addr.sun_path);
        !          4089:                    close_socket(uspy_listen_socket[i-1]);
        !          4090:                                uspy_listen_socket[i-1]=INVALID_SOCKET;
        !          4091:                    continue;
        !          4092:                }
        !          4093:             lprintf(LOG_INFO,"Node %d local spy socket %d bound to %s"
        !          4094:                 , i, uspy_listen_socket[i-1], uspy_addr.sun_path);
        !          4095:                if(listen(uspy_listen_socket[i-1],1))  {
        !          4096:                    lprintf(LOG_ERR,"Node %d !ERROR %d listening local spy socket %d", i, errno);
        !          4097:                    close_socket(uspy_listen_socket[i-1]);
        !          4098:                                uspy_listen_socket[i-1]=INVALID_SOCKET;
        !          4099:                    continue;
        !          4100:                        }
        !          4101:                uspy_addr_len=sizeof(uspy_addr);
        !          4102:            }
        !          4103:        }
        !          4104: #endif // __unix__ (unix-domain spy sockets)
        !          4105: 
1.1       root     4106:        /* signal caller that we've started up successfully */
                   4107:     if(startup->started!=NULL)
1.1.1.2 ! root     4108:        startup->started(startup->cbdata);
1.1       root     4109: 
1.1.1.2 ! root     4110: 
        !          4111:        while(!terminate_server) {
1.1       root     4112: 
                   4113:                if(node_threads_running==0) {   /* check for re-run flags */
                   4114:                        bool rerun=false;
1.1.1.2 ! root     4115:                        for(i=first_node;i<=last_node;i++) {
        !          4116:                                if(sbbs->getnodedat(i,&node,0)!=0)
        !          4117:                                        continue;
1.1       root     4118:                                if(node.misc&NODE_RRUN) {
                   4119:                                        sbbs->getnodedat(i,&node,1);
                   4120:                                        if(!rerun)
1.1.1.2 ! root     4121:                                                lprintf(LOG_INFO,"Node %d flagged for re-run",i);
1.1       root     4122:                                        rerun=true;
                   4123:                                        node.misc&=~NODE_RRUN;
                   4124:                                        sbbs->putnodedat(i,&node);
                   4125:                                }
                   4126:                        }
1.1.1.2 ! root     4127:                        if(rerun)
        !          4128:                                break;
        !          4129:                        if(!(startup->options&BBS_OPT_NO_RECYCLE)) {
        !          4130:                                if((p=semfile_list_check(&initialized,&recycle_semfiles))!=NULL) {
        !          4131:                                        lprintf(LOG_INFO,"%04d Recycle semaphore file (%s) detected"
        !          4132:                                                ,telnet_socket,p);
        !          4133:                                        break;
        !          4134:                                }
        !          4135: #if 0  /* unused */
        !          4136:                                if(startup->recycle_sem!=NULL && sem_trywait(&startup->recycle_sem)==0)
        !          4137:                                        startup->recycle_now=TRUE;
        !          4138: #endif
        !          4139:                                if(startup->recycle_now==TRUE) {
        !          4140:                                        lprintf(LOG_INFO,"%04d Recycle semaphore signaled",telnet_socket);
        !          4141:                                        startup->recycle_now=FALSE;
1.1       root     4142:                                        break;
                   4143:                                }
1.1.1.2 ! root     4144:                        }
        !          4145:                        if(((p=semfile_list_check(&initialized,&shutdown_semfiles))!=NULL
        !          4146:                                        && lprintf(LOG_INFO,"%04d Shutdown semaphore file (%s) detected"
        !          4147:                                                ,telnet_socket,p))
        !          4148:                                || (startup->shutdown_now==TRUE
        !          4149:                                        && lprintf(LOG_INFO,"%04d Shutdown semaphore signaled"
        !          4150:                                                ,telnet_socket))) {
        !          4151:                                startup->shutdown_now=FALSE;
        !          4152:                                terminate_server=TRUE;
        !          4153:                                break;
1.1       root     4154:                        }
                   4155:                }
                   4156: 
                   4157: 
                   4158:        sbbs->online=0;
                   4159: 
                   4160:                /* now wait for connection */
                   4161: 
                   4162:                FD_ZERO(&socket_set);
1.1.1.2 ! root     4163:                high_socket_set=0;
        !          4164:                if(telnet_socket!=INVALID_SOCKET) {
        !          4165:                        FD_SET(telnet_socket,&socket_set);
        !          4166:                        high_socket_set=telnet_socket+1;
        !          4167:                }
        !          4168:                if(startup->options&BBS_OPT_ALLOW_RLOGIN 
        !          4169:                        && rlogin_socket!=INVALID_SOCKET) {
1.1       root     4170:                        FD_SET(rlogin_socket,&socket_set);
                   4171:                        if(rlogin_socket+1>high_socket_set)
                   4172:                                high_socket_set=rlogin_socket+1;
                   4173:                }
1.1.1.2 ! root     4174: #ifdef __unix__
        !          4175:                for(i=first_node;i<=last_node;i++)  {
        !          4176:                        if(uspy_listen_socket[i-1]!=INVALID_SOCKET)  {
        !          4177:                                FD_SET(uspy_listen_socket[i-1],&socket_set);
        !          4178:                                if(uspy_listen_socket[i-1]+1>high_socket_set)
        !          4179:                                        high_socket_set=uspy_listen_socket[i-1]+1;
        !          4180:                        }
        !          4181:                        if(uspy_socket[i-1]!=INVALID_SOCKET)  {
        !          4182:                                FD_SET(uspy_socket[i-1],&socket_set);
        !          4183:                                if(uspy_socket[i-1]+1>high_socket_set)
        !          4184:                                        high_socket_set=uspy_listen_socket[i-1]+1;
        !          4185:                        }
        !          4186:                }
        !          4187: #endif
1.1       root     4188: 
                   4189:                struct timeval tv;
1.1.1.2 ! root     4190:                tv.tv_sec=startup->sem_chk_freq;
1.1       root     4191:                tv.tv_usec=0;
                   4192: 
                   4193:                if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
1.1.1.2 ! root     4194:                        if(i==0)
1.1       root     4195:                                continue;
                   4196:                        if(ERROR_VALUE==EINTR)
1.1.1.2 ! root     4197:                                lprintf(LOG_NOTICE,"Telnet Server listening interrupted");
1.1       root     4198:                        else if(ERROR_VALUE == ENOTSOCK)
1.1.1.2 ! root     4199:                lprintf(LOG_NOTICE,"Telnet Server sockets closed");
1.1       root     4200:                        else
1.1.1.2 ! root     4201:                                lprintf(LOG_WARNING,"!ERROR %d selecting sockets",ERROR_VALUE);
        !          4202:                        continue;
1.1       root     4203:                }
                   4204: 
1.1.1.2 ! root     4205:                if(terminate_server)    /* terminated */
        !          4206:                        break;
        !          4207: 
1.1       root     4208:                client_addr_len = sizeof(client_addr);
                   4209: 
                   4210:                bool rlogin = false;
                   4211: 
1.1.1.2 ! root     4212:                is_client=FALSE;
        !          4213:                if(telnet_socket!=INVALID_SOCKET 
        !          4214:                        && FD_ISSET(telnet_socket,&socket_set)) {
        !          4215:                        client_socket = accept_socket(telnet_socket, (struct sockaddr *)&client_addr
1.1       root     4216:                        ,&client_addr_len);
1.1.1.2 ! root     4217:                is_client=TRUE;
        !          4218:                } else if(rlogin_socket!=INVALID_SOCKET 
        !          4219:                        && FD_ISSET(rlogin_socket,&socket_set)) {
        !          4220:                        client_socket = accept_socket(rlogin_socket, (struct sockaddr *)&client_addr
1.1       root     4221:                        ,&client_addr_len);
                   4222:                        rlogin = true;
1.1.1.2 ! root     4223:                        is_client=TRUE;
1.1       root     4224:                } else {
1.1.1.2 ! root     4225: #ifdef __unix__
        !          4226:                        for(i=first_node;i<=last_node;i++)  {
        !          4227:                                if(uspy_socket[i-1]!=INVALID_SOCKET
        !          4228:                                && FD_ISSET(uspy_socket[i-1],&socket_set)) {
        !          4229:                                        if(node_socket[i-1]==INVALID_SOCKET)
        !          4230:                                                read(uspy_socket[i-1],str,sizeof(str));
        !          4231:                                        if(!socket_check(uspy_socket[i-1],NULL,NULL,0)) {
        !          4232:                                                lprintf(LOG_NOTICE,"Spy socket for node %d disconnected",i);
        !          4233:                                                close_socket(uspy_socket[i-1]);
        !          4234:                                                uspy_socket[i-1]=INVALID_SOCKET;
        !          4235:                                        }
        !          4236:                                }
        !          4237:                                if(uspy_listen_socket[i-1]!=INVALID_SOCKET
        !          4238:                                && FD_ISSET(uspy_listen_socket[i-1],&socket_set)) {
        !          4239:                                        BOOL already_connected=(uspy_socket[i-1]!=INVALID_SOCKET);
        !          4240:                                        SOCKET new_socket=INVALID_SOCKET;
        !          4241:                                        new_socket = accept(uspy_listen_socket[i-1], (struct sockaddr *)&uspy_addr
        !          4242:                                                ,&uspy_addr_len);
        !          4243:                                        if(new_socket < 0)  {
        !          4244:                                                lprintf(LOG_ERR,"!ERROR Spy socket for node %d unable to accept()",i);
        !          4245:                                                close_socket(uspy_listen_socket[i-1]);
        !          4246:                                                uspy_listen_socket[i-1]=INVALID_SOCKET;
        !          4247:                                        }
        !          4248:                                        fcntl(new_socket,F_SETFL,fcntl(new_socket,F_GETFL)|O_NONBLOCK);
        !          4249:                                        if(already_connected)  {
        !          4250:                                                lprintf(LOG_ERR,"!ERROR Spy socket %s already in use",uspy_addr.sun_path);
        !          4251:                                                send(new_socket,"Spy socket already in use.\r\n",27,0);
        !          4252:                                                close_socket(new_socket);
        !          4253:                                        }
        !          4254:                                        else  {
        !          4255:                                                lprintf(LOG_ERR,"!Spy socket %s (%d) connected",uspy_addr.sun_path,new_socket);
        !          4256:                                                uspy_socket[i-1]=new_socket;
        !          4257:                                                sprintf(str,"Spy connection established to node %d\r\n",i);
        !          4258:                                                send(uspy_socket[i-1],str,strlen(str),0);
        !          4259:                                        }
        !          4260:                                }
        !          4261:                        }
        !          4262: #else
        !          4263:                        lprintf(LOG_ERR,"!NO SOCKETS set by select");
        !          4264: #endif
1.1       root     4265:                }
                   4266: 
1.1.1.2 ! root     4267:                if(!is_client)
        !          4268:                        continue;
1.1       root     4269: 
1.1.1.2 ! root     4270:                if(client_socket == INVALID_SOCKET)     {
        !          4271: #if 0  /* is this necessary still? */
        !          4272:                        if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINTR || ERROR_VALUE == EINVAL) {
        !          4273:                lputs(LOG_NOTICE,"BBS socket closed");
        !          4274:                                break;
        !          4275:                        }
        !          4276: #endif
        !          4277:                        lprintf(LOG_ERR,"!ERROR %d accepting connection", ERROR_VALUE);
1.1       root     4278: #ifdef _WIN32
1.1.1.2 ! root     4279:                        if(WSAGetLastError()==WSAENOBUFS)       /* recycle (re-init WinSock) on this error */
        !          4280:                                break;
1.1       root     4281: #endif
1.1.1.2 ! root     4282:                        continue;
        !          4283:                }
        !          4284:                char host_ip[32];
1.1       root     4285: 
1.1.1.2 ! root     4286:                strcpy(host_ip,inet_ntoa(client_addr.sin_addr));
1.1       root     4287: 
1.1.1.2 ! root     4288:                if(trashcan(&scfg,host_ip,"ip-silent")) {
1.1       root     4289:                        close_socket(client_socket);
                   4290:                        continue;
                   4291:                }
                   4292: 
1.1.1.2 ! root     4293:                lprintf(LOG_INFO,"%04d %s connection accepted from: %s port %u"
        !          4294:                        ,client_socket
        !          4295:                        ,rlogin ? "RLogin" : "Telnet", host_ip, ntohs(client_addr.sin_port));
1.1       root     4296: 
1.1.1.2 ! root     4297: #ifdef _WIN32
        !          4298:                if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)) 
        !          4299:                        PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME);
        !          4300: #endif
1.1       root     4301: 
1.1.1.2 ! root     4302:                sbbs->client_socket=client_socket;      // required for output to the user
1.1       root     4303:         sbbs->online=ON_REMOTE;
                   4304: 
                   4305:                if(sbbs->trashcan(host_ip,"ip")) {
                   4306:                        close_socket(client_socket);
1.1.1.2 ! root     4307:                        lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can"
        !          4308:                                ,client_socket);
1.1       root     4309:                        sprintf(logstr, "Blocked IP: %s",host_ip);
1.1.1.2 ! root     4310:                        sbbs->syslog("@!",logstr);
1.1       root     4311:                        continue;
                   4312:                }
                   4313: 
1.1.1.2 ! root     4314:                if(rlogin)
1.1       root     4315:                        sbbs->outcom(0); /* acknowledge RLogin per RFC 1282 */
                   4316: 
                   4317:                sbbs->putcom(crlf);
                   4318:                sbbs->putcom(VERSION_NOTICE);
                   4319:                sbbs->putcom(crlf);
                   4320: 
                   4321:                sbbs->bprintf("Connection from: %s\r\n", host_ip);
                   4322: 
                   4323:                struct hostent* h;
                   4324:                if(startup->options&BBS_OPT_NO_HOST_LOOKUP)
                   4325:                        h=NULL;
                   4326:                else {
1.1.1.2 ! root     4327:                        sbbs->bprintf("Resolving hostname...");
1.1       root     4328:                        h=gethostbyaddr((char *)&client_addr.sin_addr
                   4329:                                ,sizeof(client_addr.sin_addr),AF_INET);
1.1.1.2 ! root     4330:                        sbbs->putcom(crlf);
1.1       root     4331:                }
                   4332:                if(h!=NULL && h->h_name!=NULL)
                   4333:                        host_name=h->h_name;
                   4334:                else
                   4335:                        host_name="<no name>";
                   4336: 
1.1.1.2 ! root     4337:                if(!(startup->options&BBS_OPT_NO_HOST_LOOKUP)) {
        !          4338:                        lprintf(LOG_INFO,"%04d Hostname: %s", client_socket, host_name);
        !          4339:                        for(i=0;h!=NULL && h->h_aliases!=NULL && h->h_aliases[i]!=NULL;i++)
        !          4340:                                lprintf(LOG_INFO,"%04d HostAlias: %s", client_socket, h->h_aliases[i]);
        !          4341:                }
1.1       root     4342: 
                   4343:                if(sbbs->trashcan(host_name,"host")) {
                   4344:                        close_socket(client_socket);
1.1.1.2 ! root     4345:                        lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in host.can",client_socket);
        !          4346:                        sprintf(logstr, "Blocked Hostname: %s",host_name);
        !          4347:                        sbbs->syslog("@!",logstr);
1.1       root     4348:                        continue;
                   4349:                }
                   4350: 
1.1.1.2 ! root     4351:                identity=NULL;
        !          4352:                if(startup->options&BBS_OPT_GET_IDENT) {
        !          4353:                        sbbs->bprintf("Resolving identity...");
        !          4354:                        identify(&client_addr, startup->telnet_port, str, sizeof(str)-1,0);
        !          4355:                        identity=strrchr(str,':');
        !          4356:                        if(identity!=NULL) {
        !          4357:                                identity++;     /* skip colon */
        !          4358:                                while(*identity && *identity<=' ') /* point to user name */
        !          4359:                                        identity++;
        !          4360:                                lprintf(LOG_INFO,"%04d Identity: %s",client_socket, identity);
        !          4361:                        }
        !          4362:                }
1.1       root     4363:                /* Initialize client display */
                   4364:                client.size=sizeof(client);
                   4365:                client.time=time(NULL);
1.1.1.2 ! root     4366:                SAFECOPY(client.addr,host_ip);
        !          4367:                SAFECOPY(client.host,host_name);
1.1       root     4368:                client.port=ntohs(client_addr.sin_port);
                   4369:                client.protocol=rlogin ? "RLogin":"Telnet";
                   4370:                client.user="<unknown>";
1.1.1.2 ! root     4371:                client_on(client_socket,&client,FALSE /* update */);
1.1       root     4372: 
1.1.1.2 ! root     4373:                for(i=first_node;i<=last_node;i++) {
        !          4374:                        /* paranoia: make sure node.status!=NODE_WFC by default */
        !          4375:                        node.status=NODE_INVALID_STATUS;        
        !          4376:                        if(sbbs->getnodedat(i,&node,1)!=0)
        !          4377:                                continue;
1.1       root     4378:                        if(node.status==NODE_WFC) {
                   4379:                                node.status=NODE_LOGON;
                   4380:                                sbbs->putnodedat(i,&node);
                   4381:                                break;
                   4382:                        }
                   4383:                        sbbs->putnodedat(i,&node);
                   4384:                }
                   4385: 
1.1.1.2 ! root     4386:                if(i>last_node) {
        !          4387:                        lprintf(LOG_WARNING,"%04d !No nodes available for login.",client_socket);
        !          4388:                        sprintf(str,"%snonodes.txt",scfg.text_dir);
        !          4389:                        if(fexist(str))
        !          4390:                                sbbs->printfile(str,P_NOABORT);
        !          4391:                        else {
        !          4392:                                sbbs->putcom("\r\nSorry, all telnet nodes are in use or otherwise unavailable.\r\n");
        !          4393:                                sbbs->putcom("Please try again later.\r\n");
        !          4394:                        }
1.1       root     4395:                        mswait(3000);
                   4396:                        client_off(client_socket);
1.1.1.2 ! root     4397:                        close_socket(client_socket);
1.1       root     4398:                        continue;
                   4399:                }
                   4400: 
                   4401:         node_socket[i-1]=client_socket;
                   4402: 
                   4403:                sbbs_t* new_node = new sbbs_t(i, client_addr.sin_addr.s_addr, host_name
1.1.1.2 ! root     4404:                ,client_socket, &scfg, text, &client);
1.1       root     4405: 
                   4406:                new_node->client=client;
                   4407: 
1.1.1.2 ! root     4408:                /* copy the IDENT response, if any */
        !          4409:                if(identity!=NULL)
        !          4410:                        SAFECOPY(new_node->client_ident,identity);
        !          4411: 
1.1       root     4412:                if(new_node->init()==false) {
1.1.1.2 ! root     4413:                        lprintf(LOG_INFO,"%04d !Node %d Initialization failure"
        !          4414:                                ,client_socket,new_node->cfg.node_num);
        !          4415:                        sprintf(str,"%snonodes.txt",scfg.text_dir);
        !          4416:                        if(fexist(str))
        !          4417:                                sbbs->printfile(str,P_NOABORT);
        !          4418:                        else 
        !          4419:                                sbbs->putcom("\r\nSorry, initialization failed. Try again later.\r\n");
1.1       root     4420:                        mswait(3000);
                   4421:                        sbbs->getnodedat(new_node->cfg.node_num,&node,1);
                   4422:                        node.status=NODE_WFC;
                   4423:                        sbbs->putnodedat(new_node->cfg.node_num,&node);
                   4424:                        delete new_node;
                   4425:                        node_socket[i-1]=INVALID_SOCKET;
                   4426:                        client_off(client_socket);
1.1.1.2 ! root     4427:                        close_socket(client_socket);
1.1       root     4428:                        continue;
                   4429:                }
                   4430: 
                   4431:                if(rlogin==true) {
                   4432:                        new_node->connection="RLogin";
                   4433:                        new_node->sys_status|=SS_RLOGIN;
1.1.1.2 ! root     4434:                        new_node->telnet_mode|=TELNET_MODE_OFF; // RLogin does not use Telnet commands
1.1       root     4435:                }
                   4436: 
1.1.1.2 ! root     4437:            node_threads_running++;
1.1       root     4438:                new_node->input_thread=(HANDLE)_beginthread(input_thread,0, new_node);
                   4439:                _beginthread(output_thread, 0, new_node);
                   4440:                _beginthread(node_thread, 0, new_node);
1.1.1.2 ! root     4441:                served++;
1.1       root     4442:        }
                   4443: 
                   4444:     // Close all open sockets
1.1.1.2 ! root     4445:     for(i=0;i<MAX_NODES;i++)  {
1.1       root     4446:        if(node_socket[i]!=INVALID_SOCKET) {
1.1.1.2 ! root     4447:                lprintf(LOG_INFO,"Closing node %d socket %d", i+1, node_socket[i]);
1.1       root     4448:                close_socket(node_socket[i]);
1.1.1.2 ! root     4449:                        node_socket[i]=INVALID_SOCKET;
1.1       root     4450:         }
1.1.1.2 ! root     4451: #ifdef __unix__
        !          4452:                if(uspy_listen_socket[i]!=INVALID_SOCKET) {
        !          4453:                        close_socket(uspy_listen_socket[i]);
        !          4454:                        uspy_listen_socket[i]=INVALID_SOCKET;
        !          4455:                        snprintf(str,sizeof(uspy_addr.sun_path),"%slocalspy%d.sock", startup->temp_dir, i+1);
        !          4456:                        if(fexist(str))
        !          4457:                                unlink(str);
        !          4458:                }
        !          4459:                if(uspy_socket[i]!=INVALID_SOCKET) {
        !          4460:                        close_socket(uspy_socket[i]);
        !          4461:                        uspy_socket[i]=INVALID_SOCKET;
        !          4462:                }               
        !          4463: #endif
        !          4464:        }
1.1       root     4465: 
                   4466:        sbbs->client_socket=INVALID_SOCKET;
1.1.1.2 ! root     4467:        if(events!=NULL)
        !          4468:                events->terminated=true;
1.1       root     4469:     // Wake-up BBS output thread so it can terminate
1.1.1.2 ! root     4470:     sem_post(&sbbs->outbuf.sem);
1.1       root     4471: 
                   4472:     // Wait for all node threads to terminate
                   4473:        if(node_threads_running) {
1.1.1.2 ! root     4474:                lprintf(LOG_INFO,"Waiting for %d node threads to terminate...", node_threads_running);
1.1       root     4475:                start=time(NULL);
                   4476:                while(node_threads_running) {
                   4477:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
1.1.1.2 ! root     4478:                                lprintf(LOG_ERR,"!TIMEOUT waiting for %d node thread(s) to "
1.1       root     4479:                        "terminate", node_threads_running);
                   4480:                                break;
                   4481:                        }
                   4482:                        mswait(100);
                   4483:                }
                   4484:        }
                   4485: 
                   4486:        // Wait for Events thread to terminate
1.1.1.2 ! root     4487:        if(events!=NULL && events->event_thread_running) {
        !          4488:                lprintf(LOG_INFO,"Waiting for event thread to terminate...");
1.1       root     4489:                start=time(NULL);
                   4490:                while(events->event_thread_running) {
                   4491:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
1.1.1.2 ! root     4492:                                lprintf(LOG_ERR,"!TIMEOUT waiting for BBS event thread to "
1.1       root     4493:                        "terminate");
                   4494:                                break;
                   4495:                        }
                   4496:                        mswait(100);
                   4497:                }
                   4498:        }
                   4499: 
                   4500:     // Wait for BBS output thread to terminate
                   4501:        if(sbbs->output_thread_running) {
1.1.1.2 ! root     4502:                lprintf(LOG_INFO,"Waiting for system output thread to terminate...");
1.1       root     4503:                start=time(NULL);
                   4504:                while(sbbs->output_thread_running) {
                   4505:                        if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
1.1.1.2 ! root     4506:                                lprintf(LOG_ERR,"!TIMEOUT waiting for BBS output thread to "
1.1       root     4507:                        "terminate");
                   4508:                                break;
                   4509:                        }
                   4510:                        mswait(100);
                   4511:                }
                   4512:        }
                   4513: 
                   4514:     // Set all nodes' status to OFFLINE
1.1.1.2 ! root     4515:     for(i=first_node;i<=last_node;i++) {
1.1       root     4516:         sbbs->getnodedat(i,&node,1);
                   4517:         node.status=NODE_OFFLINE;
                   4518:         sbbs->putnodedat(i,&node);
                   4519:     }
                   4520: 
1.1.1.2 ! root     4521:        if(events!=NULL && !events->event_thread_running)
1.1       root     4522:                delete events;
                   4523: 
                   4524:     if(!sbbs->output_thread_running)
                   4525:            delete sbbs;
                   4526: 
                   4527:        cleanup(0);
1.1.1.2 ! root     4528: 
        !          4529:        if(!terminate_server) {
        !          4530:                lprintf(LOG_INFO,"Recycling server...");
        !          4531:                mswait(2000);
        !          4532:                if(startup->recycle!=NULL)
        !          4533:                        startup->recycle(startup->cbdata);
        !          4534:        }
        !          4535: 
        !          4536:        } while(!terminate_server);
        !          4537: 
1.1       root     4538: }
                   4539: 
                   4540: 
                   4541: 

unix.superglobalmegacorp.com

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