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

1.1       root        1: /* writemsg.cpp */
                      2: 
                      3: /* Synchronet message creation routines */
                      4: 
1.1.1.2 ! root        5: /* $Id: writemsg.cpp,v 1.93 2011/08/30 22:51:21 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"
1.1.1.2 ! root       39: #include "wordwrap.h"
1.1       root       40: 
                     41: #define MAX_LINE_LEN 82L
                     42: 
1.1.1.2 ! root       43: const char *quote_fmt=" > %.*s\r\n";
1.1       root       44: void quotestr(char *str);
                     45: 
                     46: /****************************************************************************/
                     47: /* Returns temporary message text filename (for message/text editors)          */
                     48: /****************************************************************************/
1.1.1.2 ! root       49: char* sbbs_t::msg_tmp_fname(int xedit, char* path, size_t len)
1.1       root       50: {
1.1.1.2 ! root       51:        safe_snprintf(path, len, "%sINPUT.MSG", cfg.temp_dir);
1.1       root       52: 
                     53:        if(xedit) {
                     54:                if(cfg.xedit[xedit-1]->misc&QUICKBBS)
1.1.1.2 ! root       55:                        safe_snprintf(path, len, "%sMSGTMP", cfg.node_dir);     /* QuickBBS editors are dumb */
1.1       root       56:                if(cfg.xedit[xedit-1]->misc&XTRN_LWRCASE)
1.1.1.2 ! root       57:                        strlwr(getfname(path));
1.1       root       58:        }
                     59: 
1.1.1.2 ! root       60:        return path;
        !            61: }
        !            62: 
        !            63: /****************************************************************************/
        !            64: /****************************************************************************/
        !            65: char* sbbs_t::quotes_fname(int xedit, char *path, size_t len)
        !            66: {
        !            67:        safe_snprintf(path, len, "%sQUOTES.TXT", cfg.node_dir);
        !            68:        if(xedit && cfg.xedit[xedit-1]->misc&XTRN_LWRCASE)
        !            69:                strlwr(getfname(path));
        !            70:        return path;
        !            71: }
        !            72: 
        !            73: /****************************************************************************/
        !            74: /****************************************************************************/
        !            75: void sbbs_t::quotemsg(smbmsg_t* msg, int tails)
        !            76: {
        !            77:        char    fname[MAX_PATH+1];
        !            78:        char*   buf;
        !            79:        char*   wrapped=NULL;
        !            80:        FILE*   fp;
        !            81: 
        !            82:        quotes_fname(useron.xedit,fname,sizeof(fname));
        !            83:        removecase(fname);
        !            84: 
        !            85:        if((fp=fopen(fname,"w"))==NULL) {
        !            86:                errormsg(WHERE,ERR_OPEN,fname,0);
        !            87:                return; 
        !            88:        }
        !            89: 
        !            90:        if((buf=smb_getmsgtxt(&smb,msg,tails)) != NULL) {
        !            91:                strip_invalid_attr(buf);
        !            92:                if(useron.xedit && (cfg.xedit[useron.xedit-1]->misc&QUOTEWRAP))
        !            93:                        wrapped=::wordwrap(buf, cols-4, cols-1, /* handle_quotes */TRUE);
        !            94:                if(wrapped!=NULL) {
        !            95:                        fputs(wrapped,fp);
        !            96:                        free(wrapped);
        !            97:                } else
        !            98:                        fputs(buf,fp);
        !            99:                smb_freemsgtxt(buf); 
        !           100:        } else if(smb_getmsgdatlen(msg)>2)
        !           101:                errormsg(WHERE,ERR_READ,smb.file,smb_getmsgdatlen(msg));
        !           102:        fclose(fp);
        !           103: }
        !           104: 
        !           105: /****************************************************************************/
        !           106: /****************************************************************************/
        !           107: int sbbs_t::process_edited_text(char* buf, FILE* stream, long mode, unsigned* lines)
        !           108: {
        !           109:        int i,l;
        !           110:        int     len=0;
        !           111: 
        !           112:        for(l=i=0;buf[l] && i<cfg.level_linespermsg[useron.level];l++) {
        !           113:                if((uchar)buf[l]==141 && useron.xedit
        !           114:                && cfg.xedit[useron.xedit-1]->misc&QUICKBBS) {
        !           115:                        len+=fwrite(crlf,1,2,stream);
        !           116:                        i++;
        !           117:                        continue; 
        !           118:                }
        !           119:                /* Expand LF to CRLF? */
        !           120:                if(buf[l]==LF && (!l || buf[l-1]!=CR) && useron.xedit
        !           121:                        && cfg.xedit[useron.xedit-1]->misc&EXPANDLF) {
        !           122:                        len+=fwrite(crlf,1,2,stream);
        !           123:                        i++;
        !           124:                        continue; 
        !           125:                }
        !           126:                /* Strip FidoNet Kludge Lines? */
        !           127:                if(buf[l]==CTRL_A && useron.xedit
        !           128:                        && cfg.xedit[useron.xedit-1]->misc&STRIPKLUDGE) {
        !           129:                        while(buf[l] && buf[l]!=LF) 
        !           130:                                l++;
        !           131:                        if(buf[l]==0)
        !           132:                                break;
        !           133:                        continue;
        !           134:                }
        !           135:                if(!(mode&(WM_EMAIL|WM_NETMAIL))
        !           136:                        && (!l || buf[l-1]==LF)
        !           137:                        && buf[l]=='-' && buf[l+1]=='-' && buf[l+2]=='-'
        !           138:                        && (buf[l+3]==' ' || buf[l+3]==TAB || buf[l+3]==CR))
        !           139:                        buf[l+1]='+';
        !           140:                if(buf[l]==LF)
        !           141:                        i++;
        !           142:                fputc(buf[l],stream); 
        !           143:                len++;
        !           144:        }
        !           145: 
        !           146:        if(buf[l])
        !           147:                bputs(text[NoMoreLines]);
        !           148: 
        !           149:        if(lines!=NULL)
        !           150:                *lines=i;
        !           151:        return len;
        !           152: }
        !           153: 
        !           154: /****************************************************************************/
        !           155: /****************************************************************************/
        !           156: int sbbs_t::process_edited_file(const char* src, const char* dest, long mode, unsigned* lines)
        !           157: {
        !           158:        char*   buf;
        !           159:        long    len;
        !           160:        FILE*   fp;
        !           161: 
        !           162:        if((len=(long)flength(src))<1)
        !           163:                return -1;
        !           164: 
        !           165:        if((buf=(char*)malloc(len+1))==NULL)
        !           166:                return -2;
        !           167: 
        !           168:        if((fp=fopen(src,"rb"))==NULL)
        !           169:                return -3;
        !           170: 
        !           171:        memset(buf,0,len+1);
        !           172:        fread(buf,len,sizeof(char),fp);
        !           173:        fclose(fp);
        !           174: 
        !           175:        if((fp=fopen(dest,"wb"))!=NULL) {
        !           176:                len=process_edited_text(buf, fp, mode, lines);
        !           177:                fclose(fp);
        !           178:        }
        !           179:        free(buf);
        !           180: 
        !           181:        return len;
1.1       root      182: }
                    183: 
                    184: /****************************************************************************/
                    185: /* Creates a message (post or mail) using standard line editor. 'fname' is  */
                    186: /* is name of file to create, 'top' is a buffer to place at beginning of    */
                    187: /* message and 'title' is the title (70chars max) for the message.          */
                    188: /* 'dest' contains a text description of where the message is going.        */
                    189: /****************************************************************************/
1.1.1.2 ! root      190: bool sbbs_t::writemsg(const char *fname, const char *top, char *title, long mode, int subnum
        !           191:        ,const char *dest, char** editor)
1.1       root      192: {
                    193:        char    str[256],quote[128],c,*buf,*p,*tp
                    194:                                ,useron_level;
                    195:        char    msgtmp[MAX_PATH+1];
                    196:        char    tmp[512];
                    197:        int             i,j,file,linesquoted=0;
                    198:        long    length,qlen=0,qtime=0,ex_mode=0;
                    199:        int             max_title_len=LEN_TITLE;
                    200:        ulong   l;
                    201:        FILE*   stream;
                    202:        FILE*   fp;
1.1.1.2 ! root      203:        unsigned lines;
1.1       root      204: 
                    205:        useron_level=useron.level;
                    206: 
1.1.1.2 ! root      207:        if(editor!=NULL)
        !           208:                *editor=NULL;
        !           209: 
1.1       root      210:        if((buf=(char*)malloc(cfg.level_linespermsg[useron_level]*MAX_LINE_LEN))
                    211:                ==NULL) {
                    212:                errormsg(WHERE,ERR_ALLOC,fname
                    213:                        ,cfg.level_linespermsg[useron_level]*MAX_LINE_LEN);
                    214:                return(false); 
                    215:        }
                    216: 
                    217:        if(mode&WM_NETMAIL ||
                    218:                (!(mode&(WM_EMAIL|WM_NETMAIL)) && cfg.sub[subnum]->misc&SUB_PNET))
                    219:                mode|=WM_NOTOP;
                    220: 
                    221:        msg_tmp_fname(useron.xedit, msgtmp, sizeof(msgtmp));
                    222: 
                    223:        if(mode&WM_QUOTE && !(useron.rest&FLAG('J'))
                    224:                && ((mode&(WM_EMAIL|WM_NETMAIL) && cfg.sys_misc&SM_QUOTE_EM)
                    225:                || (!(mode&(WM_EMAIL|WM_NETMAIL)) && (uint)subnum!=INVALID_SUB
                    226:                        && cfg.sub[subnum]->misc&SUB_QUOTE))) {
                    227: 
                    228:                /* Quote entire message to MSGTMP or INPUT.MSG */
                    229: 
                    230:                if(useron.xedit && cfg.xedit[useron.xedit-1]->misc&QUOTEALL) {
1.1.1.2 ! root      231:                        quotes_fname(useron.xedit, str, sizeof(str));
1.1       root      232:                        if((stream=fnopen(NULL,str,O_RDONLY))==NULL) {
                    233:                                errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
                    234:                                free(buf);
                    235:                                return(false); 
                    236:                        }
                    237: 
                    238:                        if((file=nopen(msgtmp,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
                    239:                                errormsg(WHERE,ERR_OPEN,msgtmp,O_WRONLY|O_CREAT|O_TRUNC);
                    240:                                free(buf);
                    241:                                fclose(stream);
                    242:                                return(false); 
                    243:                        }
                    244: 
                    245:                        while(!feof(stream) && !ferror(stream)) {
1.1.1.2 ! root      246:                                if(!fgets(str,sizeof(str),stream))
1.1       root      247:                                        break;
                    248:                                quotestr(str);
1.1.1.2 ! root      249:                                SAFEPRINTF2(tmp,quote_fmt,cols-4,str);
1.1       root      250:                                write(file,tmp,strlen(tmp));
                    251:                                linesquoted++; 
                    252:                        }
                    253:                        fclose(stream);
                    254:                        close(file); 
                    255:                }
                    256: 
                    257:                /* Quote nothing to MSGTMP or INPUT.MSG automatically */
                    258: 
                    259:                else if(useron.xedit && cfg.xedit[useron.xedit-1]->misc&QUOTENONE)
                    260:                        ;
                    261: 
                    262:                else if(yesno(text[QuoteMessageQ])) {
1.1.1.2 ! root      263:                        quotes_fname(useron.xedit, str, sizeof(str));
1.1       root      264:                        if((stream=fnopen(&file,str,O_RDONLY))==NULL) {
                    265:                                errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
                    266:                                free(buf);
                    267:                                return(false); 
                    268:                        }
                    269: 
                    270:                        if((file=nopen(msgtmp,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
                    271:                                errormsg(WHERE,ERR_OPEN,msgtmp,O_WRONLY|O_CREAT|O_TRUNC);
                    272:                                free(buf);
                    273:                                fclose(stream);
                    274:                                return(false); 
                    275:                        }
                    276: 
1.1.1.2 ! root      277:                        l=(long)ftell(stream);                  /* l now points to start of message */
1.1       root      278: 
                    279:                        while(online) {
1.1.1.2 ! root      280:                                SAFEPRINTF(str,text[QuoteLinesPrompt],linesquoted ? "Done":"All");
1.1       root      281:                                mnemonics(str);
                    282:                                i=getstr(quote,10,K_UPPER);
                    283:                                if(sys_status&SS_ABORT) {
                    284:                                        fclose(stream);
                    285:                                        close(file);
                    286:                                        free(buf);
                    287:                                        return(false); 
                    288:                                }
                    289:                                if(!i && linesquoted)
                    290:                                        break;
                    291:                                if(!i || quote[0]=='A') {                   /* Quote all */
                    292:                                        fseek(stream,l,SEEK_SET);
                    293:                                        while(!feof(stream) && !ferror(stream)) {
1.1.1.2 ! root      294:                                                if(!fgets(str,sizeof(str),stream))
1.1       root      295:                                                        break;
                    296:                                                quotestr(str);
1.1.1.2 ! root      297:                                                SAFEPRINTF2(tmp,quote_fmt,cols-4,str);
1.1       root      298:                                                write(file,tmp,strlen(tmp));
                    299:                                                linesquoted++; 
                    300:                                        }
                    301:                                        break; 
                    302:                                }
                    303:                                if(quote[0]=='L') {
                    304:                                        fseek(stream,l,SEEK_SET);
                    305:                                        i=1;
                    306:                                        CRLF;
                    307:                                        attr(LIGHTGRAY);
                    308:                                        while(!feof(stream) && !ferror(stream) && !msgabort()) {
1.1.1.2 ! root      309:                                                if(!fgets(str,sizeof(str),stream))
1.1       root      310:                                                        break;
                    311:                                                quotestr(str);
                    312:                                                bprintf("%3d: %.74s\r\n",i,str);
                    313:                                                i++; 
                    314:                                        }
                    315:                                        continue; 
                    316:                                }
                    317: 
                    318:                                if(!isdigit(quote[0]))
                    319:                                        break;
                    320:                                p=quote;
                    321:                                while(p) {
                    322:                                        if(*p==',' || *p==' ')
                    323:                                                p++;
                    324:                                        i=atoi(p);
                    325:                                        if(!i)
                    326:                                                break;
                    327:                                        fseek(stream,l,SEEK_SET);
                    328:                                        j=1;
                    329:                                        while(!feof(stream) && !ferror(stream) && j<i) {
1.1.1.2 ! root      330:                                                if(!fgets(tmp,sizeof(tmp),stream))
1.1       root      331:                                                        break;
                    332:                                                j++; /* skip beginning */
                    333:                                        }               
                    334:                                        tp=strchr(p,'-');   /* tp for temp pointer */
                    335:                                        if(tp) {                 /* range */
                    336:                                                i=atoi(tp+1);
                    337:                                                while(!feof(stream) && !ferror(stream) && j<=i) {
1.1.1.2 ! root      338:                                                        if(!fgets(str,sizeof(str),stream))
1.1       root      339:                                                                break;
                    340:                                                        quotestr(str);
1.1.1.2 ! root      341:                                                        SAFEPRINTF2(tmp,quote_fmt,cols-4,str);
1.1       root      342:                                                        write(file,tmp,strlen(tmp));
                    343:                                                        linesquoted++;
                    344:                                                        j++; 
                    345:                                                } 
                    346:                                        }
                    347:                                        else {                  /* one line */
1.1.1.2 ! root      348:                                                if(fgets(str,sizeof(str),stream)) {
1.1       root      349:                                                        quotestr(str);
1.1.1.2 ! root      350:                                                        SAFEPRINTF2(tmp,quote_fmt,cols-4,str);
1.1       root      351:                                                        write(file,tmp,strlen(tmp));
                    352:                                                        linesquoted++; 
                    353:                                                } 
                    354:                                        }
                    355:                                        p=strchr(p,',');
                    356:                                        // if(!p) p=strchr(p,' ');  02/05/96 huh?
                    357:                                } 
                    358:                        }
                    359: 
                    360:                        fclose(stream);
                    361:                        close(file); 
                    362:                } 
                    363:        }
                    364:        else {
1.1.1.2 ! root      365:                quotes_fname(useron.xedit, str, sizeof(str));
1.1       root      366:                removecase(str); 
                    367:        }
                    368: 
                    369:        if(!online || sys_status&SS_ABORT) {
                    370:                free(buf);
                    371:                return(false); 
                    372:        }
                    373: 
                    374:        if(!(mode&(WM_EXTDESC|WM_SUBJ_RO))) {
                    375:                if(mode&WM_FILE) {
1.1.1.2 ! root      376: #if 0
1.1       root      377:                        max_title_len=12;       /* ToDo: implied 8.3 filename limit! */
1.1.1.2 ! root      378: #endif
1.1       root      379:                        CRLF;
                    380:                        bputs(text[Filename]); 
                    381:                }
                    382:                else {
1.1.1.2 ! root      383: #if 0
1.1       root      384:                        max_title_len=LEN_TITLE;
                    385:                        if(mode&WM_QWKNET
                    386:                                || (subnum!=INVALID_SUB 
                    387:                                        && (cfg.sub[subnum]->misc&(SUB_QNET|SUB_INET|SUB_FIDO))==SUB_QNET))
                    388:                                max_title_len=25;
1.1.1.2 ! root      389: #endif
1.1       root      390:                        bputs(text[SubjectPrompt]); 
                    391:                }
                    392:                if(!getstr(title,max_title_len,mode&WM_FILE ? K_LINE : K_LINE|K_EDIT|K_AUTODEL)
                    393:                        && useron_level && useron.logons) {
                    394:                        free(buf);
                    395:                        return(false); 
                    396:                }
                    397:                if(!(mode&(WM_EMAIL|WM_NETMAIL)) && cfg.sub[subnum]->misc&SUB_QNET
                    398:                        && !SYSOP
                    399:                        && (!stricmp(title,"DROP") || !stricmp(title,"ADD")
                    400:                        || !strnicmp(dest,"SBBS",4))) {
                    401:                        free(buf);   /* Users can't post DROP or ADD in QWK netted subs */
                    402:                        return(false); /* or messages to "SBBS" */
                    403:                }
                    404:        }
                    405: 
                    406:        if(!online || sys_status&SS_ABORT) {
                    407:                free(buf);
                    408:                return(false); 
                    409:        }
                    410: 
                    411:        if(console&CON_RAW_IN) {
                    412:                bprintf(text[EnterMsgNowRaw]
                    413:                        ,(ulong)cfg.level_linespermsg[useron_level]*MAX_LINE_LEN);
                    414:                if(top[0] && !(mode&WM_NOTOP)) {
                    415:                        strcpy((char *)buf,top);
                    416:                        strcat((char *)buf,crlf);
                    417:                        l=strlen((char *)buf); 
                    418:                }
                    419:                else
                    420:                        l=0;
                    421:                while(l<(ulong)(cfg.level_linespermsg[useron_level]*MAX_LINE_LEN)) {
                    422:                        c=getkey(0);
                    423:                        if(sys_status&SS_ABORT) {  /* Ctrl-C */
                    424:                                free(buf);
                    425:                                return(false); 
                    426:                        }
                    427:                        if((c==ESC || c==CTRL_A) && useron.rest&FLAG('A')) /* ANSI restriction */
                    428:                                continue;
                    429:                        if(c==BEL && useron.rest&FLAG('B'))   /* Beep restriction */
                    430:                                continue;
                    431:                        if(!(console&CON_RAW_IN))       /* Ctrl-Z was hit */
                    432:                                break;
                    433:                        outchar(c);
                    434:                        buf[l++]=c; 
                    435:                }
                    436:                buf[l]=0;
                    437:                if(l==(ulong)cfg.level_linespermsg[useron_level]*MAX_LINE_LEN)
                    438:                        bputs(text[OutOfBytes]); 
                    439:        }
                    440: 
                    441: 
                    442:        else if(useron.xedit) {
                    443: 
1.1.1.2 ! root      444:                if(editor!=NULL)
        !           445:                        *editor=cfg.xedit[useron.xedit-1]->name;
        !           446: 
1.1       root      447:                editor_inf(useron.xedit,dest,title,mode,subnum);
                    448:                if(cfg.xedit[useron.xedit-1]->type) {
                    449:                        gettimeleft();
                    450:                        xtrndat(useron.alias,cfg.node_dir,cfg.xedit[useron.xedit-1]->type
                    451:                           ,timeleft,cfg.xedit[useron.xedit-1]->misc); 
                    452:                }
                    453: 
1.1.1.2 ! root      454:                if(cfg.xedit[useron.xedit-1]->misc&XTRN_STDIO) {
        !           455:                        ex_mode|=EX_STDIO;
1.1       root      456:                        if(cfg.xedit[useron.xedit-1]->misc&WWIVCOLOR)
                    457:                                ex_mode|=EX_WWIV; 
                    458:                }
                    459:                if(cfg.xedit[useron.xedit-1]->misc&XTRN_NATIVE)
                    460:                        ex_mode|=EX_NATIVE;
                    461:                if(cfg.xedit[useron.xedit-1]->misc&XTRN_SH)
                    462:                        ex_mode|=EX_SH;
                    463: 
                    464:                if(!linesquoted)
                    465:                        removecase(msgtmp);
                    466:                else {
1.1.1.2 ! root      467:                        qlen=(long)flength(msgtmp);
1.1       root      468:                        qtime=fdate(msgtmp); 
                    469:                }
                    470: 
                    471:                CLS;
                    472:                rioctl(IOCM|PAUSE|ABORT);
                    473:                external(cmdstr(cfg.xedit[useron.xedit-1]->rcmd,msgtmp,nulstr,NULL),ex_mode,cfg.node_dir);
                    474:                rioctl(IOSM|PAUSE|ABORT); 
                    475: 
                    476:                checkline();
                    477:                if(!fexistcase(msgtmp) || !online
                    478:                        || (linesquoted && qlen==flength(msgtmp) && qtime==fdate(msgtmp))) {
                    479:                        free(buf);
                    480:                        return(false); 
                    481:                }
                    482:                SAFEPRINTF(str,"%sRESULT.ED",cfg.node_dir);
                    483:                if(!(mode&(WM_EXTDESC|WM_FILE|WM_SUBJ_RO))
                    484:                        && !(cfg.xedit[useron.xedit-1]->misc&QUICKBBS) 
                    485:                        && fexistcase(str)) {
                    486:                        if((fp=fopen(str,"r")) != NULL) {
                    487:                                fgets(str,sizeof(str),fp);
                    488:                                fgets(str,sizeof(str),fp);
                    489:                                truncsp(str);
1.1.1.2 ! root      490:                                safe_snprintf(title,max_title_len,"%s",str);
1.1       root      491:                                fclose(fp);
                    492:                        }
                    493:                }
                    494: 
                    495:                buf[0]=0;
                    496:                if(!(mode&WM_NOTOP))
                    497:                        strcpy((char *)buf,top);
                    498:                if((file=nopen(msgtmp,O_RDONLY))==-1) {
                    499:                        errormsg(WHERE,ERR_OPEN,msgtmp,O_RDONLY);
                    500:                        free(buf);
                    501:                        return(false); 
                    502:                }
1.1.1.2 ! root      503:                length=(long)filelength(file);
1.1       root      504:                l=strlen((char *)buf);    /* reserve space for top and terminating null */
                    505:                /* truncate if too big */
                    506:                if(length>(long)((cfg.level_linespermsg[useron_level]*MAX_LINE_LEN)-(l+1))) {
                    507:                        length=(cfg.level_linespermsg[useron_level]*MAX_LINE_LEN)-(l+1);
                    508:                        bputs(text[OutOfBytes]); 
                    509:                }
                    510:                lread(file,buf+l,length);
                    511:                close(file);
                    512:                // remove(msgtmp);         /* no need to save the temp input file */
                    513:                buf[l+length]=0; 
                    514:        }
                    515:        else {
                    516:                buf[0]=0;
                    517:                if(linesquoted) {
                    518:                        if((file=nopen(msgtmp,O_RDONLY))!=-1) {
1.1.1.2 ! root      519:                                length=(long)filelength(file);
1.1       root      520:                                l=length>(cfg.level_linespermsg[useron_level]*MAX_LINE_LEN)-1
                    521:                                        ? (cfg.level_linespermsg[useron_level]*MAX_LINE_LEN)-1 : length;
                    522:                                lread(file,buf,l);
                    523:                                buf[l]=0;
                    524:                                close(file);
                    525:                                // remove(msgtmp);
                    526:                        } 
                    527:                }
                    528:                if(!(msgeditor((char *)buf,mode&WM_NOTOP ? nulstr : top,title))) {
                    529:                        free(buf);      /* Assertion here Dec-17-2003, think I fixed in block above (rev 1.52) */
                    530:                        return(false); 
                    531:                } 
                    532:        }
                    533: 
                    534:        now=time(NULL);
                    535:        bputs(text[Saving]);
1.1.1.2 ! root      536:        if((stream=fnopen(NULL,fname,O_WRONLY|O_CREAT|O_TRUNC))==NULL) {
1.1       root      537:                errormsg(WHERE,ERR_OPEN,fname,O_WRONLY|O_CREAT|O_TRUNC);
                    538:                free(buf);
                    539:                return(false); 
                    540:        }
1.1.1.2 ! root      541:        l=process_edited_text(buf,stream,mode,&lines);
1.1       root      542: 
                    543:        /* Signature file */
1.1.1.2 ! root      544:        if((subnum==INVALID_SUB && cfg.msg_misc&MM_EMAILSIG)
        !           545:                || (subnum!=INVALID_SUB && !(cfg.sub[subnum]->misc&SUB_NOUSERSIG))) {
        !           546:                SAFEPRINTF2(str,"%suser/%04u.sig",cfg.data_dir,useron.number);
1.1       root      547:                FILE* sig;
                    548:                if(fexist(str) && (sig=fopen(str,"rb"))!=NULL) {
                    549:                        while(!feof(sig)) {
                    550:                                if(!fgets(str,sizeof(str),sig))
                    551:                                        break;
                    552:                                fputs(str,stream);
                    553:                                l+=strlen(str); /* byte counter */
1.1.1.2 ! root      554:                                lines++;                /* line counter */
1.1       root      555:                        }
                    556:                        fclose(sig);
                    557:                }
                    558:        }
                    559: 
                    560:        fclose(stream);
                    561:        free((char *)buf);
1.1.1.2 ! root      562:        bprintf(text[SavedNBytes],l,lines);
1.1       root      563:        return(true);
                    564: }
                    565: 
                    566: /****************************************************************************/
                    567: /* Modify 'str' to for quoted format. Remove ^A codes, etc.                 */
                    568: /****************************************************************************/
                    569: void quotestr(char *str)
                    570: {
1.1.1.2 ! root      571:        truncsp(str);
        !           572:        remove_ctrl_a(str,str);
1.1       root      573: }
                    574: 
1.1.1.2 ! root      575: /****************************************************************************/
        !           576: /****************************************************************************/
        !           577: void sbbs_t::editor_inf(int xeditnum, const char *dest, const char *title, long mode
1.1       root      578:        ,uint subnum)
                    579: {
                    580:        char str[MAX_PATH+1];
                    581:        char tmp[32];
                    582:        int file;
                    583: 
                    584:        xeditnum--;
                    585: 
                    586:        if(cfg.xedit[xeditnum]->misc&QUICKBBS) {
                    587:                strcpy(tmp,"MSGINF");
                    588:                if(cfg.xedit[xeditnum]->misc&XTRN_LWRCASE)
                    589:                        strlwr(tmp);
1.1.1.2 ! root      590:                SAFEPRINTF2(str,"%s%s",cfg.node_dir,tmp);
1.1       root      591:                if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
                    592:                        errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_TRUNC);
                    593:                        return; 
                    594:                }
1.1.1.2 ! root      595:                safe_snprintf(str,sizeof(str),"%s\r\n%s\r\n%s\r\n%u\r\n%s\r\n%s\r\n"
1.1       root      596:                        ,(subnum!=INVALID_SUB && cfg.sub[subnum]->misc&SUB_NAME) ? useron.name
                    597:                                : useron.alias
                    598:                                ,dest,title,1
                    599:                                ,mode&WM_NETMAIL ? "NetMail"
                    600:                                :mode&WM_EMAIL ? "Electronic Mail"
                    601:                                :subnum==INVALID_SUB ? nulstr
                    602:                                :cfg.sub[subnum]->sname
                    603:                        ,mode&WM_PRIVATE ? "YES":"NO");
                    604:                write(file,str,strlen(str));
                    605:                close(file); 
                    606:        }
                    607:        else {
                    608:                SAFEPRINTF(str,"%sRESULT.ED",cfg.node_dir);
                    609:                removecase(str);
                    610:                strcpy(tmp,"EDITOR.INF");
                    611:                if(cfg.xedit[xeditnum]->misc&XTRN_LWRCASE)
                    612:                        strlwr(tmp);
1.1.1.2 ! root      613:                SAFEPRINTF2(str,"%s%s",cfg.node_dir,tmp);
1.1       root      614:                if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
                    615:                        errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_TRUNC);
                    616:                        return; 
                    617:                }
1.1.1.2 ! root      618:                safe_snprintf(str,sizeof(str),"%s\r\n%s\r\n%u\r\n%s\r\n%s\r\n%u\r\n"
1.1       root      619:                        ,title,dest,useron.number
                    620:                        ,(subnum!=INVALID_SUB && cfg.sub[subnum]->misc&SUB_NAME) ? useron.name
                    621:                        : useron.alias
                    622:                        ,useron.name,useron.level);
                    623:                write(file,str,strlen(str));
                    624:                close(file); 
                    625:        }
                    626: }
                    627: 
                    628: 
                    629: 
                    630: /****************************************************************************/
                    631: /* Removes from file 'str' every LF terminated line that starts with 'str2' */
                    632: /* That is divisable by num. Function skips first 'skip' number of lines    */
                    633: /****************************************************************************/
                    634: void sbbs_t::removeline(char *str, char *str2, char num, char skip)
                    635: {
                    636:        char*   buf;
                    637:     char    slen;
                    638:     int     i,file;
                    639:        long    l=0,flen;
                    640:     FILE    *stream;
                    641: 
                    642:        if((file=nopen(str,O_RDONLY))==-1) {
                    643:                errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
                    644:                return; 
                    645:        }
1.1.1.2 ! root      646:        flen=(long)filelength(file);
1.1       root      647:        slen=strlen(str2);
                    648:        if((buf=(char *)malloc(flen))==NULL) {
                    649:                close(file);
                    650:                errormsg(WHERE,ERR_ALLOC,str,flen);
                    651:                return; 
                    652:        }
                    653:        if(lread(file,buf,flen)!=flen) {
                    654:                close(file);
                    655:                errormsg(WHERE,ERR_READ,str,flen);
                    656:                free(buf);
                    657:                return; 
                    658:        }
                    659:        close(file);
                    660:        if((stream=fnopen(&file,str,O_WRONLY|O_TRUNC))==NULL) {
                    661:                close(file);
                    662:                errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_TRUNC);
                    663:                free(buf);
                    664:                return; 
                    665:        }
                    666:        for(i=0;l<flen && i<skip;l++) {
                    667:                fputc(buf[l],stream);
                    668:                if(buf[l]==LF)
                    669:                        i++; 
                    670:        }
                    671:        while(l<flen) {
                    672:                if(!strncmp((char *)buf+l,str2,slen)) {
                    673:                        for(i=0;i<num && l<flen;i++) {
                    674:                                while(l<flen && buf[l]!=LF) l++;
                    675:                                l++; 
                    676:                        } 
                    677:                }
                    678:                else {
                    679:                        for(i=0;i<num && l<flen;i++) {
                    680:                                while(l<flen && buf[l]!=LF) fputc(buf[l++],stream);
                    681:                                fputc(buf[l++],stream); 
                    682:                        } 
                    683:                } 
                    684:        }
                    685:        fclose(stream);
                    686:        free((char *)buf);
                    687: }
                    688: 
                    689: /*****************************************************************************/
                    690: /* The Synchronet editor.                                                    */
                    691: /* Returns the number of lines edited.                                       */
                    692: /*****************************************************************************/
1.1.1.2 ! root      693: ulong sbbs_t::msgeditor(char *buf, const char *top, char *title)
1.1       root      694: {
                    695:        int             i,j,line,lines=0,maxlines;
                    696:        char    strin[256],**str,done=0;
                    697:        char    tmp[512];
                    698:        char    path[MAX_PATH+1];
                    699:     ulong      l,m;
                    700: 
                    701:        rioctl(IOCM|ABORT);
                    702:        rioctl(IOCS|ABORT); 
                    703: 
                    704:        maxlines=cfg.level_linespermsg[useron.level];
                    705: 
                    706:        if((str=(char **)malloc(sizeof(char *)*(maxlines+1)))==NULL) {
                    707:                errormsg(WHERE,ERR_ALLOC,"msgeditor",sizeof(char *)*(maxlines+1));
                    708:                return(0); 
                    709:        }
                    710:        m=strlen(buf);
                    711:        l=0;
                    712:        while(l<m && lines<maxlines) {
                    713:                msgabort(); /* to allow pausing */
                    714:                if((str[lines]=(char *)malloc(MAX_LINE_LEN))==NULL) {
                    715:                        errormsg(WHERE,ERR_ALLOC,nulstr,MAX_LINE_LEN);
                    716:                        for(i=0;i<lines;i++)
                    717:                                free(str[i]);
                    718:                        free(str);
                    719:                        rioctl(IOSM|ABORT);
                    720:                        return(0); 
                    721:                }
                    722:                for(i=0;i<79 && l<m;i++,l++) {
                    723:                        if(buf[l]==CR) {
                    724:                                l+=2;
                    725:                                break; 
                    726:                        }
                    727:                        if(buf[l]==TAB) {
                    728:                                if(!(i%8))                  /* hard-coded tabstop of 8 */
                    729:                                        str[lines][i++]=' ';     /* for expansion */
                    730:                                while(i%8 && i<79)
                    731:                                        str[lines][i++]=' ';
                    732:                                i--;
                    733:                                /***
                    734:                                bprintf("\r\nMessage editor: Expanded tab on line #%d",lines+1);
                    735:                                ***/ }
                    736:                        else str[lines][i]=buf[l]; 
                    737:                }
                    738:                if(i==79) {
                    739:                        if(buf[l]==CR)
                    740:                                l+=2;
                    741:                        else
                    742:                                bprintf("\r\nMessage editor: Split line #%d",lines+1); 
                    743:                }
                    744:                str[lines][i]=0;
                    745:                lines++; 
                    746:        }
                    747:        if(lines)
                    748:                bprintf("\r\nMessage editor: Read in %d lines\r\n",lines);
                    749:        bprintf(text[EnterMsgNow],maxlines);
                    750: 
1.1.1.2 ! root      751:        SAFEPRINTF(path,"%smenu/msgtabs.*", cfg.text_dir);
1.1       root      752:        if(fexist(path))
                    753:                menu("msgtabs");
                    754:        else {
                    755:                for(i=0;i<79;i++) {
                    756:                        if(i%EDIT_TABSIZE || !i)
                    757:                                outchar('-');
                    758:                        else 
                    759:                                outchar('+');
                    760:                }
                    761:                CRLF;
                    762:        }
                    763:        putmsg(top,P_SAVEATR|P_NOATCODES);
                    764:        for(line=0;line<lines && !msgabort();line++) { /* display lines in buf */
                    765:                putmsg(str[line],P_SAVEATR|P_NOATCODES);
                    766:                cleartoeol();  /* delete to end of line */
                    767:                CRLF; 
                    768:        }
                    769:        SYNC;
                    770:        rioctl(IOSM|ABORT);
                    771:        while(online && !done) {
                    772:                checkline();
                    773:                if(line==lines) {
                    774:                        if((str[line]=(char *)malloc(MAX_LINE_LEN))==NULL) {
                    775:                                errormsg(WHERE,ERR_ALLOC,nulstr,MAX_LINE_LEN);
                    776:                                for(i=0;i<lines;i++)
                    777:                                        free(str[i]);
                    778:                                free(str);
                    779:                                return(0); 
                    780:                        }
                    781:                        str[line][0]=0; 
                    782:                }
                    783:                if(line>(maxlines-10)) {
                    784:                        if(line==maxlines)
                    785:                                bputs(text[NoMoreLines]);
                    786:                        else
                    787:                                bprintf(text[OnlyNLinesLeft],maxlines-line); 
                    788:                }
                    789:                strcpy(strin,str[line]);
                    790:                do {
                    791:                        if(!line)
                    792:                                outchar(CR);
                    793:                        getstr(strin,79,K_WRAP|K_MSG|K_EDIT);
                    794:                        } while(console&CON_UPARROW && !line);
                    795: 
                    796:                if(sys_status&SS_ABORT) {
                    797:                        if(line==lines)
                    798:                                free(str[line]);
                    799:                        continue; 
                    800:                }
                    801:                if(strin[0]=='/' && strlen(strin)<8) {
                    802:                        if(!stricmp(strin,"/DEBUG") && SYSOP) {
                    803:                                if(line==lines)
                    804:                                        free(str[line]);
                    805:                                bprintf("\r\nline=%d lines=%d rows=%d\r\n",line,lines,rows);
                    806:                                continue; 
                    807:                        }
                    808:                        else if(!stricmp(strin,"/ABT")) {
                    809:                                if(line==lines)                 /* delete a line */
                    810:                                        free(str[line]);
                    811:                                for(i=0;i<lines;i++)
                    812:                                        free(str[i]);
                    813:                                free(str);
                    814:                                return(0); 
                    815:                        }
                    816:                        else if(toupper(strin[1])=='D') {
                    817:                                if(line==lines)         /* delete a line */
                    818:                                        free(str[line]);
                    819:                                if(!lines)
                    820:                                        continue;
                    821:                                i=atoi(strin+2)-1;
                    822:                                if(i==-1)   /* /D means delete last line */
                    823:                                        i=lines-1;
                    824:                                if(i>=lines || i<0)
                    825:                                        bputs(text[InvalidLineNumber]);
                    826:                                else {
                    827:                                        free(str[i]);
                    828:                                        lines--;
                    829:                                        while(i<lines) {
                    830:                                                str[i]=str[i+1];
                    831:                                                i++; 
                    832:                                        }
                    833:                                        if(line>lines)
                    834:                                                line=lines; 
                    835:                                }
                    836:                                continue; 
                    837:                        }
                    838:                        else if(toupper(strin[1])=='I') {
                    839:                                if(line==lines)         /* insert a line before number x */
                    840:                                        free(str[line]);
                    841:                                if(line==maxlines || !lines)
                    842:                                        continue;
                    843:                                i=atoi(strin+2)-1;
                    844:                                if(i==-1)
                    845:                                        i=lines-1;
                    846:                                if(i>=lines || i<0)
                    847:                                        bputs(text[InvalidLineNumber]);
                    848:                                else {
                    849:                                        for(line=lines;line>i;line--)   /* move the pointers */
                    850:                                                str[line]=str[line-1];
                    851:                                        if((str[i]=(char *)malloc(MAX_LINE_LEN))==NULL) {
                    852:                                                errormsg(WHERE,ERR_ALLOC,nulstr,MAX_LINE_LEN);
                    853:                                                for(i=0;i<lines;i++)
                    854:                                                        free(str[i]);
                    855:                                                free(str);
                    856:                                                return(0); 
                    857:                                        }
                    858:                                        str[i][0]=0;
                    859:                                        line=++lines; 
                    860:                                }
                    861:                                continue; 
                    862:                        }
                    863:                        else if(toupper(strin[1])=='E') {
                    864:                                if(line==lines)         /* edit a line */
                    865:                                        free(str[line]);
                    866:                                if(!lines)
                    867:                                        continue;
                    868:                                i=atoi(strin+2)-1;
                    869:                                j=K_MSG|K_EDIT; /* use j for the getstr mode */
                    870:                                if(i==-1) { /* /E means edit last line */
                    871:                                        i=lines-1;
                    872:                                        j|=K_WRAP;      /* wrap when editing last line */
                    873:                                }    
                    874:                                if(i>=lines || i<0)
                    875:                                        bputs(text[InvalidLineNumber]);
                    876:                                else
                    877:                                        getstr(str[i],79,j);
                    878:                                continue; 
                    879:                        }
                    880:                        else if(!stricmp(strin,"/CLR")) {
                    881:                                bputs(text[MsgCleared]);
                    882:                                if(line!=lines)
                    883:                                        lines--;
                    884:                                for(i=0;i<=lines;i++)
                    885:                                        free(str[i]);
                    886:                                line=0;
                    887:                                lines=0;
                    888:                                putmsg(top,P_SAVEATR|P_NOATCODES);
                    889:                                continue; 
                    890:                        }
                    891:                        else if(toupper(strin[1])=='L') {   /* list message */
                    892:                                if(line==lines)
                    893:                                        free(str[line]);
1.1.1.2 ! root      894:                                if(lines && text[WithLineNumbersQ][0])
1.1       root      895:                                        i=!noyes(text[WithLineNumbersQ]);
                    896:                                else
                    897:                                        i=0;
                    898:                                CRLF;
                    899:                                attr(LIGHTGRAY);
                    900:                                putmsg(top,P_SAVEATR|P_NOATCODES);
                    901:                                if(!lines) {
                    902:                                        continue; 
                    903:                                }
                    904:                                j=atoi(strin+2);
                    905:                                if(j) j--;  /* start from line j */
                    906:                                while(j<lines && !msgabort()) {
                    907:                                        if(i) { /* line numbers */
1.1.1.2 ! root      908:                                                SAFEPRINTF2(tmp,"%3d: %-.74s",j+1,str[j]);
1.1       root      909:                                                putmsg(tmp,P_SAVEATR|P_NOATCODES); 
                    910:                                        }
                    911:                                        else
                    912:                                                putmsg(str[j],P_SAVEATR|P_NOATCODES);
                    913:                                        cleartoeol();  /* delete to end of line */
                    914:                                        CRLF;
                    915:                                        j++; 
                    916:                                }
                    917:                                SYNC;
                    918:                                continue; 
                    919:                        }
                    920:                        else if(!stricmp(strin,"/S")) { /* Save */
                    921:                                if(line==lines)
                    922:                                        free(str[line]);
                    923:                                done=1;
                    924:                                continue;}
                    925:                        else if(!stricmp(strin,"/T")) { /* Edit title/subject */
                    926:                                if(line==lines)
                    927:                                        free(str[line]);
                    928:                                if(title[0]) {
                    929:                                        bputs(text[SubjectPrompt]);
                    930:                                        getstr(title,LEN_TITLE,K_LINE|K_EDIT|K_AUTODEL);
                    931:                                        SYNC;
                    932:                                        CRLF; 
                    933:                                }
                    934:                                continue; 
                    935:                        }
                    936:                        else if(!stricmp(strin,"/?")) {
                    937:                                if(line==lines)
                    938:                                        free(str[line]);
                    939:                                menu("editor"); /* User Editor Commands */
                    940:                                SYNC;
                    941:                                continue; 
                    942:                        }
                    943:                        else if(!stricmp(strin,"/ATTR"))    {
                    944:                                if(line==lines)
                    945:                                        free(str[line]);
                    946:                                menu("attr");   /* User ANSI Commands */
                    947:                                SYNC;
                    948:                                continue; 
                    949:                        } 
                    950:                }
                    951:                strcpy(str[line],strin);
                    952:                if(line<maxlines)
                    953:                        line++;
                    954:                else
                    955:                        free(str[line]);
                    956:                if(line>lines)
                    957:                        lines++;
                    958:                if(console&CON_UPARROW) {
                    959:                        outchar(CR);
                    960:                        cursor_up();
                    961:                        cleartoeol();
                    962:                        line-=2; 
                    963:                }
                    964:                }
                    965:        if(!online) {
                    966:                for(i=0;i<lines;i++)
                    967:                        free(str[i]);
                    968:                free(str);
                    969:                return(0); 
                    970:        }
                    971:        strcpy(buf,top);
                    972:        for(i=0;i<lines;i++) {
                    973:                strcat(buf,str[i]);
                    974:                strcat(buf,crlf);
                    975:                free(str[i]); 
                    976:        }
                    977:        free(str);
                    978:        return(lines);
                    979: }
                    980: 
                    981: 
                    982: /****************************************************************************/
                    983: /* Edits an existing file or creates a new one in MSG format                */
                    984: /****************************************************************************/
1.1.1.2 ! root      985: bool sbbs_t::editfile(char *fname)
1.1       root      986: {
                    987:        char *buf,path[MAX_PATH+1];
                    988:        char msgtmp[MAX_PATH+1];
1.1.1.2 ! root      989:        char str[MAX_PATH+1];
1.1       root      990:     int file;
1.1.1.2 ! root      991:        long length,maxlines,l,mode=0;
        !           992:        FILE*   stream;
        !           993:        unsigned lines;
1.1       root      994: 
                    995:        maxlines=cfg.level_linespermsg[useron.level];
1.1.1.2 ! root      996:        quotes_fname(useron.xedit, path, sizeof(path));
1.1       root      997:        removecase(path);
                    998: 
                    999:        if(useron.xedit) {
                   1000: 
                   1001:                SAFECOPY(path,fname);
                   1002: 
                   1003:                msg_tmp_fname(useron.xedit, msgtmp, sizeof(msgtmp));
                   1004:                if(stricmp(msgtmp,path)) {
                   1005:                        removecase(msgtmp);
                   1006:                        if(fexistcase(path))
                   1007:                                fcopy(path, msgtmp);
                   1008:                }
                   1009: 
                   1010:                editor_inf(useron.xedit,fname,nulstr,0,INVALID_SUB);
                   1011:                if(cfg.xedit[useron.xedit-1]->misc&XTRN_NATIVE)
                   1012:                        mode|=EX_NATIVE;
                   1013:                if(cfg.xedit[useron.xedit-1]->misc&XTRN_SH)
                   1014:                        mode|=EX_SH;
1.1.1.2 ! root     1015:                if(cfg.xedit[useron.xedit-1]->misc&XTRN_STDIO) {
        !          1016:                        mode|=EX_STDIO;
1.1       root     1017:                        if(cfg.xedit[useron.xedit-1]->misc&WWIVCOLOR)
                   1018:                                mode|=EX_WWIV; 
                   1019:                }
                   1020:                CLS;
                   1021:                rioctl(IOCM|PAUSE|ABORT);
1.1.1.2 ! root     1022:                if(external(cmdstr(cfg.xedit[useron.xedit-1]->rcmd,msgtmp,nulstr,NULL),mode,cfg.node_dir)!=0)
        !          1023:                        return false;
        !          1024:                l=process_edited_file(msgtmp, path, /* mode: */0, &lines);
        !          1025:                if(l>0) {
        !          1026:                        SAFEPRINTF4(str,"%s created or edited file: %s (%u bytes, %u lines)"
        !          1027:                                ,useron.alias, path, l, lines);
        !          1028:                        logline(LOG_NOTICE,nulstr,str);
        !          1029:                }
1.1       root     1030:                rioctl(IOSM|PAUSE|ABORT); 
1.1.1.2 ! root     1031:                return true; 
1.1       root     1032:        }
                   1033:        if((buf=(char *)malloc(maxlines*MAX_LINE_LEN))==NULL) {
                   1034:                errormsg(WHERE,ERR_ALLOC,nulstr,maxlines*MAX_LINE_LEN);
1.1.1.2 ! root     1035:                return false; 
1.1       root     1036:        }
                   1037:        if((file=nopen(fname,O_RDONLY))!=-1) {
1.1.1.2 ! root     1038:                length=(long)filelength(file);
1.1       root     1039:                if(length>(long)maxlines*MAX_LINE_LEN) {
                   1040:                        close(file);
                   1041:                        free(buf); 
                   1042:                        attr(cfg.color[clr_err]);
                   1043:                        bprintf("\7\r\nFile size (%lu bytes) is larger than %lu (maxlines: %lu).\r\n"
                   1044:                                ,length, (ulong)maxlines*MAX_LINE_LEN, maxlines);
1.1.1.2 ! root     1045:                        return false;
1.1       root     1046:                }
                   1047:                if(read(file,buf,length)!=length) {
                   1048:                        close(file);
                   1049:                        free(buf);
                   1050:                        errormsg(WHERE,ERR_READ,fname,length);
1.1.1.2 ! root     1051:                        return false; 
1.1       root     1052:                }
                   1053:                buf[length]=0;
                   1054:                close(file); 
                   1055:        }
                   1056:        else {
                   1057:                buf[0]=0;
                   1058:                bputs(text[NewFile]); 
                   1059:        }
                   1060:        if(!msgeditor(buf,nulstr,nulstr)) {
                   1061:                free(buf);
1.1.1.2 ! root     1062:                return false; 
1.1       root     1063:        }
                   1064:        bputs(text[Saving]);
1.1.1.2 ! root     1065:        if((stream=fnopen(NULL,fname,O_CREAT|O_WRONLY|O_TRUNC))==NULL) {
1.1       root     1066:                errormsg(WHERE,ERR_OPEN,fname,O_CREAT|O_WRONLY|O_TRUNC);
                   1067:                free(buf);
1.1.1.2 ! root     1068:                return false; 
1.1       root     1069:        }
1.1.1.2 ! root     1070:        l=process_edited_text(buf,stream,/* mode: */0,&lines);
1.1       root     1071:        bprintf(text[SavedNBytes],l,lines);
1.1.1.2 ! root     1072:        fclose(stream);
1.1       root     1073:        free(buf);
1.1.1.2 ! root     1074:        SAFEPRINTF4(str,"%s created or edited file: %s (%u bytes, %u lines)"
        !          1075:                ,useron.alias, fname, l, lines);
        !          1076:        logline(nulstr,str);
        !          1077:        return true;
1.1       root     1078: }
                   1079: 
                   1080: /*************************/
                   1081: /* Copy file attachments */
                   1082: /*************************/
                   1083: void sbbs_t::copyfattach(uint to, uint from, char *title)
                   1084: {
                   1085:        char str[128],str2[128],str3[128],*tp,*sp,*p;
                   1086: 
                   1087:        strcpy(str,title);
                   1088:        tp=str;
                   1089:        while(1) {
                   1090:                p=strchr(tp,' ');
                   1091:                if(p) *p=0;
                   1092:                sp=strrchr(tp,'/');              /* sp is slash pointer */
                   1093:                if(!sp) sp=strrchr(tp,'\\');
                   1094:                if(sp) tp=sp+1;
1.1.1.2 ! root     1095:                SAFEPRINTF3(str2,"%sfile/%04u.in/%s"  /* str2 is path/fname */
1.1       root     1096:                        ,cfg.data_dir,to,tp);
1.1.1.2 ! root     1097:                SAFEPRINTF3(str3,"%sfile/%04u.in/%s"  /* str2 is path/fname */
1.1       root     1098:                        ,cfg.data_dir,from,tp);
                   1099:                if(strcmp(str2,str3))
                   1100:                        mv(str3,str2,1);
                   1101:                if(!p)
                   1102:                        break;
                   1103:                tp=p+1; 
                   1104:        }
                   1105: }
                   1106: 
                   1107: 
                   1108: /****************************************************************************/
                   1109: /* Forwards mail (fname) to usernumber                                      */
                   1110: /* Called from function readmail                                                                                       */
                   1111: /****************************************************************************/
                   1112: void sbbs_t::forwardmail(smbmsg_t *msg, int usernumber)
                   1113: {
                   1114:        char            str[256],touser[128];
                   1115:        char            tmp[512];
                   1116:        int                     i;
                   1117:        node_t          node;
                   1118:        msghdr_t        hdr=msg->hdr;
                   1119:        idxrec_t        idx=msg->idx;
1.1.1.2 ! root     1120:        time32_t        now32;
1.1       root     1121: 
1.1.1.2 ! root     1122:        if(useron.etoday>=cfg.level_emailperday[useron.level] && !SYSOP && !(useron.exempt&FLAG('M'))) {
1.1       root     1123:                bputs(text[TooManyEmailsToday]);
                   1124:                return; 
                   1125:        }
                   1126:        if(useron.rest&FLAG('F')) {
                   1127:                bputs(text[R_Forward]);
                   1128:                return; 
                   1129:        }
                   1130:        if(usernumber==1 && useron.rest&FLAG('S')) {
                   1131:                bprintf(text[R_Feedback],cfg.sys_op);
                   1132:                return; 
                   1133:        }
                   1134:        if(usernumber!=1 && useron.rest&FLAG('E')) {
                   1135:                bputs(text[R_Email]);
                   1136:                return; 
                   1137:        }
                   1138: 
                   1139:        msg->idx.attr&=~(MSG_READ|MSG_DELETE);
                   1140:        msg->hdr.attr=msg->idx.attr;
                   1141: 
                   1142: 
                   1143:        smb_hfield_str(msg,SENDER,useron.alias);
1.1.1.2 ! root     1144:        SAFEPRINTF(str,"%u",useron.number);
1.1       root     1145:        smb_hfield_str(msg,SENDEREXT,str);
                   1146: 
1.1.1.2 ! root     1147:        /* Security logging */
        !          1148:        msg_client_hfields(msg,&client);
        !          1149:        smb_hfield_str(msg,SENDERSERVER,startup->host_name);
        !          1150: 
1.1       root     1151:        username(&cfg,usernumber,touser);
                   1152:        smb_hfield_str(msg,RECIPIENT,touser);
1.1.1.2 ! root     1153:        SAFEPRINTF(str,"%u",usernumber);
        !          1154:        smb_hfield_str(msg,RECIPIENTEXT,str);
1.1       root     1155:        msg->idx.to=usernumber;
                   1156: 
1.1.1.2 ! root     1157:        now32=time(NULL);
        !          1158:        smb_hfield(msg,FORWARDED,sizeof(time32_t),&now32);
1.1       root     1159: 
                   1160: 
                   1161:        if((i=smb_open_da(&smb))!=SMB_SUCCESS) {
                   1162:                errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
                   1163:                return; 
                   1164:        }
                   1165:        if((i=smb_incmsg_dfields(&smb,msg,1))!=SMB_SUCCESS) {
                   1166:                errormsg(WHERE,ERR_WRITE,smb.file,i);
                   1167:                return; 
                   1168:        }
                   1169:        smb_close_da(&smb);
                   1170: 
                   1171: 
                   1172:        if((i=smb_addmsghdr(&smb,msg,SMB_SELFPACK))!=SMB_SUCCESS) {
1.1.1.2 ! root     1173:                errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
1.1       root     1174:                smb_freemsg_dfields(&smb,msg,1);
                   1175:                return; 
                   1176:        }
                   1177: 
                   1178:        if(msg->hdr.auxattr&MSG_FILEATTACH)
                   1179:                copyfattach(usernumber,useron.number,msg->subj);
                   1180: 
                   1181:        bprintf(text[Forwarded],username(&cfg,usernumber,str),usernumber);
1.1.1.2 ! root     1182:        SAFEPRINTF3(str,"%s forwarded mail to %s #%d"
1.1       root     1183:                ,useron.alias
                   1184:                ,username(&cfg,usernumber,tmp)
                   1185:                ,usernumber);
                   1186:        logline("E",str);
                   1187:        msg->idx=idx;
                   1188:        msg->hdr=hdr;
                   1189: 
                   1190: 
                   1191:        if(usernumber==1) {
                   1192:                useron.fbacks++;
                   1193:                logon_fbacks++;
                   1194:                putuserrec(&cfg,useron.number,U_FBACKS,5,ultoa(useron.fbacks,tmp,10)); 
                   1195:        }
                   1196:        else {
                   1197:                useron.emails++;
                   1198:                logon_emails++;
                   1199:                putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); 
                   1200:        }
                   1201:        useron.etoday++;
                   1202:        putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10));
                   1203: 
                   1204:        for(i=1;i<=cfg.sys_nodes;i++) { /* Tell user, if online */
                   1205:                getnodedat(i,&node,0);
                   1206:                if(node.useron==usernumber && !(node.misc&NODE_POFF)
                   1207:                        && (node.status==NODE_INUSE || node.status==NODE_QUIET)) {
1.1.1.2 ! root     1208:                        SAFEPRINTF2(str,text[EmailNodeMsg],cfg.node_num,useron.alias);
1.1       root     1209:                        putnmsg(&cfg,i,str);
                   1210:                        break; 
                   1211:                } 
                   1212:        }
                   1213:        if(i>cfg.sys_nodes) {   /* User wasn't online, so leave short msg */
1.1.1.2 ! root     1214:                SAFEPRINTF(str,text[UserSentYouMail],useron.alias);
1.1       root     1215:                putsmsg(&cfg,usernumber,str); 
                   1216:        }
                   1217: }
                   1218: 
                   1219: /****************************************************************************/
                   1220: /* Auto-Message Routine ('A' from the main menu)                            */
                   1221: /****************************************************************************/
                   1222: void sbbs_t::automsg()
                   1223: {
                   1224:     char       str[256],buf[300],anon=0;
                   1225:        char    tmp[512];
                   1226:        char    automsg[MAX_PATH+1];
                   1227:     int                file;
                   1228:        time_t  now=time(NULL);
                   1229: 
1.1.1.2 ! root     1230:        SAFEPRINTF(automsg,"%smsgs/auto.msg",cfg.data_dir);
1.1       root     1231:        while(online) {
                   1232:                SYNC;
                   1233:                mnemonics(text[AutoMsg]);
                   1234:                switch(getkeys("RWQ",0)) {
                   1235:                        case 'R':
                   1236:                                printfile(automsg,P_NOABORT|P_NOATCODES);
                   1237:                                break;
                   1238:                        case 'W':
                   1239:                                if(useron.rest&FLAG('W')) {
                   1240:                                        bputs(text[R_AutoMsg]);
                   1241:                                        break; 
                   1242:                                }
                   1243:                                action=NODE_AMSG;
                   1244:                                SYNC;
                   1245:                                bputs("\r\n3 lines:\r\n");
                   1246:                                if(!getstr(str,68,K_WRAP|K_MSG))
                   1247:                                        break;
                   1248:                                strcpy(buf,str);
                   1249:                                strcat(buf,"\r\n          ");
                   1250:                                getstr(str,68,K_WRAP|K_MSG);
                   1251:                                strcat(buf,str);
                   1252:                                strcat(buf,"\r\n          ");
                   1253:                                getstr(str,68,K_MSG);
                   1254:                                strcat(str,crlf);
                   1255:                                strcat(buf,str);
                   1256:                                if(yesno(text[OK])) {
                   1257:                                        if(useron.exempt&FLAG('A')) {
                   1258:                                                if(!noyes(text[AnonymousQ]))
                   1259:                                                        anon=1; 
                   1260:                                        }
                   1261:                                        if((file=nopen(automsg,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
                   1262:                                                errormsg(WHERE,ERR_OPEN,automsg,O_WRONLY|O_CREAT|O_TRUNC);
                   1263:                                                return; 
                   1264:                                        }
                   1265:                                        if(anon)
1.1.1.2 ! root     1266:                                                SAFEPRINTF(tmp,"%.80s",text[Anonymous]);
1.1       root     1267:                                        else
1.1.1.2 ! root     1268:                                                SAFEPRINTF2(tmp,"%s #%d",useron.alias,useron.number);
        !          1269:                                        SAFEPRINTF2(str,text[AutoMsgBy],tmp,timestr(now));
1.1       root     1270:                                        strcat(str,"          ");
                   1271:                                        write(file,str,strlen(str));
                   1272:                                        write(file,buf,strlen(buf));
                   1273:                                        close(file); 
                   1274:                                }
                   1275:                                break;
                   1276:                        case 'Q':
                   1277:                                return; 
                   1278:                } 
                   1279:        }
                   1280: }
                   1281: 
                   1282: /****************************************************************************/
                   1283: /* Edits messages                                                                                                                      */
                   1284: /****************************************************************************/
                   1285: void sbbs_t::editmsg(smbmsg_t *msg, uint subnum)
                   1286: {
                   1287:        char    buf[SDT_BLOCK_LEN];
                   1288:        char    msgtmp[MAX_PATH+1];
1.1.1.2 ! root     1289:        uint16_t        xlat;
1.1       root     1290:        int     file,i,j,x;
                   1291:        long    length,offset;
                   1292:        FILE    *instream;
                   1293: 
                   1294:        if(!msg->hdr.total_dfields)
                   1295:                return;
                   1296: 
                   1297:        msg_tmp_fname(useron.xedit, msgtmp, sizeof(msgtmp));
                   1298:        removecase(msgtmp);
                   1299:        msgtotxt(msg,msgtmp,0,1);
1.1.1.2 ! root     1300:        if(!editfile(msgtmp))
        !          1301:                return;
        !          1302:        length=(long)flength(msgtmp);
1.1       root     1303:        if(length<1L)
                   1304:                return;
                   1305: 
                   1306:        length+=2;       /* +2 for translation string */
                   1307: 
                   1308:        if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
1.1.1.2 ! root     1309:                errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
1.1       root     1310:                return; 
                   1311:        }
                   1312: 
                   1313:        if((i=smb_getstatus(&smb))!=SMB_SUCCESS) {
1.1.1.2 ! root     1314:                errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
1.1       root     1315:                return; 
                   1316:        }
                   1317: 
                   1318:        if(!(smb.status.attr&SMB_HYPERALLOC)) {
                   1319:                if((i=smb_open_da(&smb))!=SMB_SUCCESS) {
                   1320:                        errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
                   1321:                        return; 
                   1322:                }
                   1323:                if((i=smb_freemsg_dfields(&smb,msg,1))!=SMB_SUCCESS)
                   1324:                        errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error); 
                   1325:        }
                   1326: 
                   1327:        msg->dfield[0].type=TEXT_BODY;                          /* Make one single data field */
                   1328:        msg->dfield[0].length=length;
                   1329:        msg->dfield[0].offset=0;
                   1330:        for(x=1;x<msg->hdr.total_dfields;x++) {         /* Clear the other data fields */
                   1331:                msg->dfield[x].type=UNUSED;                     /* so we leave the header length */
                   1332:                msg->dfield[x].length=0;                                /* unchanged */
                   1333:                msg->dfield[x].offset=0; 
                   1334:        }
                   1335: 
                   1336: 
                   1337:        if(smb.status.attr&SMB_HYPERALLOC)
                   1338:                offset=smb_hallocdat(&smb); 
                   1339:        else {
                   1340:                if((subnum!=INVALID_SUB && cfg.sub[subnum]->misc&SUB_FAST)
                   1341:                        || (subnum==INVALID_SUB && cfg.sys_misc&SM_FASTMAIL))
                   1342:                        offset=smb_fallocdat(&smb,length,1);
                   1343:                else
                   1344:                        offset=smb_allocdat(&smb,length,1);
                   1345:                smb_close_da(&smb); 
                   1346:        }
                   1347: 
                   1348:        msg->hdr.offset=offset;
                   1349:        if((file=open(msgtmp,O_RDONLY|O_BINARY))==-1
                   1350:                || (instream=fdopen(file,"rb"))==NULL) {
                   1351:                smb_unlocksmbhdr(&smb);
                   1352:                smb_freemsgdat(&smb,offset,length,1);
                   1353:                errormsg(WHERE,ERR_OPEN,msgtmp,O_RDONLY|O_BINARY);
                   1354:                return; 
                   1355:        }
                   1356: 
                   1357:        setvbuf(instream,NULL,_IOFBF,2*1024);
                   1358:        fseek(smb.sdt_fp,offset,SEEK_SET);
                   1359:        xlat=XLAT_NONE;
                   1360:        fwrite(&xlat,2,1,smb.sdt_fp);
                   1361:        x=SDT_BLOCK_LEN-2;                              /* Don't read/write more than 255 */
                   1362:        while(!feof(instream)) {
                   1363:                memset(buf,0,x);
                   1364:                j=fread(buf,1,x,instream);
                   1365:                if(j<1)
                   1366:                        break;
                   1367:                if(j>1 && (j!=x || feof(instream)) && buf[j-1]==LF && buf[j-2]==CR)
                   1368:                        buf[j-1]=buf[j-2]=0;    /* Convert to NULL */
                   1369:                fwrite(buf,j,1,smb.sdt_fp);
                   1370:                x=SDT_BLOCK_LEN; 
                   1371:        }
                   1372:        fflush(smb.sdt_fp);
                   1373:        fclose(instream);
                   1374: 
                   1375:        smb_unlocksmbhdr(&smb);
                   1376:        msg->hdr.length=(ushort)smb_getmsghdrlen(msg);
                   1377:        if((i=smb_putmsghdr(&smb,msg))!=SMB_SUCCESS)
1.1.1.2 ! root     1378:                errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
1.1       root     1379: }
                   1380: 
                   1381: /****************************************************************************/
                   1382: /* Moves a message from one message base to another                                            */
                   1383: /****************************************************************************/
                   1384: bool sbbs_t::movemsg(smbmsg_t* msg, uint subnum)
                   1385: {
                   1386:        char str[256],*buf;
                   1387:        uint i;
                   1388:        int newgrp,newsub,storage;
                   1389:        ulong offset,length;
                   1390:        smbmsg_t        newmsg=*msg;
                   1391:        smb_t           newsmb;
                   1392: 
                   1393:        for(i=0;i<usrgrps;i++)           /* Select New Group */
                   1394:                uselect(1,i,"Message Group",cfg.grp[usrgrp[i]]->lname,0);
                   1395:        if((newgrp=uselect(0,0,0,0,0))<0)
                   1396:                return(false);
                   1397: 
                   1398:        for(i=0;i<usrsubs[newgrp];i++)           /* Select New Sub-Board */
                   1399:                uselect(1,i,"Sub-Board",cfg.sub[usrsub[newgrp][i]]->lname,0);
                   1400:        if((newsub=uselect(0,0,0,0,0))<0)
                   1401:                return(false);
                   1402:        newsub=usrsub[newgrp][newsub];
                   1403: 
                   1404:        length=smb_getmsgdatlen(msg);
                   1405:        if((buf=(char *)malloc(length))==NULL) {
                   1406:                errormsg(WHERE,ERR_ALLOC,smb.file,length);
                   1407:                return(false); 
                   1408:        }
                   1409: 
                   1410:        fseek(smb.sdt_fp,msg->hdr.offset,SEEK_SET);
                   1411:        fread(buf,length,1,smb.sdt_fp);
                   1412: 
1.1.1.2 ! root     1413:        SAFEPRINTF2(newsmb.file,"%s%s",cfg.sub[newsub]->data_dir,cfg.sub[newsub]->code);
1.1       root     1414:        newsmb.retry_time=cfg.smb_retry_time;
                   1415:        newsmb.subnum=newsub;
                   1416:        if((i=smb_open(&newsmb))!=SMB_SUCCESS) {
                   1417:                free(buf);
                   1418:                errormsg(WHERE,ERR_OPEN,newsmb.file,i,newsmb.last_error);
                   1419:                return(false); 
                   1420:        }
                   1421: 
                   1422:        if(filelength(fileno(newsmb.shd_fp))<1) {        /* Create it if it doesn't exist */
                   1423:                newsmb.status.max_crcs=cfg.sub[newsub]->maxcrcs;
                   1424:                newsmb.status.max_msgs=cfg.sub[newsub]->maxmsgs;
                   1425:                newsmb.status.max_age=cfg.sub[newsub]->maxage;
                   1426:                newsmb.status.attr=cfg.sub[newsub]->misc&SUB_HYPER ? SMB_HYPERALLOC :0;
                   1427:                if((i=smb_create(&newsmb))!=SMB_SUCCESS) {
                   1428:                        free(buf);
                   1429:                        smb_close(&newsmb);
                   1430:                        errormsg(WHERE,ERR_CREATE,newsmb.file,i,newsmb.last_error);
                   1431:                        return(false); 
                   1432:                } 
                   1433:        }
                   1434: 
                   1435:        if((i=smb_locksmbhdr(&newsmb))!=SMB_SUCCESS) {
                   1436:                free(buf);
                   1437:                smb_close(&newsmb);
                   1438:                errormsg(WHERE,ERR_LOCK,newsmb.file,i,newsmb.last_error);
                   1439:                return(false); 
                   1440:        }
                   1441: 
                   1442:        if((i=smb_getstatus(&newsmb))!=SMB_SUCCESS) {
                   1443:                free(buf);
                   1444:                smb_close(&newsmb);
                   1445:                errormsg(WHERE,ERR_READ,newsmb.file,i,newsmb.last_error);
                   1446:                return(false); 
                   1447:        }
                   1448: 
                   1449:        if(newsmb.status.attr&SMB_HYPERALLOC) {
                   1450:                offset=smb_hallocdat(&newsmb);
                   1451:                storage=SMB_HYPERALLOC; 
                   1452:        }
                   1453:        else {
                   1454:                if((i=smb_open_da(&newsmb))!=SMB_SUCCESS) {
                   1455:                        free(buf);
                   1456:                        smb_close(&newsmb);
                   1457:                        errormsg(WHERE,ERR_OPEN,newsmb.file,i,newsmb.last_error);
                   1458:                        return(false); 
                   1459:                }
                   1460:                if(cfg.sub[newsub]->misc&SUB_FAST) {
                   1461:                        offset=smb_fallocdat(&newsmb,length,1);
                   1462:                        storage=SMB_FASTALLOC; 
                   1463:                }
                   1464:                else {
                   1465:                        offset=smb_allocdat(&newsmb,length,1);
                   1466:                        storage=SMB_SELFPACK; 
                   1467:                }
                   1468:                smb_close_da(&newsmb); 
                   1469:        }
                   1470: 
                   1471:        newmsg.hdr.offset=offset;
                   1472:        newmsg.hdr.version=smb_ver();
                   1473: 
                   1474:        fseek(newsmb.sdt_fp,offset,SEEK_SET);
                   1475:        fwrite(buf,length,1,newsmb.sdt_fp);
                   1476:        fflush(newsmb.sdt_fp);
                   1477:        free(buf);
                   1478: 
                   1479:        i=smb_addmsghdr(&newsmb,&newmsg,storage);       // calls smb_unlocksmbhdr() 
                   1480:        smb_close(&newsmb);
                   1481: 
                   1482:        if(i) {
                   1483:                errormsg(WHERE,ERR_WRITE,newsmb.file,i,newsmb.last_error);
                   1484:                smb_freemsg_dfields(&newsmb,&newmsg,1);
                   1485:                return(false); 
                   1486:        }
                   1487: 
                   1488:        bprintf("\r\nMoved to %s %s\r\n\r\n"
                   1489:                ,cfg.grp[usrgrp[newgrp]]->sname,cfg.sub[newsub]->lname);
1.1.1.2 ! root     1490:        safe_snprintf(str,sizeof(str),"%s moved message from %s %s to %s %s"
1.1       root     1491:                ,useron.alias
                   1492:                ,cfg.grp[newgrp]->sname,cfg.sub[newsub]->sname
                   1493:                ,cfg.grp[cfg.sub[subnum]->grp]->sname,cfg.sub[subnum]->sname);
                   1494:        logline("M+",str);
                   1495:        signal_sub_sem(&cfg,newsub);
                   1496: 
                   1497:        return(true);
                   1498: }
                   1499: 
                   1500: ushort sbbs_t::chmsgattr(ushort attr)
                   1501: {
                   1502:        int ch;
                   1503: 
                   1504:        while(online && !(sys_status&SS_ABORT)) {
                   1505:                CRLF;
                   1506:                show_msgattr(attr);
                   1507:                menu("msgattr");
                   1508:                ch=getkey(K_UPPER);
                   1509:                if(ch)
                   1510:                        bprintf("%c\r\n",ch);
                   1511:                switch(ch) {
                   1512:                        case 'P':
                   1513:                                attr^=MSG_PRIVATE;
                   1514:                                break;
                   1515:                        case 'R':
                   1516:                                attr^=MSG_READ;
                   1517:                                break;
                   1518:                        case 'K':
                   1519:                                attr^=MSG_KILLREAD;
                   1520:                                break;
                   1521:                        case 'A':
                   1522:                                attr^=MSG_ANONYMOUS;
                   1523:                                break;
                   1524:                        case 'N':   /* Non-purgeable */
                   1525:                                attr^=MSG_PERMANENT;
                   1526:                                break;
                   1527:                        case 'M':
                   1528:                                attr^=MSG_MODERATED;
                   1529:                                break;
                   1530:                        case 'V':
                   1531:                                attr^=MSG_VALIDATED;
                   1532:                                break;
                   1533:                        case 'D':
                   1534:                                attr^=MSG_DELETE;
                   1535:                                break;
                   1536:                        case 'L':
                   1537:                                attr^=MSG_LOCKED;
                   1538:                                break;
                   1539:                        default:
                   1540:                                return(attr); 
                   1541:                } 
                   1542:        }
                   1543:        return(attr);
                   1544: }

unix.superglobalmegacorp.com

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