|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.