Commits (3)
/* Library to deal with legacy Pascal (e.g. Borland Turbo Pascal) data types */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU Lesser General Public License for more details: lgpl.txt or *
* https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include <climits>
#include <cstdint>
#include "gen_defs.h"
#include "xpendian.h"
namespace Pascal {
template <size_t size>
class String {
static_assert(size <= UCHAR_MAX, "PascalString size cannot be > 255");
uint8_t buf[size + 1]{};
public:
size_t len() {
return buf[0];
}
void operator = (const char* s) {
memset(buf, 0, size);
buf[0] = (uint8_t)min(size, strlen(s));
memcpy(buf + 1, s, len());
}
};
// Boolean is an 8-bit integer with only 2 possible values: TRUE and FALSE
class Boolean {
int8_t value{};
public:
void operator = (int nval) {
// Insure only TRUE or FALSE are stored in Booleans
value = INT_TO_BOOL(nval);
}
int8_t operator = (const Boolean&) {
return value;
}
};
// All multi-byte integer data types are all implicitly little-endian (x86),
// so provide automatic byte-swap (on big-endian systems) during assignment operations.
template <typename T>
class LittleEndianInteger {
T value{};
public:
void operator = (T nval) {
value = LE_INT(nval);
}
T operator = (const LittleEndianInteger&) {
return LE_INT(value);
}
};
using Integer = LittleEndianInteger<int16_t>; // Integer is a 16-bit signed integer
using Word = LittleEndianInteger<uint16_t>; // Word is a 16-bit unsigned integer
using LongInt = LittleEndianInteger<int32_t>; // LongInt is a 32-bit signed integer
using LongWord = LittleEndianInteger<uint32_t>; // LongWord is a 32-bit unsigned integer
using Byte = uint8_t; // Byte is an 8-bit unsigned integer
using Char = char; // Char is an 8-bit char
} // namespace Pascal
/* QuickBBS Structure Definitions, Source: STRUCT.290 from QuickBBS v2.90 */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU Lesser General Public License for more details: lgpl.txt or *
* http://www.fsf.org/copyleft/lesser.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#ifndef QBBSDEFS_H_
#define QBBSDEFS_H_
#include "pascal_types.hpp"
namespace QBBS {
using Pascal::String;
using Pascal::Byte;
using Pascal::Word;
using Pascal::Boolean;
using Pascal::Integer;
using Pascal::LongInt;
using Pascal::LongWord;
static const int USER_NAME_LEN = 35;
static const int USER_ATTRIB_DELETED = (1<<0);
static const int USER_ATTRIB_CLRSCRN = (1<<1);
static const int USER_ATTRIB_MORE = (1<<2);
static const int USER_ATTRIB_ANSI = (1<<3);
static const int USER_ATTRIB_NO_KILL = (1<<4);
static const int USER_ATTRIB_IGN_DL_HRS = (1<<5);
static const int USER_ATTRIB_ANSI_FSED = (1<<6);
static const int USER_ATTRIB_FEMALE = (1<<7);
static const int USER_ATTRIB2_GUEST = (1<<0);
static const int USER_ATTRIB2_SSR = (1<<1);
static const int USER_ATTRIB2_DIRTY = (1<<7);
#pragma pack(push,1) // Disk image structures must be packed
struct sysinfo {
LongInt CallCount;
String<USER_NAME_LEN> LastCallerName; // Just "LastCaller" in QuickBBS v2.75
String<USER_NAME_LEN> LastCallerAlias; // Not present in QuickBBS v2.75
Byte ExtraSpace[92];
};
struct timelog {
String<8> StartDate; // MM-DD-YY
Word BusyPerHour[24];
Word BusyPerDay[7];
};
struct user {
String<USER_NAME_LEN> Name;
String<25> Location; // "City"
// End of commonality with RemoteAccess
Byte Reserved; // Reserved, should always be 0 (used to be the password string length)
Byte Language;
LongInt PwdCrc; // Was PascalString<15> Password in QuickBBS v2.75
Word PwdChangeData,
ExpireData; // Number of days since 1/1/1900
LongInt HighMsgRead;
Byte Attrib2;
Byte ExtraSpace;
String<12> DataPhone;
String<12> HomePhone;
String<5> LastTime;
String<8> LastDate;
Byte Attrib;
LongWord Flags; // Byte[4]
Word Credit,
Pending,
TimesPosted,
ObsoleteField, // Was HighMsgRead in QuickBBS v2.75
SecLvl,
Times,
Ups,
Downs,
UpK,
DownK,
TodayK;
Integer Elapsed,
ScreenLength; // "Len" in QuickBBS STRUCT.*, "ScreenLength" in RemoteAccess STUCT.* (at different offset)
Word CombinedPtr; // Record number in COMBINED.BBS, Note: 0 signifies no combined record assigned
Word AliasPtr; // Record number in ALIAS.BBS, Note: 0 signifies no alias record assigned
LongInt Birthday; // Number of days since 1/1/1600
};
struct exitinfo {
Word BaudRate;
sysinfo SysInfo;
timelog TimeLogInfo;
user UserInfo;
Byte EventInfo[19]; // *NO LONGER* used, It should be initialized to NULL
Boolean NetMailEntered;
Boolean EchoMailEntered;
String<5> LoginTime;
String<8> LoginDate;
Integer TimeLimit; // TmLimit
LongInt LoginSec;
// End of commonality with RemoteAccess v2.52 EXITINFO.BBS definition (STRUCT.252)
LongInt Credit;
Integer UserRecNum;
Word ReadThru;
Integer PageTimes;
Integer DownLimit;
Boolean WantChat;
Byte GosubLevel;
String<8> GoSubDataType[20];
String<8> Menu;
// End of QuickBBS v2.75 EXITINFO.BBS definition (STRUCT.275)
Boolean ScreenClear,
MorePrompts,
GraphicsMode,
ExternEdit;
Integer ScreenLength;
Boolean MNP_Connect;
String<48> ChatReason;
Boolean ExternLogoff;
Boolean ANSI_Capable;
// End of Synchronet v3.19b EXITINFO.BBS generation
Byte CurrentLanguage;
Boolean RIP_Active;
Byte ExtraSpace[199];
};
#pragma pack(pop) // original packing
} // namespace QBBS
#endif // Don't add anything after this line
......@@ -20,6 +20,7 @@
****************************************************************************/
#include "sbbs.h"
#include "qbbsdefs.hpp"
/****************************************************************************/
/* This is the external programs (doors) section of the bbs */
......@@ -545,131 +546,52 @@ void sbbs_t::xtrndat(const char *name, const char *dropdir, uchar type, ulong tl
errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_TRUNC);
return;
}
char blank[256]{};
w=(WORD)dte_rate;
write(file,&w,sizeof(w)); /* BaudRate */
/* SysInfo */
getstats(&cfg,0,&stats);
write(file,&stats.logons,sizeof(stats.logons)); /* CallCount */
write(file,blank,36); /* LastCallerName */
write(file,blank,36); /* LastCallerAlias */
write(file,blank,92); /* ExtraSpace */
/* TimeLogInfo */
write(file,blank,9); /* StartDate */
write(file,blank,24*sizeof(int16_t)); /* BusyPerHour */
write(file,blank,7*sizeof(int16_t)); /* BusyPerDay */
/* UserInfo */
str2pas(name,str); /* Name */
write(file,str,36);
str2pas(useron.location,str);
write(file,str,26); /* City */
str2pas(useron.pass,str);
write(file,str,16); /* Pwd */
str2pas(useron.phone,str);
write(file,str,13); /* DataPhone */
write(file,str,13); /* HomePhone */
QBBS::exitinfo exitinfo{};
exitinfo.BaudRate = (uint16_t)dte_rate;
exitinfo.SysInfo.CallCount = stats.logons;
exitinfo.UserInfo.Name = name;
exitinfo.UserInfo.Location = useron.location;
exitinfo.UserInfo.DataPhone = useron.phone;
exitinfo.UserInfo.HomePhone = useron.phone;
localtime32(&useron.laston,&tm);
SAFEPRINTF2(tmp,"%02d:%02d",tm.tm_hour,tm.tm_min);
str2pas(tmp,str);
write(file,str,6); /* LastTime */
exitinfo.UserInfo.LastTime = tmp;
unixtodstr(&cfg,useron.laston,tmp);
str2pas(tmp,str);
write(file,str,9); /* LastDate */
c=0;
if(useron.misc&DELETED) c|=(1<<0);
if(useron.misc&CLRSCRN) c|=(1<<1);
if(useron.misc&UPAUSE) c|=(1<<2);
if(term & ANSI) c|=(1<<3);
if(useron.sex=='F') c|=(1<<7);
write(file,&c,1); /* Attrib */
write(file,&useron.flags1,4); /* Flags */
w=0;
write(file,&w,sizeof(w)); /* Credit */
write(file,&w,sizeof(w)); /* Pending */
write(file,&useron.posts,sizeof(useron.posts));/* TimesPosted */
write(file,&w,sizeof(w)); /* HighMsgRead */
w=useron.level;
write(file,&w,sizeof(w)); /* SecLvl */
w=0;
write(file,&w,sizeof(w)); /* Times */
write(file,&useron.uls,sizeof(useron.uls)); /* Ups */
write(file,&useron.dls,sizeof(useron.dls)); /* Downs */
w=(ushort)(useron.ulb/1024UL);
write(file,&w,sizeof(w)); /* UpK */
w=(ushort)(useron.dlb/1024UL);
write(file,&w,sizeof(w)); /* DownK */
w=(ushort)(logon_dlb/1024UL);
write(file,&w,sizeof(w)); /* TodayK */
w=0;
write(file,&w,sizeof(w)); /* Elapsed */
write(file,&w,sizeof(w)); /* Len */
write(file,&w,sizeof(w)); /* CombinedPtr */
write(file,&w,sizeof(w)); /* AliasPtr */
l = strtol(useron.birth, NULL, 10);
write(file,&l,sizeof(l)); /* Birthday (as a long?) */
/* EventInfo */
c=0;
write(file,&c,sizeof(char)); /* Status */
write(file,&l /* sys_eventtime */,sizeof(l)); /* RunTime */
write(file,&c,sizeof(char)); /* ErrorLevel */
c='\xff';
write(file,&c,sizeof(char)); /* Days */
// c=sys_eventnode==node_num || sys_misc&SM_TIMED_EX ? 1 : 0;
c=0;
write(file,&c,sizeof(char)); /* Forced */
if(!cfg.total_events)
l=0;
else
l=cfg.event[0]->last;
write(file,&l,sizeof(l)); /* LastTimeRun */
memset(str,0,40);
write(file,str,7); /* Spare */
c=0;
write(file,&c,1); /* NetMailEntered */
write(file,&c,1); /* EchoMailEntered */
exitinfo.UserInfo.LastDate = tmp;
if(useron.misc&DELETED) exitinfo.UserInfo.Attrib |= QBBS::USER_ATTRIB_DELETED;
if(useron.misc&CLRSCRN) exitinfo.UserInfo.Attrib |= QBBS::USER_ATTRIB_CLRSCRN;
if(useron.misc&UPAUSE) exitinfo.UserInfo.Attrib |= QBBS::USER_ATTRIB_MORE;
if(term & ANSI) exitinfo.UserInfo.Attrib |= QBBS::USER_ATTRIB_ANSI;
if(useron.sex=='F') exitinfo.UserInfo.Attrib |= QBBS::USER_ATTRIB_FEMALE;
exitinfo.UserInfo.Flags = useron.flags1;
exitinfo.UserInfo.TimesPosted = useron.posts;
exitinfo.UserInfo.SecLvl = useron.level;
exitinfo.UserInfo.Ups = useron.uls;
exitinfo.UserInfo.Downs = useron.dls;
exitinfo.UserInfo.UpK = (uint16_t)(useron.ulb/1024UL);
exitinfo.UserInfo.DownK = (uint16_t)(useron.dlb/1024UL);
exitinfo.UserInfo.TodayK = (uint16_t)(logon_dlb/1024UL);
exitinfo.UserInfo.ScreenLength = (int16_t)rows;
localtime_r(&logontime,&tm);
SAFEPRINTF2(tmp,"%02d:%02d",tm.tm_hour,tm.tm_min);
str2pas(tmp,str);
write(file,str,6); /* LoginTime */
exitinfo.LoginTime = tmp;
unixtodstr(&cfg,(time32_t)logontime,tmp);
str2pas(tmp,str);
write(file,str,9); /* LoginDate */
write(file,&cfg.level_timepercall[useron.level],sizeof(int16_t)); /* TmLimit */
write(file,&logontime,sizeof(time32_t)); /* LoginSec */
write(file,&useron.cdt,sizeof(useron.cdt)); /* Credit */
write(file,&useron.number,sizeof(useron.number)); /* UserRecNum */
i=0;
write(file,&i,2); /* ReadThru */
write(file,&i,2); /* PageTimes */
write(file,&i,2); /* DownLimit */
c=sys_status&SS_SYSPAGE ? 1:0;
write(file,&c,1); /* WantChat */
c=0;
write(file,&c,1); /* GosubLevel */
memset(str,0,255);
for(i=0;i<20;i++)
write(file,str,9); /* GosubData */
write(file,str,9); /* Menu */
c=useron.misc&CLRSCRN ? 1:0;
write(file,&c,1); /* ScreenClear */
c=useron.misc&UPAUSE ? 1:0;
write(file,&c,1); /* MorePrompts */
c=(term & NO_EXASCII) ? 0:1;
write(file,&c,1); /* GraphicsMode */
c=useron.xedit ? 1:0;
write(file,&c,1); /* ExternEdit */
i=(int16_t)rows;
write(file,&i,2); /* ScreenLength */
c=1;
write(file,&c,1); /* MNP_Connect */
write(file,str,49); /* ChatReason */
c=0;
write(file,&c,1); /* ExternLogoff */
c=(char)INT_TO_BOOL(term & ANSI);
write(file,&c,1); /* ANSI_Capable */
exitinfo.LoginDate = tmp;
exitinfo.TimeLimit = cfg.level_timepercall[useron.level];
exitinfo.Credit = useron.cdt;
exitinfo.UserRecNum = useron.number;
exitinfo.WantChat = (sys_status & SS_SYSPAGE);
exitinfo.ScreenClear = (useron.misc & CLRSCRN);
exitinfo.MorePrompts = (useron.misc & UPAUSE);
exitinfo.GraphicsMode = !(term & NO_EXASCII);
exitinfo.ExternEdit = (useron.xedit);
exitinfo.ScreenLength = (int16_t)rows;
exitinfo.MNP_Connect = true;
exitinfo.ANSI_Capable = (term & ANSI);
exitinfo.RIP_Active = (term & RIP);
write(file, &exitinfo, sizeof(exitinfo));
close(file);
}
......