...
 
Commits (2)
  • Rob Swindell's avatar
    When printing a file one line at a time, don't use putmsg() · 1510b3e2
    Rob Swindell authored
    Fix problem introduced in
    b1ecd9b6 (August 8, 2019)
    
    When sbbs_t::printfile() is used to display a file that is < 2MB in size
    and the P_OPENCLOSE mode flag was not specified, the file is read and
    displayed one line at a time. This allows for the quick display of very
    large files. This was accomlished by calling sbbs_t::putmsg() for each
    line. Unfortunately, putmsg() would save and restore console mode flags
    like the auto-screen pause control flags stored in sbbs_t::sys_misc
    so this would render some features like the POFF @-code, inoperable.
    This problem was reported by WitNik with files displayed from
    Bulleeye! Bulletins.
    
    Other issues were discovered with the WORDWRAP/WRAPOFF @-codes.
    
    Fixed with the addition of sbbs_t::putmsgfrag() which is used by
    printfile() to display a message fragment (one line) without
    saving/restoring console state flags.
    1510b3e2
  • Rob Swindell's avatar
    82016519
......@@ -38,6 +38,7 @@
#include "sbbs.h"
#include "utf8.h"
#include "petdefs.h"
#ifndef PRINTFILE_MAX_LINE_LEN
#define PRINTFILE_MAX_LINE_LEN (8*1024)
......@@ -126,9 +127,15 @@ bool sbbs_t::printfile(const char* fname, long mode, long org_cols, JSObject* ob
}
free(buf);
} else { // Line-at-a-time mode
ulong sys_status_sav = sys_status;
enum output_rate output_rate = cur_output_rate;
uint tmpatr = curatr;
ulong orgcon = console;
attr_sp = 0; /* clear any saved attributes */
if(!(mode&P_SAVEATR))
attr(LIGHTGRAY);
if(mode&P_NOPAUSE)
sys_status |= SS_PAUSEOFF;
if(length > PRINTFILE_MAX_LINE_LEN)
length = PRINTFILE_MAX_LINE_LEN;
if((buf=(char*)malloc(length+1L))==NULL) {
......@@ -141,13 +148,24 @@ bool sbbs_t::printfile(const char* fname, long mode, long org_cols, JSObject* ob
break;
if((mode&P_UTF8) && !term_supports(UTF8))
utf8_normalize_str(buf);
if(putmsg(buf, mode|P_SAVEATR, org_cols, obj) != '\0') // early-EOF?
if(putmsgfrag(buf, &mode, org_cols, obj) != '\0') // early-EOF?
break;
}
free(buf);
fclose(stream);
if(!(mode&P_SAVEATR))
if(!(mode&P_SAVEATR)) {
console = orgcon;
attr(tmpatr);
}
if(!(mode&P_NOATCODES) && cur_output_rate != output_rate)
set_output_rate(output_rate);
if(mode&P_PETSCII)
outcom(PETSCII_UPPERLOWER);
attr_sp=0; /* clear any saved attributes */
/* Restore original settings of Forced Pause On/Off */
sys_status &= ~(SS_PAUSEOFF|SS_PAUSEON);
sys_status |= (sys_status_sav&(SS_PAUSEOFF|SS_PAUSEON));
}
if((mode&P_NOABORT || rip) && online==ON_REMOTE) {
......
......@@ -53,35 +53,61 @@
char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
{
uint tmpatr;
char tmp2[256],tmp3[128];
char ret;
char* str=(char*)buf;
uchar exatr=0;
int orgcon=console,i;
ulong l=0,sys_status_sav=sys_status;
uint lines_printed = 0;
ulong orgcon=console;
ulong sys_status_sav=sys_status;
enum output_rate output_rate = cur_output_rate;
struct mouse_hotspot hot_spot = {0};
hot_attr = 0;
hungry_hotspots = true;
attr_sp=0; /* clear any saved attributes */
tmpatr=curatr; /* was lclatr(-1) */
if(!(mode&P_SAVEATR))
attr(LIGHTGRAY);
if(mode&P_NOPAUSE)
sys_status|=SS_PAUSEOFF;
str = auto_utf8(str, &mode);
char ret = putmsgfrag(buf, &mode, org_cols, obj);
if(!(mode&P_SAVEATR)) {
console=orgcon;
attr(tmpatr);
}
if(!(mode&P_NOATCODES) && cur_output_rate != output_rate)
set_output_rate(output_rate);
if(mode&P_PETSCII)
outcom(PETSCII_UPPERLOWER);
attr_sp=0; /* clear any saved attributes */
/* Restore original settings of Forced Pause On/Off */
sys_status&=~(SS_PAUSEOFF|SS_PAUSEON);
sys_status|=(sys_status_sav&(SS_PAUSEOFF|SS_PAUSEON));
return(ret);
}
// Print a message fragment, doesn't save/restore any console states (e.g. attributes, auto-pause)
char sbbs_t::putmsgfrag(const char* buf, long* mode, long org_cols, JSObject* obj)
{
char tmp2[256],tmp3[128];
char* str=(char*)buf;
uchar exatr=0;
int i;
ulong l=0;
uint lines_printed = 0;
struct mouse_hotspot hot_spot = {0};
hot_attr = 0;
hungry_hotspots = true;
str = auto_utf8(str, mode);
size_t len = strlen(str);
long term = term_supports();
if(!(mode&P_NOATCODES) && memcmp(str, "@WRAPOFF@", 9) == 0) {
mode &= ~P_WORDWRAP;
if(!((*mode)&P_NOATCODES) && memcmp(str, "@WRAPOFF@", 9) == 0) {
(*mode) &= ~P_WORDWRAP;
l += 9;
}
if(mode&P_WORDWRAP) {
if((*mode)&P_WORDWRAP) {
char* wrapoff = NULL;
if(!(mode&P_NOATCODES)) {
if(!((*mode)&P_NOATCODES)) {
wrapoff = strstr((char*)str+l, "@WRAPOFF@");
if(wrapoff != NULL)
*wrapoff = 0;
......@@ -90,11 +116,12 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
if(org_cols < TERM_COLS_MIN)
org_cols = TERM_COLS_DEFAULT;
if((wrapped=::wordwrap((char*)str+l, cols - 1, org_cols - 1, /* handle_quotes: */TRUE
,/* is_utf8: */INT_TO_BOOL(mode&P_UTF8))) == NULL)
,/* is_utf8: */INT_TO_BOOL((*mode)&P_UTF8))) == NULL)
errormsg(WHERE,ERR_ALLOC,"wordwrap buffer",0);
else {
truncsp_lines(wrapped);
putmsg(wrapped, mode&(~P_WORDWRAP));
(*mode) &= ~P_WORDWRAP;
putmsgfrag(wrapped, mode);
free(wrapped);
l=strlen(str);
if(wrapoff != NULL)
......@@ -102,7 +129,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
}
}
while(l < len && (mode&P_NOABORT || !msgabort()) && online) {
while(l < len && ((*mode)&P_NOABORT || !msgabort()) && online) {
switch(str[l]) {
case '\r':
case '\n':
......@@ -116,10 +143,10 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
}
// fallthrough
default: // printing char
if((mode&P_TRUNCATE) && column >= (cols - 1)) {
if(((*mode)&P_TRUNCATE) && column >= (cols - 1)) {
l++;
continue;
} else if(mode&P_WRAP) {
} else if((*mode)&P_WRAP) {
if(org_cols) {
if(column > (org_cols - 1)) {
CRLF;
......@@ -133,7 +160,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
break;
}
if(str[l]==CTRL_A && str[l+1]!=0) {
if(str[l+1]=='"' && !(sys_status&SS_NEST_PF) && !(mode&P_NOATCODES)) { /* Quote a file */
if(str[l+1]=='"' && !(sys_status&SS_NEST_PF) && !((*mode)&P_NOATCODES)) { /* Quote a file */
l+=2;
i=0;
while(i<(int)sizeof(tmp2)-1 && isprint((unsigned char)str[l]) && str[l]!='\\' && str[l]!='/')
......@@ -171,7 +198,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
outchar(ESC); /* Convert `[ and [ to ESC[ */
l++;
}
else if(!(mode&P_NOXATTRS)
else if(!((*mode)&P_NOXATTRS)
&& (cfg.sys_misc&SM_PCBOARD) && str[l]=='@' && str[l+1]=='X'
&& isxdigit((unsigned char)str[l+2]) && isxdigit((unsigned char)str[l+3])) {
sprintf(tmp2,"%.2s",str+l+2);
......@@ -192,7 +219,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
exatr=1;
l+=4;
}
else if(!(mode&P_NOXATTRS)
else if(!((*mode)&P_NOXATTRS)
&& (cfg.sys_misc&SM_WILDCAT) && str[l]=='@' && str[l+3]=='@'
&& isxdigit((unsigned char)str[l+1]) && isxdigit((unsigned char)str[l+2])) {
sprintf(tmp2,"%.2s",str+l+1);
......@@ -200,7 +227,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
// exatr=1;
l+=4;
}
else if(!(mode&P_NOXATTRS)
else if(!((*mode)&P_NOXATTRS)
&& (cfg.sys_misc&SM_RENEGADE) && str[l]=='|' && isdigit((unsigned char)str[l+1])
&& isdigit((unsigned char)str[l+2]) && !(useron.misc&RIP)) {
sprintf(tmp2,"%.2s",str+l+1);
......@@ -216,7 +243,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
exatr=1;
l+=3; /* Skip |xx */
}
else if(!(mode&P_NOXATTRS)
else if(!((*mode)&P_NOXATTRS)
&& (cfg.sys_misc&SM_CELERITY) && str[l]=='|' && isalpha((unsigned char)str[l+1])
&& !(useron.misc&RIP)) {
switch(str[l+1]) {
......@@ -275,7 +302,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
exatr=1;
l+=2; /* Skip |x */
} /* Skip second digit if it exists */
else if(!(mode&P_NOXATTRS)
else if(!((*mode)&P_NOXATTRS)
&& (cfg.sys_misc&SM_WWIV) && str[l]==CTRL_C && isdigit((unsigned char)str[l+1])) {
exatr=1;
switch(str[l+1]) {
......@@ -333,7 +360,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
}
if(str[l]=='!' && str[l+1]=='|' && useron.misc&RIP) /* RIP */
lncntr=0; /* so defeat pause */
if(str[l]=='@' && !(mode&P_NOATCODES)) {
if(str[l]=='@' && !((*mode)&P_NOATCODES)) {
if(memcmp(str+l, "@EOF@", 5) == 0)
break;
if(memcmp(str+l, "@CLEAR@", 7) == 0) {
......@@ -366,17 +393,17 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
}
if(memcmp(str+l, "@WORDWRAP@", 10) == 0) {
l += 10;
putmsg(str+l, mode|P_WORDWRAP, org_cols);
break;
(*mode) |= P_WORDWRAP;
return putmsgfrag(str+l, mode, org_cols);
}
if(memcmp(str+l, "@QON@", 5) == 0) { // Allow the file display to be aborted (PCBoard)
l += 5;
mode &= ~P_NOABORT;
(*mode) &= ~P_NOABORT;
continue;
}
if(memcmp(str+l, "@QOFF@", 6) == 0) { // Do not allow the display of teh file to be aborted (PCBoard)
l += 6;
mode |= P_NOABORT;
(*mode) |= P_NOABORT;
continue;
}
bool was_tos = (row == 0);
......@@ -387,7 +414,7 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
if(i) /* if valid string, go to top */
continue;
}
if(mode&P_CPM_EOF && str[l]==CTRL_Z)
if((*mode)&P_CPM_EOF && str[l]==CTRL_Z)
break;
if(hot_attr) {
if(curatr == hot_attr && str[l] > ' ') {
......@@ -403,12 +430,12 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
}
}
size_t skip = sizeof(char);
if(mode&P_PETSCII) {
if((*mode)&P_PETSCII) {
if(term&PETSCII)
outcom(str[l]);
else
petscii_to_ansibbs(str[l]);
} else if((str[l]&0x80) && (mode&P_UTF8)) {
} else if((str[l]&0x80) && ((*mode)&P_UTF8)) {
if(term&UTF8)
outcom(str[l]);
else
......@@ -422,23 +449,6 @@ char sbbs_t::putmsg(const char *buf, long mode, long org_cols, JSObject* obj)
l += skip;
}
}
if(!(mode&P_SAVEATR)) {
console=orgcon;
attr(tmpatr);
}
if(!(mode&P_NOATCODES) && cur_output_rate != output_rate)
set_output_rate(output_rate);
if(mode&P_PETSCII)
outcom(PETSCII_UPPERLOWER);
attr_sp=0; /* clear any saved attributes */
ret=str[l];
/* Restore original settings of Forced Pause On/Off */
sys_status&=~(SS_PAUSEOFF|SS_PAUSEON);
sys_status|=(sys_status_sav&(SS_PAUSEOFF|SS_PAUSEON));
return(ret);
return str[l];
}
......@@ -674,6 +674,7 @@ public:
char* quotes_fname(int xedit, char* buf, size_t len);
char* msg_tmp_fname(int xedit, char* fname, size_t len);
char putmsg(const char *str, long mode, long org_cols = 0, JSObject* obj = NULL);
char putmsgfrag(const char* str, long* mode, long org_cols = 0, JSObject* obj = NULL);
bool msgabort(void);
bool email(int usernumber, const char *top = NULL, const char *title = NULL
, long mode = WM_NONE, smb_t* resmb = NULL, smbmsg_t* remsg = NULL);
......