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