Annotation of sbbs/src/sbbs3/chat.cpp, revision 1.1.1.2

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.