proboard/IO.CPP

1066 lines
23 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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)'Ú']='+';
conversion[(byte)'Ã']='+';
conversion[(byte)'À']='+';
conversion[(byte)'Â']='+';
conversion[(byte)'Å']='+';
conversion[(byte)'Á']='+';
conversion[(byte)'¿']='+';
conversion[(byte)'´']='+';
conversion[(byte)'Ù']='+';
conversion[(byte)'É']='+';
conversion[(byte)'Ë']='+';
conversion[(byte)'»']='+';
conversion[(byte)'Ì']='+';
conversion[(byte)'Î']='+';
conversion[(byte)'¹']='+';
conversion[(byte)'È']='+';
conversion[(byte)'Ê']='+';
conversion[(byte)'¼']='+';
conversion[(byte)'Ö']='+';
conversion[(byte)'Ò']='+';
conversion[(byte)'·']='+';
conversion[(byte)'Ç']='+';
conversion[(byte)'×']='+';
conversion[(byte)'']='+';
conversion[(byte)'Ó']='+';
conversion[(byte)'Ð']='+';
conversion[(byte)'½']='+';
conversion[(byte)'Õ']='+';
conversion[(byte)'Ñ']='+';
conversion[(byte)'¸']='+';
conversion[(byte)'Æ']='+';
conversion[(byte)'Ø']='+';
conversion[(byte)'µ']='+';
conversion[(byte)'Ô']='+';
conversion[(byte)'Ï']='+';
conversion[(byte)'¾']='+';
conversion[(byte)'Í']='-';
conversion[(byte)'Ä']='-';
conversion[(byte)'³']='|';
conversion[(byte)'º']='|';
conversion[(byte)'Û']='#';
conversion[(byte)'û']='*';
conversion[(byte)'']='^';
conversion[(byte)'']='v';
conversion[(byte)'°']='#';
conversion[(byte)'±']='#';
conversion[(byte)'²']='#';
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;
}