proboard/IO.CPP

1066 lines
23 KiB
C++
Raw Permalink Normal View History

#define Use_MsgBase
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <tswin.hpp>
#include <time.h>
#include <io.h>
#include <dos.h>
#include "desqview.hpp"
#include "proboard.hpp"
#include "fossil.hpp"
static String align_string(char *s , int width , int alignment);
static void near
nocarrier()
{
if(ignore_carrier) return;
dword ticks = clockticks();
for(;clockdiff(ticks)<10;) // Check for 1/2 second
{
msleep(100);
if(fos_carrier(io.port)) return;
}
LOG("Carrier lost!");
exit_proboard();
}
static byte conversion[256];
void
fossilio::init(int p,long b)
{
byte baudcode;
for(int i=0;i<256;i++) conversion[i]=i;
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='+';
conversion[(byte)'<EFBFBD>']='-';
conversion[(byte)'<EFBFBD>']='-';
conversion[(byte)'<EFBFBD>']='|';
conversion[(byte)'<EFBFBD>']='|';
conversion[(byte)'<EFBFBD>']='#';
conversion[(byte)'<EFBFBD>']='*';
conversion[(byte)'']='^';
conversion[(byte)'']='v';
conversion[(byte)'<EFBFBD>']='#';
conversion[(byte)'<EFBFBD>']='#';
conversion[(byte)'<EFBFBD>']='#';
port=p;
baud=b;
stopenabled=0;
show_local = TRUE;
show_remote = TRUE;
more_func = NULLFUNC;
inputbuffer.clear();
if(baud)
{
switch(baud)
{
case 300L: baudcode=0x43; break;
case 1200L: baudcode=0x83; break;
case 2400L: baudcode=0xA3; break;
case 4800L: baudcode=0xC3; break;
case 7200L:
case 9600L: baudcode=0xE3; break;
case 12000L:
case 14400L:
case 16800L:
case 19200L: baudcode=0x03; break;
default : baudcode=0x23; break;
}
fos_init(port);
fos_setbps(port,baudcode);
fos_flowctl(port,2);
sleep(1);
}
if(outputBuffer == NULL)
outputBuffer = new byte[cfg.IObuffersize];
bufferPtr = 0;
SCREEN.disableCursor();
}
void
fossilio::clearinput()
{
fos_purgeinput(port);
}
fossilio::~fossilio()
{
cooldown();
if(outputBuffer != NULL)
delete [] outputBuffer;
}
void fossilio::cooldown()
{
if(baud && baud != 65535L)
{
fos_purgeoutput(port);
fos_deinit(port);
sleep(1);
}
}
void
fossilio::heatup()
{
if(baud)
{
fos_init(port);
sleep(1);
}
bufferPtr = 0;
}
byte
fossilio::readkey()
{
if(KB.hit())
{
KEY key=KB.get();
if(key>256)
{
sysopkey(key);
return 0;
}
else
{
external=0;
return (byte)key;
}
}
static dword prevticks = 0;
if(clockdiff(prevticks)>90)
{
static int inchatreq=0;
prevticks = clockticks();
SCRAMBLE();
timer.check();
if(!access(form("%sDOWN.%d",syspath,node_number),0))
{
io << S_SYSTEM_GOING_DOWN;
LOG("Going down on external request");
File f;
f.open(form("%sISDOWN.%d",syspath,node_number),fmode_create|fmode_write);
f.close();
exit_proboard(100);
}
if(!inchatreq && cfg.numnodes>1 && !chatflag)
{
user_online uo;
int cht=uo.check_chat();
if(cht)
{
inchatreq=1;
uo.read(cht);
io << "\n\n" << S_USER_REQUESTS_CHAT(uo.name,form("%d",cht));
if(ask(1))
{
uo.setstatus(UO_CHATTING);
io << "\n\n" << S_MULTILINE_CHAT_STARTED;
multilinechat(cht);
io << "\n\n" << S_MULTILINE_CHAT_ENDED << "\n\n" << S_PRESS_ENTER_TO_CONTINUE;
uo.setstatus(UO_BROWSING);
}
else
{
uo.setstatus(UO_BUSY);
}
inchatreq=0;
}
}
}
if(!baud) return 0;
FOS_STATUS status = fos_status(port);
if(!status_carrier(status)) nocarrier();
if(status_byteready(status))
{
external = 1;
return fos_getch(port);
}
return 0;
}
void
fossilio::flush()
{
SCREEN.placeCursor();
if(bufferPtr)
{
for(;;)
{
FOS_STATUS s = fos_status(port);
if(!(s & FSTAT_CARRIER)) nocarrier();
word x = fos_sendblock(port,outputBuffer,bufferPtr);
if(x >= bufferPtr) break;
bufferPtr -= x;
memmove( outputBuffer , &outputBuffer[x] , bufferPtr);
}
bufferPtr = 0;
}
}
fossilio&
fossilio::operator<<(char c)
{
if(c=='\f' && !cls_mode && user_recnr>=0 && !SCREEN.inEscape()) return *this;
if(c=='\f' && !SCREEN.inEscape())
{
color(COLOR_WHITE);
linecounter(0);
}
if(c=='\n' && !SCREEN.inEscape()) (*this) << '\r';
if(no_ibm) c=conversion[(byte)c];
if(byte(c) == byte(255))
{
flush();
return *this;
}
if(baud && show_remote)
{
if(cfg.IObuffersize == 1)
{
for(;;)
{
FOS_STATUS s = fos_status(port);
if(!(s & FSTAT_CARRIER)) nocarrier();
if(s & FSTAT_BUFEMPTY) break;
}
fos_send(port,c);
}
else
{
outputBuffer[bufferPtr++] = c;
if(bufferPtr == cfg.IObuffersize) flush();
}
}
if(show_local) SCREEN << c;
return *this;
}
fossilio&
fossilio::operator<<(char *s)
{
send(s);
return *this;
}
byte
fossilio::send(char *str,char *hotkeys)
{
if(hotkeys)
strupr(hotkeys);
for(;*str;str++)
{
byte c=0;
if(SCREEN.inEscape())
{
(*this) << (*str);
continue;
}
if(stopenabled || hotkeys)
c = toupper(readkey());
if(hotkeys && c)
if(strchr(hotkeys,c))
{
return c;
}
if(c=='S')
{
stopped = TRUE;
flush();
return 1;
}
if(c=='P')
wait("P\r");
c = *str;
if(c=='\t')
{
wait('\r');
continue;
}
if(c == 26)
{
fullcolor(*(++str));
continue;
}
if(c<8 && c>0)
{
color(c);
continue;
}
if(c == 24 || c == 25)
{
int l = int(*(str+1));
char *fname = new char[l+1];
strncpy(fname,str+2,l);
fname[l] = '\0';
if(c == 24)
run_sdkfile(fname);
else
showansasc(fname);
str += l+1;
delete [] fname;
continue;
}
if(c<0x18 && c>0x10 && c!=0x16)
{
color((c-0x10)|0x80);
}
else
{
(*this) << c;
}
}
return 0;
}
#pragma warn -def
const int ALIGN_LEFT = 0,
ALIGN_RIGHT = 1,
ALIGN_CENTER = 2;
byte
fossilio::sendfile(char *fn,char *hotkeys)
{
bool fflag = FALSE,
kflag = FALSE,
moreok = TRUE,
stopok = TRUE,
avt_compr = FALSE;
int alignment = ALIGN_LEFT;
String str;
if(rip_mode && (!show_local || !show_remote))
{
moreok = FALSE;
stopok = FALSE;
}
static char *on_string = "ON " , *off_string = "OFF";
int fieldwidth;
byte avt_compr_char = '\0';
File f(fn,fmode_read,1024);
if(!f.opened()) return 2;
if(hotkeys) strupr(hotkeys);
linecounter(0);
for(;;)
{
byte c=toupper(readkey());
if(hotkeys && c) if(strchr(hotkeys,c))
{
return c;
}
if(c=='S' && stopok)
{
stopped=1;
flush();
return 1;
}
if(c=='P') wait("\rP");
int x=f.readByte();
if(x<0) break;
byte input=(byte)x;
if(avt_compr)
{
if(fflag || kflag)
{
if(!avt_compr_char)
{
avt_compr_char = input;
}
else
{
if(avt_compr_char=='@' || avt_compr_char=='#' || avt_compr_char=='%')
{
fieldwidth += input;
switch(avt_compr_char)
{
case '@': alignment = ALIGN_LEFT; break;
case '#': alignment = ALIGN_RIGHT; break;
case '%': alignment = ALIGN_CENTER; break;
}
}
avt_compr = FALSE;
}
}
else
{
avt_compr = FALSE;
(*this) << char(25) << input;
}
continue;
}
if(SCREEN.inEscape())
{
(*this) << input;
continue;
}
if(input == 0x19)
{
avt_compr = TRUE;
avt_compr_char = '\0';
continue;
}
if((fflag || kflag) && (input=='@' || input=='#' || input=='%'))
{
fieldwidth++;
switch(input)
{
case '@': alignment = ALIGN_LEFT; break;
case '#': alignment = ALIGN_RIGHT; break;
case '%': alignment = ALIGN_CENTER; break;
}
continue;
}
if(fflag)
{
switch(input)
{
case 'A': str = user.name; break;
case 'B': str = user.city; break;
case 'C': str = user.passWord; break;
case 'D': str = user.dataPhone; break;
case 'E': str = user.voicePhone; break;
case 'F': str = user.lastDate.format("D MMM CCYY"); break;
case 'G': str = user.lastTime.format("HH:MM:SS"); break;
case 'H':
case 'I':
case 'J':
case 'K': {
char s[33];
user.aFlags.flagstostr(s);
str = s;
} break;
case 'L': str = form("%d",user.credit); break;
case 'M': str = form("%lu",user.msgsPosted); break;
case 'N': str = form("%d",user.highMsgRead); break;
case 'O': str = form("%u",user.level); break;
case 'P': str = form("%lu",user.timesCalled); break;
case 'Q': str = form("%lu",user.numUploads); break;
case 'R': str = form("%lu",user.kbUploaded); break;
case 'S': str = form("%lu",user.numDownloads); break;
case 'T': str = form("%lu",user.kbDownloaded); break;
case 'U': str = form("%ld",user.timeUsed); break;
case 'V': str = form("%d",user.screenLength); break;
case 'W': str = user_firstname; break;
case 'X': str = (ansi_mode? on_string:off_string); break;
case 'Y': str = (pause_mode? on_string:off_string); break;
case 'Z': str = (cls_mode? on_string:off_string); break;
case '0': str = (fsed_mode? on_string:off_string); break;
case '1': str = user.alias; break;
case '2': str = (stack_mode? off_string:on_string); break;
case '3': str = (no_ibm? off_string:on_string); break;
case '4': str = user.state; break;
case '5': str = user.birthDate.format("D MMM CCYY"); break;
case '6': str = user.expDate.format("D MMM CCYY"); break;
case '7': str = form("%d",int(user.expDate - Date(TODAY))); break;
case '8': str = (avatar? on_string:off_string); break;
case '9': str = (avtplus? on_string:off_string); break;
case '>': str = user.forwardTo; break;
case '<': str = date_formats_long[user.dateFormat]; break;
case '[': str = form("%ld",long(download_limit)-user.kbToday); break;
case '!': if(timer.online()<download_delay) str = form("%d",download_delay-timer.online());
else str = "0";
break;
case '$': str = user.address1; break;
case '\'': str = user.address2; break;
case '&': str = user.address3; break;
case '`': switch(user.sex)
{
case 1: str = S_MALE; break;
case 2: str = S_FEMALE; break;
default: str = S_UNKNOWN; break;
}
break;
case '~': str = form("%d",download_delay); break;
case ':': str = user.firstDate.format("D MMM CCYY"); break;
case '\"': str = user.country; break;
case '*': str = form("%d",user.fileGroup); break;
case '+': str = form("%d",user.msgGroup); break;
case '(': {
AreaGroup group;
File f(FileName(syspath,"FGROUPS.PB"));
f.seek(long(user.fileGroup-1) * sizeof(AreaGroup));
if(f.read(&group,sizeof(AreaGroup)) != sizeof(AreaGroup))
str = "";
else
str = group.name;
}
break;
case ')': {
AreaGroup group;
File f(FileName(syspath,"MGROUPS.PB"));
f.seek(long(user.msgGroup-1) * sizeof(AreaGroup));
if(f.read(&group,sizeof(AreaGroup)) != sizeof(AreaGroup))
str = "";
else
str = group.name;
}
break;
case '=' : str = user.faxPhone; break;
case '\\': str = user.language; break;
case '^' : break;
//------------
// New in v2.2
//------------
case ';':
if ( cfg.hidePassword )
{
str = String( cfg.pwdchar, strlen( user.passWord ) );
}
else
{
str = user.passWord;
}
break;
}
(*this) << align_string(str, fieldwidth , alignment);
fflag=0;
continue;
}
if(kflag)
{
Date dd(TODAY);
Time tt(NOW);
str.clear();
switch(input)
{
case 'A': str = form("%ld",totalcalls); break;
case 'B': str = lastcaller.name; break;
case 'C': str = form("%ld",msgbase.totalMsgs()); break;
case 'D': str = form("%d",0/*minfo.low*/); break;
case 'E': str = form("%d",0/*minfo.high*/); break;
case 'F': str = form("%d",num_yells); break;
case 'G': str = days_full[dd.weekDay()]; break;
case 'H': str = form("%d",num_users); break;
case 'I': str = tt.format("HH:MM"); break;
case 'J': str = dd.format("DD MMM CCYY");break;
case 'K': str = form("%d",timer.online()); break;
case 'L': str = "0"; break;
case 'M': str = form("%ld",user.timeUsed); break;
case 'N': str = "0"; break;
case 'O': str = form("%d",timer.left()); break;
case 'P': str = VERSION; break;
case 'Q': str = form("%d",time_limit); break;
case 'R': str = form("%ld",io.baud); break;
case 'S': str = days_short[dd.weekDay()]; break;
case 'T': str = form("%d",download_limit); break;
case 'U': str = form("%d",nextevent.minutesleft()); break;
case 'V': str = form("%02d:%02d",nextevent.start[0],nextevent.start[1]); break;
case 'W': str = form("%d",node_number); break;
case 'X': LOG("Hangup from text file");
io.flush();
sleep(2);
exit_proboard();
case 'Y': {
MsgArea ma;
if(ma.read(user.msgArea))
str = ma.name;
else
str = "* None *";
} break;
case 'Z': {
FileArea fa;
if(fa.read(user.fileArea))
str = fa.name;
else
str = "* None *";
} break;
case '0': {
MsgArea ma;
ma.read(user.msgArea);
str = form("%ld",ma.numMsgs());
}
break;
case '1': str = form("%d",user.msgArea); break;
case '2': str = form("%d",user.fileArea); break;
}
(*this) << align_string(str, fieldwidth , alignment);
kflag=0;
continue;
}
fflag=kflag=fieldwidth=0;
if(input<27)
{
switch(input)
{
case 1: wait('\r');
break;
case 2: stopok = FALSE;
break;
case 3: stopok = TRUE ;
break;
case 4: moreok = TRUE ;
break;
case 5: moreok = FALSE;
break;
case 6: fflag = 1;
fieldwidth = 2;
break;
case 10: (*this) << input;
if(moreok)
if(linecounter())
{
flush();
return 1;
}
break;
case 11: kflag=1;
fieldwidth=2;
break;
//case 12: cls();
// break;
case 17: break; // XON/XOFF
case 19: break; // XON/XOFF
case 23: sleep(1);
break;
case 24: break;
case 26: break; // EOF
default: kflag = fflag = FALSE;
(*this) << input;
break;
}
}
else
(*this) << input;
}
flush();
return 0;
}
#pragma warn .def
byte
fossilio::wait()
{
SCREEN.placeCursor();
timer.check();
timer.clearinactivity();
flush();
byte c;
if(comstack.pollnext()) return comstack.getnext();
redo:
c = inputbuffer.getnext();
if(c)
{
external = 0;
return c;
}
while(!(c=readkey()))
{
static unsigned long ticks = clockticks();
if(clockdiff(ticks)>90) // Update info-window every 5 seconds.
{
update_display();
ticks = clockticks();
}
if(inputbuffer.pollnext()) goto redo;
timer.checkinactivity();
DV_timeslice();
}
return c;
}
void
fossilio::wait(char c)
{
while(toupper(wait())!=toupper(c)) {}
}
byte
fossilio::wait(char *s)
{
strupr(s);
for(;;)
{
char k = toupper(wait());
if(strchr(s,k)) return k;
}
}
void
fossilio::drawfield(int max)
{
int i;
if(ansi_mode || avatar)
{
fullcolor((SCREEN.attrib()) & (0xF) | (cfg.promptColor<<4));
if(!avatar)
{
for(i=0;i<max;i++) (*this) << ' ';
(*this) << form("\x1b[%dD",max);
}
else
{
(*this) << char(25) << ' ' << char(max);
if(avtplus)
{
(*this) << char(22) << char(25) << char(2)
<< char(22) << char(5) << char(max);
}
else
for(i=0;i<max;i++) (*this) << '\b';
}
}
}
void
fossilio::read(char *s,int max,byte mode)
{
char k;
int i=0;
if(!(mode&READMODE_NOFIELD))
drawfield(max);
i=0;
while((k=wait())!=13)
{
if(k==27 || k==10 || k==9) continue;
if(k==8)
{
if(i>0)
{
i--;
(*this) << "\b \b";
}
}
else if(i<max && (isprint(k) || (k & 0x80)))
{
switch(mode & 7)
{
case READMODE_ALL : break;
case READMODE_DIGITS : if(!isdigit(k)) continue;
break;
case READMODE_UPFIRST: if(s[i-1]=='.' || s[i-1]==' ' || s[i-1]=='-' || i==0)
k=toupper(k);
else k=tolower(k);
break;
case READMODE_UPALL : k=toupper(k);
}
s[i++]=k;
if(mode & READMODE_PWD) (*this) << cfg.pwdchar;
else (*this) << k;
}
}
io << '\r';
s[i]='\0';
if(avatar)
(*this) << char(22) << char(1) << char(SCREEN.attrib()&0x0F);
else
if(ansi_mode) (*this) << "\x1b[40m";
flush();
}
int
fossilio::read(int& i,int len)
{
long l;
int ret = read(l,(len<5)?len:5);
if(ret >= 0) i = int(l);
return ret;
}
int
fossilio::read(long& i,int len)
{
char s[10];
read(s,(len<10)?len:10,READMODE_DIGITS);
if(!s[0]) return -1;
i = atol(s);
return 0;
}
void
fossilio::hangup()
{
if(baud) fos_setdtr(port,0);
}
int
fossilio::ask(int def)
{
int ret;
String keys;
if(def)
{
io << S_ASK_YES_NO;
keys = K_ASK_YES_NO;
}
else
{
io << S_ASK_NO_YES;
keys = K_ASK_NO_YES;
}
keys << '\r';
char k = wait(keys);
if(k == keys[0])
ret = TRUE;
if(k == keys[1])
ret = FALSE;
if(k == keys[2])
ret = def;
if(ret)
(*this) << S_YES;
else
(*this) << S_NO;
(*this) << char(0xFF);
return ret;
}
void
fossilio::color(byte c)
{
current_color=c;
int blink=(int)(c & 0x80);
c &= 0x7;
if(avatar)
{
static char colors[] = { 0,4,2,6,1,5,3,7 };
(*this) << char(22) << char(1);
(*this) << char(colors[c]|8);
if(blink) (*this) << char(22) << char(2);
return;
}
if(!ansi_mode) return;
String s("\x1b[0;1;3");
s << (char)(c+'0');
if(blink) s << ";5";
s << 'm';
for(int i=0;s[i];i++) (*this) << s[i];
}
void
fossilio::cls()
{
(*this) << '\f' << char(0xFF);
}
void
fossilio::enablestop()
{
stopenabled = 1;
stopped = 0;
}
void
fossilio::disablestop()
{
stopenabled = stopped = 0;
}
static
String
align_string(char *s , int width , int alignment)
{
String ret_s;
int i,j = width-strlen(s);
if(strlen(s) >= width) return String(s);
switch(alignment)
{
case ALIGN_LEFT : for(i=0;i<width && s[i];i++) ret_s << s[i];
for( ;i<width;i++) ret_s << ' ';
break;
case ALIGN_CENTER : j = (width-strlen(s))/2;
case ALIGN_RIGHT : for(i=0 ; i<j ; i++) ret_s << ' ';
for( ; i<width && s[i-j] ; i++) ret_s << s[i-j];
for( ; i<width ; i++) ret_s << ' ';
}
return ret_s;
}