|
|
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"EWRAP))
! 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"EALL) {
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"ENONE)
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.