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