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