|
|
1.1 root 1: /* chat.cpp */
2:
3: /* Synchronet real-time chat functions */
4:
5: /* $Id: chat.cpp,v 1.47 2006/08/23 01:45:05 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 2006 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: #include "sbbs.h"
39:
40: #define PCHAT_LEN 1000 /* Size of Private chat file */
41:
42: const char *weekday[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"
43: ,"Saturday"};
44: const char *month[]={"January","February","March","April","May","June"
45: ,"July","August","September","October","November","December"};
46:
47: /****************************************************************************/
48: /****************************************************************************/
49: void sbbs_t::multinodechat(int channel)
50: {
51: char line[256],str[256],ch,done
52: ,usrs,preusrs,qusrs,*gurubuf=NULL,savch,*p
53: ,pgraph[400],buf[400]
54: ,usr[MAX_NODES],preusr[MAX_NODES],qusr[MAX_NODES];
55: char guru_lastanswer[512];
56: char tmp[512];
57: int file;
58: long i,j,k,n;
59: node_t node;
60:
61: if(useron.rest&FLAG('C')) {
62: bputs(text[R_Chat]);
63: return;
64: }
65:
66: if(channel<1 || channel>cfg.total_chans)
67: channel=1;
68:
69: if(!chan_access(channel-1))
70: return;
71: if(useron.misc&(RIP|WIP|HTML) ||!(useron.misc&EXPERT))
72: menu("multchat");
73: bputs(text[WelcomeToMultiChat]);
74: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
75: thisnode.aux=channel;
76: putnodedat(cfg.node_num,&thisnode);
77: }
78: bprintf(text[WelcomeToChannelN],channel,cfg.chan[channel-1]->name);
79: if(gurubuf) {
80: free(gurubuf);
81: gurubuf=NULL; }
82: if(cfg.chan[channel-1]->misc&CHAN_GURU && cfg.chan[channel-1]->guru<cfg.total_gurus
83: && chk_ar(cfg.guru[cfg.chan[channel-1]->guru]->ar,&useron)) {
84: sprintf(str,"%s%s.dat",cfg.ctrl_dir,cfg.guru[cfg.chan[channel-1]->guru]->code);
85: if((file=nopen(str,O_RDONLY))==-1) {
86: errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
87: return; }
88: if((gurubuf=(char *)malloc(filelength(file)+1))==NULL) {
89: close(file);
90: errormsg(WHERE,ERR_ALLOC,str,filelength(file)+1);
91: return; }
92: read(file,gurubuf,filelength(file));
93: gurubuf[filelength(file)]=0;
94: close(file); }
95: usrs=0;
96: for(i=1;i<=cfg.sys_nodes && i<=cfg.sys_lastnode;i++) {
97: if(i==cfg.node_num)
98: continue;
99: getnodedat(i,&node,0);
100: if(node.action!=NODE_MCHT || node.status!=NODE_INUSE)
101: continue;
102: if(node.aux && (node.aux&0xff)!=channel)
103: continue;
104: printnodedat(i,&node);
105: preusr[usrs]=usr[usrs++]=(char)i; }
106: preusrs=usrs;
107: if(gurubuf)
108: bprintf(text[NodeInMultiChatLocally]
109: ,cfg.sys_nodes+1,cfg.guru[cfg.chan[channel-1]->guru]->name,channel);
110: bputs(text[YoureOnTheAir]);
111: done=0;
112: while(online && !done) {
113: checkline();
114: gettimeleft();
115: action=NODE_MCHT;
116: qusrs=usrs=0;
117: for(i=1;i<=cfg.sys_nodes;i++) {
118: if(i==cfg.node_num)
119: continue;
120: getnodedat(i,&node,0);
121: if(node.action!=NODE_MCHT
122: || (node.aux && channel && (node.aux&0xff)!=channel))
123: continue;
124: if(node.status==NODE_QUIET)
125: qusr[qusrs++]=(char)i;
126: else if(node.status==NODE_INUSE)
127: usr[usrs++]=(char)i; }
128: if(preusrs>usrs) {
129: if(!usrs && channel && cfg.chan[channel-1]->misc&CHAN_GURU
130: && cfg.chan[channel-1]->guru<cfg.total_gurus)
131: bprintf(text[NodeJoinedMultiChat]
132: ,cfg.sys_nodes+1,cfg.guru[cfg.chan[channel-1]->guru]->name
133: ,channel);
134: outchar(BEL);
135: for(i=0;i<preusrs;i++) {
136: for(j=0;j<usrs;j++)
137: if(preusr[i]==usr[j])
138: break;
139: if(j==usrs) {
140: getnodedat(preusr[i],&node,0);
141: if(node.misc&NODE_ANON)
142: sprintf(str,"%.80s",text[UNKNOWN_USER]);
143: else
144: username(&cfg,node.useron,str);
145: bprintf(text[NodeLeftMultiChat]
146: ,preusr[i],str,channel); } } }
147: else if(preusrs<usrs) {
148: if(!preusrs && channel && cfg.chan[channel-1]->misc&CHAN_GURU
149: && cfg.chan[channel-1]->guru<cfg.total_gurus)
150: bprintf(text[NodeLeftMultiChat]
151: ,cfg.sys_nodes+1,cfg.guru[cfg.chan[channel-1]->guru]->name
152: ,channel);
153: outchar(BEL);
154: for(i=0;i<usrs;i++) {
155: for(j=0;j<preusrs;j++)
156: if(usr[i]==preusr[j])
157: break;
158: if(j==preusrs) {
159: getnodedat(usr[i],&node,0);
160: if(node.misc&NODE_ANON)
161: sprintf(str,"%.80s",text[UNKNOWN_USER]);
162: else
163: username(&cfg,node.useron,str);
164: bprintf(text[NodeJoinedMultiChat]
165: ,usr[i],str,channel); } } }
166: preusrs=usrs;
167: for(i=0;i<usrs;i++)
168: preusr[i]=usr[i];
169: attr(cfg.color[clr_multichat]);
170: SYNC;
171: sys_status&=~SS_ABORT;
172: if((ch=inkey(K_NONE,250))!=0 || wordwrap[0]) {
173: if(ch=='/') {
174: bputs(text[MultiChatCommandPrompt]);
175: strcpy(str,"ACELWQ?*");
176: if(SYSOP)
177: strcat(str,"0");
178: i=getkeys(str,cfg.total_chans);
179: if(i&0x80000000L) { /* change channel */
180: savch=(char)(i&~0x80000000L);
181: if(savch==channel)
182: continue;
183: if(!chan_access(savch-1))
184: continue;
185: bprintf(text[WelcomeToChannelN]
186: ,savch,cfg.chan[savch-1]->name);
187:
188: usrs=0;
189: for(i=1;i<=cfg.sys_nodes;i++) {
190: if(i==cfg.node_num)
191: continue;
192: getnodedat(i,&node,0);
193: if(node.action!=NODE_MCHT
194: || node.status!=NODE_INUSE)
195: continue;
196: if(node.aux && (node.aux&0xff)!=savch)
197: continue;
198: printnodedat(i,&node);
199: if(node.aux&0x1f00) { /* password */
200: bprintf(text[PasswordProtected]
201: ,node.misc&NODE_ANON
202: ? text[UNKNOWN_USER]
203: : username(&cfg,node.useron,tmp));
204: if(!getstr(str,8,K_UPPER|K_ALPHA|K_LINE))
205: break;
206: if(strcmp(str,unpackchatpass(tmp,&node)))
207: break;
208: bputs(text[CorrectPassword]); }
209: preusr[usrs]=usr[usrs++]=(char)i; }
210: if(i<=cfg.sys_nodes) { /* failed password */
211: bputs(text[WrongPassword]);
212: continue; }
213: if(gurubuf) {
214: free(gurubuf);
215: gurubuf=NULL; }
216: if(cfg.chan[savch-1]->misc&CHAN_GURU
217: && cfg.chan[savch-1]->guru<cfg.total_gurus
218: && chk_ar(cfg.guru[cfg.chan[savch-1]->guru]->ar,&useron
219: )) {
220: sprintf(str,"%s%s.dat",cfg.ctrl_dir
221: ,cfg.guru[cfg.chan[savch-1]->guru]->code);
222: if((file=nopen(str,O_RDONLY))==-1) {
223: errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
224: break; }
225: if((gurubuf=(char *)malloc(filelength(file)+1))==NULL) {
226: close(file);
227: errormsg(WHERE,ERR_ALLOC,str
228: ,filelength(file)+1);
229: break; }
230: read(file,gurubuf,filelength(file));
231: gurubuf[filelength(file)]=0;
232: close(file); }
233: preusrs=usrs;
234: if(gurubuf)
235: bprintf(text[NodeInMultiChatLocally]
236: ,cfg.sys_nodes+1
237: ,cfg.guru[cfg.chan[savch-1]->guru]->name
238: ,savch);
239: channel=savch;
240: if(!usrs && cfg.chan[savch-1]->misc&CHAN_PW
241: && !noyes(text[PasswordProtectChanQ])) {
242: bputs(text[PasswordPrompt]);
243: if(getstr(str,8,K_UPPER|K_ALPHA|K_LINE)) {
244: getnodedat(cfg.node_num,&thisnode,true);
245: thisnode.aux=channel;
246: packchatpass(str,&thisnode); }
247: else {
248: getnodedat(cfg.node_num,&thisnode,true);
249: thisnode.aux=channel; } }
250: else {
251: getnodedat(cfg.node_num,&thisnode,true);
252: thisnode.aux=channel; }
253: putnodedat(cfg.node_num,&thisnode);
254: bputs(text[YoureOnTheAir]);
255: if(cfg.chan[channel-1]->cost
256: && !(useron.exempt&FLAG('J')))
257: subtract_cdt(&cfg,&useron,cfg.chan[channel-1]->cost); }
258: else switch(i) { /* other command */
259: case '0': /* Global channel */
260: if(!SYSOP)
261: break;
262: usrs=0;
263: for(i=1;i<=cfg.sys_nodes;i++) {
264: if(i==cfg.node_num)
265: continue;
266: getnodedat(i,&node,0);
267: if(node.action!=NODE_MCHT
268: || node.status!=NODE_INUSE)
269: continue;
270: printnodedat(i,&node);
271: preusr[usrs]=usr[usrs++]=(char)i; }
272: preusrs=usrs;
273: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
274: thisnode.aux=channel=0;
275: putnodedat(cfg.node_num,&thisnode);
276: }
277: break;
278: case 'A': /* Action commands */
279: useron.chat^=CHAT_ACTION;
280: bprintf("\r\nAction commands are now %s\r\n"
281: ,useron.chat&CHAT_ACTION
282: ? text[ON]:text[OFF]);
283: putuserrec(&cfg,useron.number,U_CHAT,8
284: ,ultoa(useron.chat,str,16));
285: break;
286: case 'C': /* List of action commands */
287: CRLF;
288: for(i=0;channel && i<cfg.total_chatacts;i++) {
289: if(cfg.chatact[i]->actset
290: !=cfg.chan[channel-1]->actset)
291: continue;
292: bprintf("%-*.*s",LEN_CHATACTCMD
293: ,LEN_CHATACTCMD,cfg.chatact[i]->cmd);
294: if(!((i+1)%8)) {
295: CRLF; }
296: else
297: bputs(" "); }
298: CRLF;
299: break;
300: case 'E': /* Toggle echo */
301: useron.chat^=CHAT_ECHO;
302: bprintf(text[EchoIsNow]
303: ,useron.chat&CHAT_ECHO
304: ? text[ON]:text[OFF]);
305: putuserrec(&cfg,useron.number,U_CHAT,8
306: ,ultoa(useron.chat,str,16));
307: break;
308: case 'L': /* list nodes */
309: CRLF;
310: for(i=1;i<=cfg.sys_nodes && i<=cfg.sys_lastnode;i++) {
311: getnodedat(i,&node,0);
312: printnodedat(i,&node); }
313: CRLF;
314: break;
315: case 'W': /* page node(s) */
316: j=getnodetopage(0,0);
317: if(!j)
318: break;
319: for(i=0;i<usrs;i++)
320: if(usr[i]==j)
321: break;
322: if(i>=usrs) {
323: bputs(text[UserNotFound]);
324: break; }
325:
326: bputs(text[NodeMsgPrompt]);
327: if(!getstr(line,66,K_LINE|K_MSG))
328: break;
329:
330: sprintf(buf,text[ChatLineFmt]
331: ,thisnode.misc&NODE_ANON
332: ? text[AnonUserChatHandle]
333: : useron.handle
334: ,cfg.node_num,'*',line);
335: strcat(buf,crlf);
336: if(useron.chat&CHAT_ECHO)
337: bputs(buf);
338: putnmsg(&cfg,j,buf);
339: break;
340: case 'Q': /* quit */
341: done=1;
342: break;
343: case '*':
344: sprintf(str,"%smenu/chan.*",cfg.text_dir);
345: if(fexist(str))
346: menu("chan");
347: else {
348: bputs(text[ChatChanLstHdr]);
349: bputs(text[ChatChanLstTitles]);
350: if(cfg.total_chans>=10) {
351: bputs(" ");
352: bputs(text[ChatChanLstTitles]); }
353: CRLF;
354: bputs(text[ChatChanLstUnderline]);
355: if(cfg.total_chans>=10) {
356: bputs(" ");
357: bputs(text[ChatChanLstUnderline]); }
358: CRLF;
359: if(cfg.total_chans>=10)
360: j=(cfg.total_chans/2)+(cfg.total_chans&1);
361: else
362: j=cfg.total_chans;
363: for(i=0;i<j && !msgabort();i++) {
364: bprintf(text[ChatChanLstFmt],i+1
365: ,cfg.chan[i]->name
366: ,cfg.chan[i]->cost);
367: if(cfg.total_chans>=10) {
368: k=(cfg.total_chans/2)
369: +i+(cfg.total_chans&1);
370: if(k<cfg.total_chans) {
371: bputs(" ");
372: bprintf(text[ChatChanLstFmt]
373: ,k+1
374: ,cfg.chan[k]->name
375: ,cfg.chan[k]->cost); } }
376: CRLF; }
377: CRLF; }
378: break;
379: case '?': /* menu */
380: menu("multchat");
381: break;
382: }
383: } else {
384: ungetkey(ch);
385: j=0;
386: pgraph[0]=0;
387: while(j<5) {
388: if(!getstr(line,66,K_WRAP|K_MSG|K_CHAT))
389: break;
390: if(j) {
391: sprintf(str,text[ChatLineFmt]
392: ,thisnode.misc&NODE_ANON
393: ? text[AnonUserChatHandle]
394: : useron.handle
395: ,cfg.node_num,':',nulstr);
396: sprintf(tmp,"%*s",bstrlen(str),nulstr);
397: strcat(pgraph,tmp); }
398: strcat(pgraph,line);
399: strcat(pgraph,crlf);
400: if(!wordwrap[0])
401: break;
402: j++; }
403: if(pgraph[0]) {
404: if(channel && useron.chat&CHAT_ACTION) {
405: for(i=0;i<cfg.total_chatacts;i++) {
406: if(cfg.chatact[i]->actset
407: !=cfg.chan[channel-1]->actset)
408: continue;
409: sprintf(str,"%s ",cfg.chatact[i]->cmd);
410: if(!strnicmp(str,pgraph,strlen(str)))
411: break;
412: sprintf(str,"%.*s"
413: ,LEN_CHATACTCMD+2,pgraph);
414: str[strlen(str)-2]=0;
415: if(!stricmp(cfg.chatact[i]->cmd,str))
416: break; }
417:
418: if(i<cfg.total_chatacts) {
419: p=pgraph+strlen(str);
420: n=atoi(p);
421: for(j=0;j<usrs;j++) {
422: getnodedat(usr[j],&node,0);
423: if(usrs==1) /* no need to search */
424: break;
425: if(n) {
426: if(usr[j]==n)
427: break;
428: continue; }
429: username(&cfg,node.useron,str);
430: if(!strnicmp(str,p,strlen(str)))
431: break;
432: getuserrec(&cfg,node.useron,U_HANDLE
433: ,LEN_HANDLE,str);
434: if(!strnicmp(str,p,strlen(str)))
435: break; }
436: if(!usrs
437: && cfg.chan[channel-1]->guru<cfg.total_gurus)
438: strcpy(str
439: ,cfg.guru[cfg.chan[channel-1]->guru]->name);
440: else if(j>=usrs)
441: strcpy(str,"everyone");
442: else if(node.misc&NODE_ANON)
443: strcpy(str,text[UNKNOWN_USER]);
444: else
445: username(&cfg,node.useron,str);
446:
447: /* Display on same node */
448: bprintf(cfg.chatact[i]->out
449: ,thisnode.misc&NODE_ANON
450: ? text[UNKNOWN_USER] : useron.alias
451: ,str);
452: CRLF;
453:
454: if(usrs && j<usrs) {
455: /* Display to dest user */
456: sprintf(buf,cfg.chatact[i]->out
457: ,thisnode.misc&NODE_ANON
458: ? text[UNKNOWN_USER] : useron.alias
459: ,"you");
460: strcat(buf,crlf);
461: putnmsg(&cfg,usr[j],buf); }
462:
463:
464: /* Display to all other users */
465: sprintf(buf,cfg.chatact[i]->out
466: ,thisnode.misc&NODE_ANON
467: ? text[UNKNOWN_USER] : useron.alias
468: ,str);
469: strcat(buf,crlf);
470:
471: for(i=0;i<usrs;i++) {
472: if(i==j)
473: continue;
474: getnodedat(usr[i],&node,0);
475: putnmsg(&cfg,usr[i],buf); }
476: for(i=0;i<qusrs;i++) {
477: getnodedat(qusr[i],&node,0);
478: putnmsg(&cfg,qusr[i],buf); }
479: continue; } }
480:
481: sprintf(buf,text[ChatLineFmt]
482: ,thisnode.misc&NODE_ANON
483: ? text[AnonUserChatHandle]
484: : useron.handle
485: ,cfg.node_num,':',pgraph);
486: if(useron.chat&CHAT_ECHO)
487: bputs(buf);
488: for(i=0;i<usrs;i++) {
489: getnodedat(usr[i],&node,0);
490: putnmsg(&cfg,usr[i],buf);
491: }
492: for(i=0;i<qusrs;i++) {
493: getnodedat(qusr[i],&node,0);
494: putnmsg(&cfg,qusr[i],buf);
495: }
496: if(!usrs && channel && gurubuf
497: && cfg.chan[channel-1]->misc&CHAN_GURU)
498: guruchat(pgraph,gurubuf,cfg.chan[channel-1]->guru,guru_lastanswer);
499: }
500: }
501: }
502: if(sys_status&SS_ABORT)
503: break;
504: }
505: lncntr=0;
506: }
507:
508: /****************************************************************************/
509: /****************************************************************************/
510: bool sbbs_t::guru_page(void)
511: {
512: char path[MAX_PATH+1];
513: char* gurubuf;
514: int file;
515: long i;
516:
517: if(useron.rest&FLAG('C')) {
518: bputs(text[R_Chat]);
519: return(false);
520: }
521:
522: if(!cfg.total_gurus) {
523: bprintf(text[SysopIsNotAvailable],"The Guru");
524: return(false);
525: }
526: if(cfg.total_gurus==1 && chk_ar(cfg.guru[0]->ar,&useron))
527: i=0;
528: else {
529: for(i=0;i<cfg.total_gurus;i++)
530: uselect(1,i,nulstr,cfg.guru[i]->name,cfg.guru[i]->ar);
531: i=uselect(0,0,0,0,0);
532: if(i<0)
533: return(false);
534: }
535: sprintf(path,"%s%s.dat",cfg.ctrl_dir,cfg.guru[i]->code);
536: if((file=nopen(path,O_RDONLY))==-1) {
537: errormsg(WHERE,ERR_OPEN,path,O_RDONLY);
538: return(false);
539: }
540: if((gurubuf=(char *)malloc(filelength(file)+1))==NULL) {
541: close(file);
542: errormsg(WHERE,ERR_ALLOC,path,filelength(file)+1);
543: return(false);
544: }
545: read(file,gurubuf,filelength(file));
546: gurubuf[filelength(file)]=0;
547: close(file);
548: localguru(gurubuf,i);
549: free(gurubuf);
550: return(true);
551: }
552:
553: /****************************************************************************/
554: /* The chat section */
555: /****************************************************************************/
556: void sbbs_t::chatsection()
557: {
558: char str[256],ch,no_rip_menu;
559:
560: if(useron.rest&FLAG('C')) {
561: bputs(text[R_Chat]);
562: return;
563: }
564:
565: action=NODE_CHAT;
566: if(useron.misc&(RIP|WIP|HTML) || !(useron.misc&EXPERT))
567: menu("chat");
568: ASYNC;
569: bputs(text[ChatPrompt]);
570: while(online) {
571: no_rip_menu=0;
572: ch=(char)getkeys("ACDJPQST?\r",0);
573: if(ch>' ')
574: logch(ch,0);
575: switch(ch) {
576: case 'S':
577: useron.chat^=CHAT_SPLITP;
578: putuserrec(&cfg,useron.number,U_CHAT,8
579: ,ultoa(useron.chat,str,16));
580: bprintf("\r\nPrivate split-screen chat is now: %s\r\n"
581: ,useron.chat&CHAT_SPLITP ? text[ON]:text[OFF]);
582: break;
583: case 'A':
584: CRLF;
585: useron.chat^=CHAT_NOACT;
586: putuserrec(&cfg,useron.number,U_CHAT,8
587: ,ultoa(useron.chat,str,16));
588: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
589: thisnode.misc^=NODE_AOFF;
590: printnodedat(cfg.node_num,&thisnode);
591: }
592: putnodedat(cfg.node_num,&thisnode);
593: no_rip_menu=true;
594: break;
595: case 'D':
596: CRLF;
597: useron.chat^=CHAT_NOPAGE;
598: putuserrec(&cfg,useron.number,U_CHAT,8
599: ,ultoa(useron.chat,str,16));
600: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
601: thisnode.misc^=NODE_POFF;
602: printnodedat(cfg.node_num,&thisnode);
603: }
604: putnodedat(cfg.node_num,&thisnode);
605: no_rip_menu=true;
606: break;
607: case 'J':
608: multinodechat();
609: break;
610: case 'P': /* private node-to-node chat */
611: privchat();
612: break;
613: case 'C':
614: no_rip_menu=1;
615: if(sysop_page())
616: break;
617: if(cfg.total_gurus && chk_ar(cfg.guru[0]->ar,&useron)) {
618: sprintf(str,text[ChatWithGuruInsteadQ],cfg.guru[0]->name);
619: if(!yesno(str))
620: break; }
621: else
622: break;
623: /* FALL-THROUGH */
624: case 'T':
625: guru_page();
626: no_rip_menu=1;
627: break;
628: case '?':
629: if(useron.misc&EXPERT)
630: menu("chat");
631: break;
632: default: /* 'Q' or <CR> */
633: lncntr=0;
634: // if(gurubuf)
635: // free(gurubuf);
636: return; }
637: action=NODE_CHAT;
638: if(!(useron.misc&EXPERT) || useron.misc&(WIP|HTML)
639: || (useron.misc&RIP && !no_rip_menu)) {
640: menu("chat");
641: }
642: ASYNC;
643: bputs(text[ChatPrompt]); }
644: // if(gurubuf)
645: // free(gurubuf);
646: }
647:
648: /****************************************************************************/
649: /****************************************************************************/
650: bool sbbs_t::sysop_page(void)
651: {
652: char str[256];
653: int i;
654:
655: if(useron.rest&FLAG('C')) {
656: bputs(text[R_Chat]);
657: return(false);
658: }
659:
660: if(startup->options&BBS_OPT_SYSOP_AVAILABLE
661: || (cfg.sys_chat_ar[0] && chk_ar(cfg.sys_chat_ar,&useron))
662: || useron.exempt&FLAG('C')) {
663:
664: sprintf(str,"%s paged sysop for chat",useron.alias);
665: logline("C",str);
666:
667: for(i=0;i<cfg.total_pages;i++)
668: if(chk_ar(cfg.page[i]->ar,&useron))
669: break;
670: if(i<cfg.total_pages) {
671: bprintf(text[PagingGuru],cfg.sys_op);
672: external(cmdstr(cfg.page[i]->cmd,nulstr,nulstr,NULL)
673: ,cfg.page[i]->misc&IO_INTS ? EX_OUTL|EX_OUTR|EX_INR
674: : EX_OUTL); }
675: else if(cfg.sys_misc&SM_SHRTPAGE) {
676: bprintf(text[PagingGuru],cfg.sys_op);
677: for(i=0;i<10 && !lkbrd(1);i++) {
678: sbbs_beep(1000,200);
679: mswait(200);
680: outchar('.'); }
681: CRLF; }
682: else {
683: sys_status^=SS_SYSPAGE;
684: bprintf(text[SysopPageIsNow]
685: ,sys_status&SS_SYSPAGE ? text[ON] : text[OFF]);
686: nosound();
687: }
688:
689: return(true);
690: }
691:
692: bprintf(text[SysopIsNotAvailable],cfg.sys_op);
693:
694: return(false);
695: }
696:
697: /****************************************************************************/
698: /* Returns 1 if user online has access to channel "channum" */
699: /****************************************************************************/
700: bool sbbs_t::chan_access(uint cnum)
701: {
702:
703: if(!cfg.total_chans || cnum>=cfg.total_chans || !chk_ar(cfg.chan[cnum]->ar,&useron)) {
704: bputs(text[CantAccessThatChannel]);
705: return(false); }
706: if(!(useron.exempt&FLAG('J')) && cfg.chan[cnum]->cost>useron.cdt+useron.freecdt) {
707: bputs(text[NotEnoughCredits]);
708: return(false); }
709: return(true);
710: }
711:
712: /****************************************************************************/
713: /* Private split-screen (or interspersed) chat with node or local sysop */
714: /****************************************************************************/
715: void sbbs_t::privchat(bool local)
716: {
717: char str[128],c,*p,localbuf[5][81],remotebuf[5][81]
718: ,localline=0,remoteline=0,localchar=0,remotechar=0
719: ,*sep=text[PrivateChatSeparator]
720: ,*local_sep=text[SysopChatSeparator]
721: ;
722: char tmp[512];
723: char outpath[MAX_PATH+1];
724: char inpath[MAX_PATH+1];
725: uchar ch;
726: int in,out,i,n,echo=1,x,y,activity,remote_activity;
727: int local_y=1,remote_y=1;
728: node_t node;
729: time_t last_nodechk=0;
730:
731: if(useron.rest&FLAG('C')) {
732: bputs(text[R_Chat]);
733: return;
734: }
735:
736: if(local)
737: n=0;
738: else {
739: n=getnodetopage(0,0);
740: if(!n)
741: return;
742: if(n==cfg.node_num) {
743: bputs(text[NoNeedToPageSelf]);
744: return; }
745: getnodedat(n,&node,0);
746: if(node.action==NODE_PCHT && node.aux!=cfg.node_num) {
747: bprintf(text[NodeNAlreadyInPChat],n);
748: return; }
749: if((node.action!=NODE_PAGE || node.aux!=cfg.node_num)
750: && node.misc&NODE_POFF && !SYSOP) {
751: bprintf(text[CantPageNode],node.misc&NODE_ANON
752: ? text[UNKNOWN_USER] : username(&cfg,node.useron,tmp));
753: return; }
754: if(node.action!=NODE_PAGE) {
755: bprintf(text[PagingUser]
756: ,node.misc&NODE_ANON ? text[UNKNOWN_USER] : username(&cfg,node.useron,tmp)
757: ,node.misc&NODE_ANON ? 0 : node.useron);
758: sprintf(str,text[NodePChatPageMsg]
759: ,cfg.node_num,thisnode.misc&NODE_ANON
760: ? text[UNKNOWN_USER] : useron.alias);
761: putnmsg(&cfg,n,str);
762: sprintf(str,"%s paged %s on node %d to private chat"
763: ,useron.alias,username(&cfg,node.useron,tmp),n);
764: logline("C",str); }
765:
766: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
767: thisnode.action=action=NODE_PAGE;
768: thisnode.aux=n;
769: putnodedat(cfg.node_num,&thisnode);
770: }
771:
772: if(node.action!=NODE_PAGE || node.aux!=cfg.node_num) {
773: bprintf(text[WaitingForNodeInPChat],n);
774: while(online && !(sys_status&SS_ABORT)) {
775: getnodedat(n,&node,0);
776: if((node.action==NODE_PAGE || node.action==NODE_PCHT)
777: && node.aux==cfg.node_num) {
778: bprintf(text[NodeJoinedPrivateChat]
779: ,n,node.misc&NODE_ANON ? text[UNKNOWN_USER]
780: : username(&cfg,node.useron,tmp));
781: break;
782: }
783: action=NODE_PAGE;
784: checkline();
785: gettimeleft();
786: SYNC;
787: inkey(K_NONE,500);
788: }
789: }
790: }
791:
792: gettimeleft();
793:
794: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
795: thisnode.action=action=NODE_PCHT;
796: thisnode.aux=n;
797: thisnode.misc&=~NODE_LCHAT;
798: putnodedat(cfg.node_num,&thisnode);
799: }
800:
801: if(!online || sys_status&SS_ABORT)
802: return;
803:
804: if(((sys_status&SS_USERON && useron.chat&CHAT_SPLITP) || !(sys_status&SS_USERON))
805: && term_supports(ANSI) && rows>=24)
806: sys_status|=SS_SPLITP;
807: else
808: sys_status&=~SS_SPLITP;
809: /*
810: if(!(useron.misc&EXPERT))
811: menu("privchat");
812: */
813:
814: if(!(sys_status&SS_SPLITP)) {
815: if(local)
816: bprintf(text[SysopIsHere],cfg.sys_op);
817: else
818: bputs(text[WelcomeToPrivateChat]);
819: }
820:
821: sprintf(outpath,"%schat.dab",cfg.node_dir);
822: if((out=sopen(outpath,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,S_IREAD|S_IWRITE))==-1) {
823: errormsg(WHERE,ERR_OPEN,outpath,O_RDWR|O_DENYNONE|O_CREAT);
824: return;
825: }
826:
827: if(local)
828: sprintf(inpath,"%slchat.dab",cfg.node_dir);
829: else
830: sprintf(inpath,"%schat.dab",cfg.node_path[n-1]);
831: if(!fexist(inpath)) /* Wait while it's created for the first time */
832: mswait(2000);
833: if((in=sopen(inpath,O_RDWR|O_CREAT|O_BINARY,SH_DENYNO,S_IREAD|S_IWRITE))==-1) {
834: close(out);
835: errormsg(WHERE,ERR_OPEN,str,O_RDWR|O_DENYNONE|O_CREAT);
836: return; }
837:
838: if((p=(char *)malloc(PCHAT_LEN))==NULL) {
839: close(in);
840: close(out);
841: errormsg(WHERE,ERR_ALLOC,str,PCHAT_LEN);
842: return; }
843: memset(p,0,PCHAT_LEN);
844: write(in,p,PCHAT_LEN);
845: write(out,p,PCHAT_LEN);
846: free(p);
847: lseek(in,0L,SEEK_SET);
848: lseek(out,0L,SEEK_SET);
849:
850: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
851: thisnode.misc&=~NODE_RPCHT; /* Clear "reset pchat flag" */
852: putnodedat(cfg.node_num,&thisnode);
853: }
854:
855: if(!local) {
856: if(getnodedat(n,&node,true)==0) {
857: node.misc|=NODE_RPCHT; /* Set "reset pchat flag" */
858: putnodedat(n,&node); /* on other node */
859: }
860:
861: /* Wait for other node */
862: /* to acknowledge and reset */
863: while(online && !(sys_status&SS_ABORT)) {
864: getnodedat(n,&node,0);
865: if(!(node.misc&NODE_RPCHT))
866: break;
867: getnodedat(cfg.node_num,&thisnode,0);
868: if(thisnode.misc&NODE_RPCHT)
869: break;
870: checkline();
871: gettimeleft();
872: SYNC;
873: SLEEP(500);
874: }
875: }
876:
877: action=NODE_PCHT;
878: SYNC;
879:
880: if(sys_status&SS_SPLITP) {
881: lncntr=0;
882: CLS;
883: ANSI_SAVE();
884: #if 0
885: if(local)
886: bprintf(text[SysopIsHere],cfg.sys_op);
887: #endif
888: GOTOXY(1,13);
889: remote_y=1;
890: bprintf(local ? local_sep : sep
891: ,thisnode.misc&NODE_MSGW ? 'T':' '
892: ,sectostr(timeleft,tmp)
893: ,thisnode.misc&NODE_NMSG ? 'M':' ');
894: CRLF;
895: local_y=14; }
896:
897: while(online && (local || !(sys_status&SS_ABORT))) {
898: lncntr=0;
899: if(sys_status&SS_SPLITP)
900: lbuflen=0;
901: action=NODE_PCHT;
902: activity=0;
903: remote_activity=0;
904: if((ch=inkey(K_GETSTR,100))!=0) {
905: activity=1;
906: if(echo)
907: attr(cfg.color[clr_chatlocal]);
908: if(ch==BS || ch==DEL) {
909: if(localchar) {
910: if(echo)
911: backspace();
912: localchar--;
913: localbuf[localline][localchar]=0; } }
914: else if(ch==TAB) {
915: if(echo)
916: outchar(' ');
917: localbuf[localline][localchar]=' ';
918: localchar++;
919: while(localchar<78 && localchar%8) {
920: if(echo)
921: outchar(' ');
922: localbuf[localline][localchar++]=' '; } }
923: else if(ch==CTRL_R) {
924: if(sys_status&SS_SPLITP) {
925: CLS;
926: attr(cfg.color[clr_chatremote]);
927: remotebuf[remoteline][remotechar]=0;
928: for(i=0;i<=remoteline;i++) {
929: bputs(remotebuf[i]);
930: if(i!=remoteline)
931: bputs(crlf);
932: }
933: remote_y=1+remoteline;
934: bputs("\1i_\1n"); /* Fake cursor */
935: ANSI_SAVE();
936: GOTOXY(1,13);
937: bprintf(local ? local_sep : sep
938: ,thisnode.misc&NODE_MSGW ? 'T':' '
939: ,sectostr(timeleft,tmp)
940: ,thisnode.misc&NODE_NMSG ? 'M':' ');
941: CRLF;
942: attr(cfg.color[clr_chatlocal]);
943: localbuf[localline][localchar]=0;
944: for(i=0;i<=localline;i++) {
945: bputs(localbuf[i]);
946: if(i!=localline)
947: bputs(crlf);
948: }
949: local_y=15+localline;
950: }
951: continue;
952: }
953: else if(ch>=' ' || ch==CR) {
954: if(ch!=CR) {
955: if(echo)
956: outchar(ch);
957: localbuf[localline][localchar]=ch; }
958:
959: if(ch==CR || (localchar>68 && ch==' ') || ++localchar>78) {
960:
961: localbuf[localline][localchar]=0;
962: localchar=0;
963:
964: if(sys_status&SS_SPLITP && local_y==24) {
965: GOTOXY(1,13);
966: bprintf(local ? local_sep : sep
967: ,thisnode.misc&NODE_MSGW ? 'T':' '
968: ,sectostr(timeleft,tmp)
969: ,thisnode.misc&NODE_NMSG ? 'M':' ');
970: attr(cfg.color[clr_chatlocal]);
971: for(x=13,y=0;x<rows;x++,y++) {
972: rprintf("\x1b[%d;1H\x1b[K",x+1);
973: if(y<=localline)
974: bprintf("%s\r\n",localbuf[y]); }
975: GOTOXY(1,local_y=(15+localline));
976: localline=0; }
977: else {
978: if(localline>=4)
979: for(i=0;i<4;i++)
980: memcpy(localbuf[i],localbuf[i+1],81);
981: else
982: localline++;
983: if(echo) {
984: CRLF;
985: local_y++;
986: if(sys_status&SS_SPLITP)
987: cleartoeol();
988: }
989: }
990: // SYNC;
991: }
992: }
993:
994: read(out,&c,1);
995: lseek(out,-1L,SEEK_CUR);
996: if(!c) /* hasn't wrapped */
997: write(out,&ch,1);
998: else {
999: if(!tell(out))
1000: lseek(out,0L,SEEK_END);
1001: lseek(out,-1L,SEEK_CUR);
1002: ch=0;
1003: write(out,&ch,1);
1004: lseek(out,-1L,SEEK_CUR);
1005: }
1006: utime(outpath,NULL); /* update mod time for NFS/smbfs nodes */
1007: if(tell(out)>=PCHAT_LEN)
1008: lseek(out,0L,SEEK_SET);
1009: }
1010: else while(online) {
1011: if(!(sys_status&SS_SPLITP))
1012: remotechar=localchar;
1013: if(tell(in)>=PCHAT_LEN)
1014: lseek(in,0L,SEEK_SET);
1015: ch=0;
1016: utime(inpath,NULL);
1017: read(in,&ch,1);
1018: lseek(in,-1L,SEEK_CUR);
1019: if(!ch) break; /* char from other node */
1020: activity=1;
1021: if(sys_status&SS_SPLITP && !remote_activity) {
1022: ansi_getxy(&x,&y);
1023: ANSI_RESTORE();
1024: }
1025: attr(cfg.color[clr_chatremote]);
1026: if(sys_status&SS_SPLITP && !remote_activity)
1027: backspace(); /* Delete fake cursor */
1028: remote_activity=1;
1029: if(ch==BS || ch==DEL) {
1030: if(remotechar) {
1031: backspace();
1032: remotechar--;
1033: remotebuf[remoteline][remotechar]=0; } }
1034: else if(ch==TAB) {
1035: outchar(' ');
1036: remotebuf[remoteline][remotechar]=' ';
1037: remotechar++;
1038: while(remotechar<78 && remotechar%8) {
1039: outchar(' ');
1040: remotebuf[remoteline][remotechar++]=' '; } }
1041: else if(ch>=' ' || ch==CR) {
1042: if(ch!=CR) {
1043: outchar(ch);
1044: remotebuf[remoteline][remotechar]=ch; }
1045:
1046: if(ch==CR || (remotechar>68 && ch==' ') || ++remotechar>78) {
1047:
1048: remotebuf[remoteline][remotechar]=0;
1049: remotechar=0;
1050:
1051: if(sys_status&SS_SPLITP && remote_y==12) {
1052: CRLF;
1053: bprintf(local ? local_sep : sep
1054: ,thisnode.misc&NODE_MSGW ? 'T':' '
1055: ,sectostr(timeleft,tmp)
1056: ,thisnode.misc&NODE_NMSG ? 'M':' ');
1057: attr(cfg.color[clr_chatremote]);
1058: for(i=0;i<12;i++) {
1059: bprintf("\x1b[%d;1H\x1b[K",i+1);
1060: if(i<=remoteline)
1061: bprintf("%s\r\n",remotebuf[i]); }
1062: remoteline=0;
1063: GOTOXY(1, remote_y=6); }
1064: else {
1065: if(remoteline>=4)
1066: for(i=0;i<4;i++)
1067: memcpy(remotebuf[i],remotebuf[i+1],81);
1068: else
1069: remoteline++;
1070: if(echo) {
1071: CRLF;
1072: remote_y++;
1073: if(sys_status&SS_SPLITP)
1074: cleartoeol();
1075: }
1076: }
1077: }
1078: }
1079: ch=0;
1080: write(in,&ch,1);
1081:
1082: if(!(sys_status&SS_SPLITP))
1083: localchar=remotechar;
1084: }
1085:
1086: if(sys_status&SS_SPLITP && remote_activity) {
1087: bputs("\1i_\1n"); /* Fake cursor */
1088: ANSI_SAVE();
1089: GOTOXY(x,y);
1090: }
1091:
1092: now=time(NULL);
1093: if(!activity && now!=last_nodechk) { /* no activity so chk node.dab */
1094:
1095: if(!localchar) {
1096: if(sys_status&SS_SPLITP) {
1097: getnodedat(cfg.node_num,&thisnode,0);
1098: if(thisnode.misc&NODE_INTR)
1099: break;
1100: if(thisnode.misc&NODE_UDAT && !(useron.rest&FLAG('G'))) {
1101: getuserdat(&cfg,&useron);
1102: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
1103: thisnode.misc&=~NODE_UDAT;
1104: putnodedat(cfg.node_num,&thisnode);
1105: }
1106: }
1107: }
1108: else
1109: nodesync();
1110: }
1111:
1112: if(!local) {
1113: getnodedat(n,&node,0);
1114: if((node.action!=NODE_PCHT && node.action!=NODE_PAGE)
1115: || node.aux!=cfg.node_num) {
1116: bprintf(text[NodeLeftPrivateChat]
1117: ,n,node.misc&NODE_ANON ? text[UNKNOWN_USER]
1118: : username(&cfg,node.useron,tmp));
1119: break;
1120: }
1121: }
1122: getnodedat(cfg.node_num,&thisnode,0);
1123: if(thisnode.action!=NODE_PCHT) {
1124: action=thisnode.action;
1125: bputs(text[EndOfChat]);
1126: break;
1127: }
1128: if(thisnode.misc&NODE_RPCHT) { /* pchat has been reset */
1129: lseek(in,0L,SEEK_SET); /* so seek to beginning */
1130: lseek(out,0L,SEEK_SET);
1131: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
1132: thisnode.misc&=~NODE_RPCHT;
1133: putnodedat(cfg.node_num,&thisnode);
1134: }
1135: }
1136: last_nodechk=now;
1137: gettimeleft();
1138: }
1139: }
1140: if(sys_status&SS_SPLITP)
1141: CLS;
1142: sys_status&=~(SS_SPLITP|SS_ABORT);
1143: close(in);
1144: close(out);
1145: }
1146:
1147:
1148: int sbbs_t::getnodetopage(int all, int telegram)
1149: {
1150: char str[128];
1151: char tmp[512];
1152: uint i,j;
1153: ulong l;
1154: node_t node;
1155:
1156: if(!lastnodemsg)
1157: lastnodemsguser[0]=0;
1158: if(lastnodemsg) {
1159: getnodedat(lastnodemsg,&node,0);
1160: if(node.status!=NODE_INUSE && !SYSOP)
1161: lastnodemsg=1; }
1162: for(j=0,i=1;i<=cfg.sys_nodes && i<=cfg.sys_lastnode;i++) {
1163: getnodedat(i,&node,0);
1164: if(i==cfg.node_num)
1165: continue;
1166: if(node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET)) {
1167: if(!lastnodemsg)
1168: lastnodemsg=i;
1169: j++; } }
1170:
1171: if(!lastnodemsguser[0])
1172: sprintf(lastnodemsguser,"%u",lastnodemsg);
1173:
1174: if(!j && !telegram) {
1175: bputs(text[NoOtherActiveNodes]);
1176: return(0); }
1177:
1178: if(all)
1179: sprintf(str,text[NodeToSendMsgTo],lastnodemsg);
1180: else
1181: sprintf(str,text[NodeToPrivateChat],lastnodemsg);
1182: mnemonics(str);
1183:
1184: strcpy(str,lastnodemsguser);
1185: getstr(str,LEN_ALIAS,K_UPRLWR|K_LINE|K_EDIT|K_AUTODEL);
1186: if(sys_status&SS_ABORT)
1187: return(0);
1188: if(!str[0])
1189: return(0);
1190:
1191: j=atoi(str);
1192: if(j && j<=cfg.sys_lastnode && j<=cfg.sys_nodes) {
1193: getnodedat(j,&node,0);
1194: if(node.status!=NODE_INUSE && !SYSOP) {
1195: bprintf(text[NodeNIsNotInUse],j);
1196: return(0); }
1197: if(telegram && node.misc&(NODE_POFF|NODE_ANON) && !SYSOP) {
1198: bprintf(text[CantPageNode],node.misc&NODE_ANON
1199: ? text[UNKNOWN_USER] : username(&cfg,node.useron,tmp));
1200: return(0); }
1201: strcpy(lastnodemsguser,str);
1202: if(telegram)
1203: return(node.useron);
1204: return(j); }
1205: if(all && !stricmp(str,"ALL"))
1206: return(-1);
1207:
1208: if(str[0]=='\'') {
1209: j=userdatdupe(0,U_HANDLE,LEN_HANDLE,str+1,0);
1210: if(!j) {
1211: bputs(text[UnknownUser]);
1212: return(0); } }
1213: else if(str[0]=='#')
1214: j=atoi(str+1);
1215: else
1216: j=finduser(str);
1217: if(!j)
1218: return(0);
1219: if(j>lastuser(&cfg))
1220: return(0);
1221: getuserrec(&cfg,j,U_MISC,8,tmp);
1222: l=ahtoul(tmp);
1223: if(l&(DELETED|INACTIVE)) { /* Deleted or Inactive User */
1224: bputs(text[UnknownUser]);
1225: return(0); }
1226:
1227: for(i=1;i<=cfg.sys_nodes && i<=cfg.sys_lastnode;i++) {
1228: getnodedat(i,&node,0);
1229: if((node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET))
1230: && node.useron==j) {
1231: if(telegram && node.misc&NODE_POFF && !SYSOP) {
1232: bprintf(text[CantPageNode],node.misc&NODE_ANON
1233: ? text[UNKNOWN_USER] : username(&cfg,node.useron,tmp));
1234: return(0); }
1235: if(telegram)
1236: return(j);
1237: strcpy(lastnodemsguser,str);
1238: return(i); } }
1239: if(telegram) {
1240: strcpy(lastnodemsguser,str);
1241: return(j); }
1242: bputs(text[UserNotFound]);
1243: return(0);
1244: }
1245:
1246:
1247: /****************************************************************************/
1248: /* Sending single line messages between nodes */
1249: /****************************************************************************/
1250: void sbbs_t::nodemsg()
1251: {
1252: char str[256],line[256],buf[512],logbuf[512],ch=0;
1253: char tmp[512];
1254: int i,usernumber,done=0;
1255: node_t node,savenode;
1256:
1257: if(nodemsg_inside>1) /* nested once only */
1258: return;
1259: sys_status|=SS_IN_CTRLP;
1260: getnodedat(cfg.node_num,&savenode,0);
1261: nodemsg_inside++;
1262: wordwrap[0]=0;
1263: while(online && !done) {
1264: if(useron.rest&FLAG('C')) {
1265: bputs(text[R_SendMessages]);
1266: break;
1267: }
1268: SYNC;
1269: mnemonics(text[PrivateMsgPrompt]);
1270: sys_status&=~SS_ABORT;
1271: while(online) { /* Watch for incoming messages */
1272: ch=toupper(inkey(K_NONE,1000));
1273: if(ch && strchr("TMCQ\r",ch))
1274: break;
1275: if(sys_status&SS_ABORT)
1276: break;
1277: if(getnodedat(cfg.node_num,&thisnode,false)==0) {
1278: if(thisnode.misc&(NODE_MSGW|NODE_NMSG)) {
1279: lncntr=0; /* prevent pause prompt */
1280: SAVELINE;
1281: CRLF;
1282: if(thisnode.misc&NODE_NMSG)
1283: getnmsg();
1284: if(thisnode.misc&NODE_MSGW)
1285: getsmsg(useron.number);
1286: CRLF;
1287: RESTORELINE; }
1288: else
1289: nodesync();
1290: }
1291: gettimeleft();
1292: }
1293:
1294: if(!online || sys_status&SS_ABORT) {
1295: sys_status&=~SS_ABORT;
1296: CRLF;
1297: break;
1298: }
1299:
1300: switch(toupper(ch)) {
1301: case 'T': /* Telegram */
1302: bputs("Telegram\r\n");
1303: usernumber=getnodetopage(0,1);
1304: if(!usernumber)
1305: break;
1306:
1307: if(usernumber==1 && useron.rest&FLAG('S')) { /* ! val fback */
1308: bprintf(text[R_Feedback],cfg.sys_op);
1309: break; }
1310: if(usernumber!=1 && useron.rest&FLAG('E')) {
1311: bputs(text[R_Email]);
1312: break; }
1313: now=time(NULL);
1314: bprintf(text[SendingTelegramToUser]
1315: ,username(&cfg,usernumber,tmp),usernumber);
1316: sprintf(buf,text[TelegramFmt]
1317: ,thisnode.misc&NODE_ANON ? text[UNKNOWN_USER] : useron.alias
1318: ,timestr(&now));
1319: i=0;
1320: logbuf[0]=0;
1321: while(online && i<5) {
1322: bprintf("%4s",nulstr);
1323: if(!getstr(line,70,K_WRAP|K_MSG))
1324: break;
1325: sprintf(str,"%4s%s\r\n",nulstr,line);
1326: strcat(buf,str);
1327: if(line[0]) {
1328: if(i)
1329: strcat(logbuf," ");
1330: strcat(logbuf,line);
1331: }
1332: i++; }
1333: if(!i)
1334: break;
1335: if(sys_status&SS_ABORT) {
1336: CRLF;
1337: break; }
1338: putsmsg(&cfg,usernumber,buf);
1339: sprintf(str,"%s sent telegram to %s #%u"
1340: ,useron.alias,username(&cfg,usernumber,tmp),usernumber);
1341: logline("C",str);
1342: logline(nulstr,logbuf);
1343: bprintf(text[MsgSentToUser],"Telegram"
1344: ,username(&cfg,usernumber,tmp),usernumber);
1345: break;
1346: case 'M': /* Message */
1347: bputs("Message\r\n");
1348: i=getnodetopage(1,0);
1349: if(!i)
1350: break;
1351: if(i!=-1) {
1352: getnodedat(i,&node,0);
1353: usernumber=node.useron;
1354: if(node.misc&NODE_POFF && !SYSOP)
1355: bprintf(text[CantPageNode],node.misc&NODE_ANON
1356: ? text[UNKNOWN_USER] : username(&cfg,node.useron,tmp));
1357: else {
1358: bprintf(text[SendingMessageToUser]
1359: ,node.misc&NODE_ANON ? text[UNKNOWN_USER]
1360: : username(&cfg,node.useron,tmp)
1361: ,node.misc&NODE_ANON ? 0 : node.useron);
1362: bputs(text[NodeMsgPrompt]);
1363: if(!getstr(line,69,K_LINE))
1364: break;
1365: sprintf(buf,text[NodeMsgFmt],cfg.node_num
1366: ,thisnode.misc&NODE_ANON
1367: ? text[UNKNOWN_USER] : useron.alias,line);
1368: putnmsg(&cfg,i,buf);
1369: if(!(node.misc&NODE_ANON))
1370: bprintf(text[MsgSentToUser],"Message"
1371: ,username(&cfg,usernumber,tmp),usernumber);
1372: sprintf(str,"%s sent message to %s on node %d:"
1373: ,useron.alias,username(&cfg,usernumber,tmp),i);
1374: logline("C",str);
1375: logline(nulstr,line); } }
1376: else { /* ALL */
1377: bputs(text[NodeMsgPrompt]);
1378: if(!getstr(line,70,K_LINE))
1379: break;
1380: sprintf(buf,text[AllNodeMsgFmt],cfg.node_num
1381: ,thisnode.misc&NODE_ANON
1382: ? text[UNKNOWN_USER] : useron.alias,line);
1383: for(i=1;i<=cfg.sys_nodes;i++) {
1384: if(i==cfg.node_num)
1385: continue;
1386: getnodedat(i,&node,0);
1387: if((node.status==NODE_INUSE
1388: || (SYSOP && node.status==NODE_QUIET))
1389: && (SYSOP || !(node.misc&NODE_POFF)))
1390: putnmsg(&cfg,i,buf); }
1391: sprintf(str,"%s sent message to all nodes",useron.alias);
1392: logline("C",str);
1393: logline(nulstr,line);
1394: }
1395: break;
1396: case 'C': /* Chat */
1397: bputs("Chat\r\n");
1398: if(action==NODE_PCHT) { /* already in pchat */
1399: done=1;
1400: break; }
1401: privchat();
1402: action=savenode.action;
1403: break;
1404: default:
1405: bputs("Quit\r\n");
1406: done=1;
1407: break; } }
1408: nodemsg_inside--;
1409: if(!nodemsg_inside)
1410: sys_status&=~SS_IN_CTRLP;
1411: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
1412: thisnode.action=action=savenode.action;
1413: thisnode.aux=savenode.aux;
1414: thisnode.extaux=savenode.extaux;
1415: putnodedat(cfg.node_num,&thisnode);
1416: }
1417: }
1418:
1419: /****************************************************************************/
1420: /* The guru will respond from the 'guru' buffer to 'line' */
1421: /****************************************************************************/
1422: void sbbs_t::guruchat(char* line, char* gurubuf, int gurunum, char* last_answer)
1423: {
1424: char str[512],cstr[512],*ptr,*answer[100],theanswer[1024]
1425: ,mistakes=1,hu=0;
1426: char tmp[512];
1427: int file;
1428: uint c,i,j,k,answers;
1429: long len;
1430: struct tm tm;
1431:
1432: now=time(NULL);
1433: localtime_r(&now,&tm);
1434:
1435: for(i=0;i<100;i++) {
1436: if((answer[i]=(char *)malloc(512))==NULL) {
1437: errormsg(WHERE,ERR_ALLOC,nulstr,512);
1438: while(i) {
1439: i--;
1440: free(answer[i]); }
1441: sys_status&=~SS_GURUCHAT;
1442: return; } }
1443: ptr=gurubuf;
1444: len=strlen(gurubuf);
1445: strupr(line);
1446: j=strlen(line);
1447: k=0;
1448: for(i=0;i<j;i++) {
1449: if(!isalnum(line[i]) && !k) /* beginning non-alphanumeric */
1450: continue;
1451: if(!isalnum(line[i]) && line[i]==line[i+1]) /* redundant non-alnum */
1452: continue;
1453: if(!isalnum(line[i]) && line[i+1]=='?') /* fix "WHAT ?" */
1454: continue;
1455: cstr[k++]=line[i]; }
1456: cstr[k]=0;
1457: while(k) {
1458: k--;
1459: if(!isalnum(cstr[k]))
1460: continue;
1461: break; }
1462: if(k<1) {
1463: for(i=0;i<100;i++)
1464: free(answer[i]);
1465: return; }
1466: if(cstr[k+1]=='?')
1467: k++;
1468: cstr[k+1]=0;
1469: while(*ptr && ptr<gurubuf+len) {
1470: if(*ptr=='(') {
1471: ptr++;
1472: if(!guruexp(&ptr,cstr)) {
1473: while(*ptr && *ptr!='(' && ptr<gurubuf+len)
1474: ptr++;
1475: continue; } }
1476: else {
1477: while(*ptr && *ptr!=LF && ptr<gurubuf+len) /* skip LF after ')' */
1478: ptr++;
1479: ptr++;
1480: answers=0;
1481: while(*ptr && answers<100 && ptr<gurubuf+len) {
1482: i=0;
1483: while(*ptr && *ptr!=CR && *ptr!=LF && i<511 && ptr<gurubuf+len) {
1484: answer[answers][i]=*ptr;
1485: ptr++;
1486: i++;
1487: /* multi-line answer */
1488: if(*ptr=='\\' && (*(ptr+1)==CR || *(ptr+1)==LF)) {
1489: ptr++; /* skip \ */
1490: while(*ptr && *ptr<' ') ptr++; /* skip [CR]LF */
1491: answer[answers][i++]=CR;
1492: answer[answers][i++]=LF; } }
1493: answer[answers][i]=0;
1494: if(!strlen(answer[answers]) || answer[answers][0]=='(') {
1495: ptr-=strlen(answer[answers]);
1496: break; }
1497: while(*ptr && *ptr<' ') ptr++; /* skip [CR]LF */
1498: answers++; }
1499: if(answers==100)
1500: while(*ptr && *ptr!='(' && ptr<gurubuf+len)
1501: ptr++;
1502: /* Try to not repeat yourself */
1503: for(j=0;j<answers;j++) {
1504: i=sbbs_random(answers);
1505: if(stricmp(answer[i],last_answer))
1506: break;
1507: }
1508: strcpy(last_answer,answer[i]);
1509: for(j=0,k=0;answer[i][j];j++) {
1510: if(answer[i][j]=='`') {
1511: j++;
1512: theanswer[k]=0;
1513: switch(toupper(answer[i][j])) {
1514: case 'A':
1515: if(sys_status&SS_USERON)
1516: strcat(theanswer,useron.alias);
1517: else
1518: strcat(theanswer,text[UNKNOWN_USER]);
1519: break;
1520: case 'B':
1521: if(sys_status&SS_USERON)
1522: strcat(theanswer,useron.birth);
1523: else
1524: strcat(theanswer,"00/00/00");
1525: break;
1526: case 'C':
1527: if(sys_status&SS_USERON)
1528: strcat(theanswer,useron.comp);
1529: else
1530: strcat(theanswer,"PC Jr.");
1531: break;
1532: case 'D':
1533: if(sys_status&SS_USERON)
1534: strcat(theanswer,ultoac(useron.dlb,tmp));
1535: else
1536: strcat(theanswer,"0");
1537: break;
1538: case 'G':
1539: strcat(theanswer,cfg.guru[gurunum]->name);
1540: break;
1541: case 'H':
1542: hu=1;
1543: break;
1544: case 'I':
1545: strcat(theanswer,cfg.sys_id);
1546: break;
1547: case 'J':
1548: sprintf(tmp,"%u",tm.tm_mday);
1549: break;
1550: case 'L':
1551: if(sys_status&SS_USERON)
1552: strcat(theanswer,ultoa(useron.level,tmp,10));
1553: else
1554: strcat(theanswer,"0");
1555: break;
1556: case 'M':
1557: strcat(theanswer,month[tm.tm_mon]);
1558: break;
1559: case 'N': /* Note */
1560: if(sys_status&SS_USERON)
1561: strcat(theanswer,useron.note);
1562: else
1563: strcat(theanswer,text[UNKNOWN_USER]);
1564: break;
1565: case 'O':
1566: strcat(theanswer,cfg.sys_op);
1567: break;
1568: case 'P':
1569: if(sys_status&SS_USERON)
1570: strcat(theanswer,useron.phone);
1571: else
1572: strcat(theanswer,"000-000-0000");
1573: break;
1574: case 'Q':
1575: sys_status&=~SS_GURUCHAT;
1576: break;
1577: case 'R':
1578: if(sys_status&SS_USERON)
1579: strcat(theanswer,useron.name);
1580: else
1581: strcat(theanswer,text[UNKNOWN_USER]);
1582: break;
1583: case 'S':
1584: strcat(theanswer,cfg.sys_name);
1585: break;
1586: case 'T':
1587: sprintf(tmp,"%u:%02u",tm.tm_hour>12 ? tm.tm_hour-12
1588: : tm.tm_hour,tm.tm_min);
1589: strcat(theanswer,tmp);
1590: break;
1591: case 'U':
1592: if(sys_status&SS_USERON)
1593: strcat(theanswer,ultoac(useron.ulb,tmp));
1594: else
1595: strcat(theanswer,"0");
1596: break;
1597: case 'W':
1598: strcat(theanswer,weekday[tm.tm_wday]);
1599: break;
1600: case 'Y': /* Current year */
1601: sprintf(tmp,"%u",1900+tm.tm_year);
1602: strcat(theanswer,tmp);
1603: break;
1604: case 'Z':
1605: if(sys_status&SS_USERON)
1606: strcat(theanswer,useron.zipcode);
1607: else
1608: strcat(theanswer,"90210");
1609: break;
1610: case '$': /* Credits */
1611: if(sys_status&SS_USERON)
1612: strcat(theanswer,ultoac(useron.cdt,tmp));
1613: else
1614: strcat(theanswer,"0");
1615: break;
1616: case '#':
1617: if(sys_status&SS_USERON)
1618: strcat(theanswer,ultoa(getage(&cfg,useron.birth)
1619: ,tmp,10));
1620: else
1621: strcat(theanswer,"0");
1622: break;
1623: case '!':
1624: mistakes=!mistakes;
1625: break;
1626: case '_':
1627: mswait(500);
1628: break; }
1629: k=strlen(theanswer); }
1630: else
1631: theanswer[k++]=answer[i][j]; }
1632: theanswer[k]=0;
1633: mswait(500+sbbs_random(1000)); /* thinking time */
1634: if(action!=NODE_MCHT) {
1635: for(i=0;i<k;i++) {
1636: if(mistakes && theanswer[i]!=theanswer[i-1] &&
1637: ((!isalnum(theanswer[i]) && !sbbs_random(100))
1638: || (isalnum(theanswer[i]) && !sbbs_random(30)))) {
1639: c=j=((uint)sbbs_random(3)+1); /* 1 to 3 chars */
1640: if(c<strcspn(theanswer+(i+1),"\0., "))
1641: c=j=1;
1642: while(j) {
1643: outchar(97+sbbs_random(26));
1644: mswait(25+sbbs_random(150));
1645: j--; }
1646: if(sbbs_random(100)) {
1647: mswait(100+sbbs_random(300));
1648: while(c) {
1649: backspace();
1650: mswait(50+sbbs_random(50));
1651: c--; } } }
1652: outchar(theanswer[i]);
1653: if(theanswer[i]==theanswer[i+1])
1654: mswait(25+sbbs_random(50));
1655: else
1656: mswait(25+sbbs_random(150));
1657: if(theanswer[i]==' ')
1658: mswait(sbbs_random(50));
1659: } }
1660: else {
1661: mswait(strlen(theanswer)*100);
1662: bprintf(text[ChatLineFmt],cfg.guru[gurunum]->name
1663: ,cfg.sys_nodes+1,':',theanswer); }
1664: CRLF;
1665: sprintf(str,"%sguru.log",cfg.logs_dir);
1666: if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1)
1667: errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_APPEND);
1668: else {
1669: if(action==NODE_MCHT) {
1670: sprintf(str,"[Multi] ");
1671: write(file,str,strlen(str)); }
1672: sprintf(str,"%s:\r\n",sys_status&SS_USERON
1673: ? useron.alias : "UNKNOWN");
1674: write(file,str,strlen(str));
1675: write(file,line,strlen(line));
1676: if(action!=NODE_MCHT)
1677: write(file,crlf,2);
1678: sprintf(str,"%s:\r\n",cfg.guru[gurunum]->name);
1679: write(file,str,strlen(str));
1680: write(file,theanswer,strlen(theanswer));
1681: write(file,crlf,2);
1682: close(file); }
1683: if(hu)
1684: hangup();
1685: break; } }
1686: for(i=0;i<100;i++)
1687: free(answer[i]);
1688: }
1689:
1690: /****************************************************************************/
1691: /* An expression from the guru's buffer 'ptrptr' is evaluated and true or */
1692: /* false is returned. */
1693: /****************************************************************************/
1694: bool sbbs_t::guruexp(char **ptrptr, char *line)
1695: {
1696: char c,*cp,str[256];
1697: int nest;
1698: bool result=false,_and=false,_or=false;
1699: uchar *ar;
1700:
1701: if((**ptrptr)==')') { /* expressions of () are always result */
1702: (*ptrptr)++;
1703: return(true); }
1704: while((**ptrptr)!=')' && (**ptrptr)) {
1705: if((**ptrptr)=='[') {
1706: (*ptrptr)++;
1707: SAFECOPY(str,*ptrptr);
1708: while(**ptrptr && (**ptrptr)!=']')
1709: (*ptrptr)++;
1710: (*ptrptr)++;
1711: cp=strchr(str,']');
1712: if(cp) *cp=0;
1713: ar=arstr(NULL,str,&cfg);
1714: c=chk_ar(ar,&useron);
1715: if(ar[0]!=AR_NULL)
1716: free(ar);
1717: if(!c && _and) {
1718: result=false;
1719: break; }
1720: if(c && _or) {
1721: result=true;
1722: break; }
1723: if(c)
1724: result=true;
1725: continue; }
1726: if((**ptrptr)=='(') {
1727: (*ptrptr)++;
1728: c=guruexp(&(*ptrptr),line);
1729: if(!c && _and) {
1730: result=false;
1731: break; }
1732: if(c && _or) {
1733: result=true;
1734: break; }
1735: if(c)
1736: result=true; }
1737: if((**ptrptr)==')')
1738: break;
1739: c=0;
1740: while((**ptrptr) && isspace(**ptrptr))
1741: (*ptrptr)++;
1742: while((**ptrptr)!='|' && (**ptrptr)!='&' && (**ptrptr)!=')' &&(**ptrptr)) {
1743: str[c++]=(**ptrptr);
1744: (*ptrptr)++; }
1745: str[c]=0;
1746: if((**ptrptr)=='|') {
1747: if(!c && result)
1748: break;
1749: _and=false;
1750: _or=true; }
1751: else if((**ptrptr)=='&') {
1752: if(!c && !result)
1753: break;
1754: _and=true;
1755: _or=false; }
1756: if(!c) { /* support ((exp)op(exp)) */
1757: (*ptrptr)++;
1758: continue; }
1759: if((**ptrptr)!=')')
1760: (*ptrptr)++;
1761: c=0; /* c now used for start line flag */
1762: if(str[strlen(str)-1]=='^') { /* ^signifies start of line only */
1763: str[strlen(str)-1]=0;
1764: c=true; }
1765: if(str[strlen(str)-1]=='~') { /* ~signifies non-isolated word */
1766: str[strlen(str)-1]=0;
1767: cp=strstr(line,str);
1768: if(c && cp!=line)
1769: cp=0; }
1770: else {
1771: cp=strstr(line,str);
1772: if(cp && c) {
1773: if(cp!=line || isalnum(*(cp+strlen(str))))
1774: cp=0; }
1775: else { /* must be isolated word */
1776: while(cp)
1777: if((cp!=line && isalnum(*(cp-1)))
1778: || isalnum(*(cp+strlen(str))))
1779: cp=strstr(cp+strlen(str),str);
1780: else
1781: break; } }
1782: if(!cp && _and) {
1783: result=false;
1784: break; }
1785: if(cp && _or) {
1786: result=true;
1787: break; }
1788: if(cp)
1789: result=true; }
1790: nest=0;
1791: while((**ptrptr)!=')' && (**ptrptr)) { /* handle nested exp */
1792: if((**ptrptr)=='(') /* (TRUE|(IGNORE)) */
1793: nest++;
1794: (*ptrptr)++;
1795: while((**ptrptr)==')' && nest && (**ptrptr)) {
1796: nest--;
1797: (*ptrptr)++; } }
1798: (*ptrptr)++; /* skip over ')' */
1799: return(result);
1800: }
1801:
1802: /****************************************************************************/
1803: /* Guru chat with the appearance of Local chat with sysop. */
1804: /****************************************************************************/
1805: void sbbs_t::localguru(char *gurubuf, int gurunum)
1806: {
1807: char ch,str[256];
1808: int con=console; /* save console state */
1809: char lastanswer[512];
1810:
1811: if(sys_status&SS_GURUCHAT || !cfg.total_gurus)
1812: return;
1813: sys_status|=SS_GURUCHAT;
1814: console&=~(CON_L_ECHOX|CON_R_ECHOX); /* turn off X's */
1815: console|=(CON_L_ECHO|CON_R_ECHO); /* make sure echo is on */
1816: if(action==NODE_CHAT) { /* only page if from chat section */
1817: bprintf(text[PagingGuru],cfg.guru[gurunum]->name);
1818: ch=sbbs_random(25)+25;
1819: while(ch--) {
1820: mswait(200);
1821: outchar('.'); } }
1822: bprintf(text[SysopIsHere],cfg.guru[gurunum]->name);
1823: if(getnodedat(cfg.node_num,&thisnode,true)==0) {
1824: thisnode.aux=gurunum;
1825: putnodedat(cfg.node_num,&thisnode);
1826: }
1827: attr(cfg.color[clr_chatlocal]);
1828: strcpy(str,"HELLO");
1829: guruchat(str,gurubuf,gurunum,lastanswer);
1830: str[0]=0;
1831: while(online && (sys_status&SS_GURUCHAT)) {
1832: checkline();
1833: action=NODE_GCHT;
1834: SYNC;
1835: if(wordwrap[0]==0) {
1836: if((ch=inkey(K_NONE,1000))==0) {
1837: if(str[0]) {
1838: attr(cfg.color[clr_chatlocal]);
1839: guruchat(str,gurubuf,gurunum,lastanswer);
1840: str[0]=0;
1841: }
1842: continue;
1843: }
1844: ungetkey(ch);
1845: }
1846: attr(cfg.color[clr_chatremote]);
1847: getstr(str,78,K_WRAP|K_CHAT);
1848: }
1849: bputs(text[EndOfChat]);
1850: sys_status&=~SS_GURUCHAT;
1851: console=con; /* restore console state */
1852: }
1853:
1854:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.