|
|
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.