home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 15
/
CD_ASCQ_15_070894.iso
/
vrac
/
wc40rec.zip
/
WC40REC.DOC
< prev
next >
Wrap
Text File
|
1994-06-01
|
13KB
|
384 lines
General Routines
----------------
With the release of 4.0 we have made changes to help support those people
who want to program in other languages like C. This means that when you
create keys for the Wildcat! 4 databases you must first pack them using the
standard WordToKey routine (or LongToKey) and then call the Filer routine
CStyleNumKey. This strips all the nulls from the key and makes it ascii
compliant. Here are the two routines used in the database modules:
function Word2Key(Num : Word) : String;
begin
Word2Key := CStyleNumKey(WordToKey(Num));
end;
function Long2Key(Num : LongInt) : String;
begin
Long2Key := CStyleNumKey(LongToKey(Num));
end;
If you need to do a KeyToWord (or KeyToLong) first call the PascalStyleNumKey
routine and then call KeyToWord.
*** READ THE FOLLOWING ***
You will want to add a two lines of code to the CStyleNumKey and the
PascalStyleNumKey to fix a problem with the Btree Filer 5.41 routines,
In the CStyleNumKeys add this line:
OrigLen := Length(S);
if (OrigLen = 0) or (OrigLen > MaxInpStrLen) then begin
CStyleNumKey := '';
Exit;
end;
S[OrigLen+1] := #0; <---- Add This Line
And in the PascalStyleNumKeys add the same line:
OrigLen := Length(S);
if OrigLen = 0 then begin
PascalStyleNumKey := '';
Exit;
end;
S[OrigLen+1] := #0; <---- Add This Line
File Database
-------------
The main file database is a Btree Filer database with four keys. There
is also a secondary index file that is not generated with Filer to
support fast searching of the file database. This secondary index will
be documented in later versions of this file. This Filer database is a
variable record sized Filer database. The section size of this
database is 291 bytes, this is the number that must be passed to
BtCreateFileBlock when creating a file database. The extended
description of a file is an array of characters layed out in the
following format: 1) There is a line length limit of 79 characters,
each line is ended with a CR character making the length of a full line
80 bytes. 2) There may be up to 15 lines in the extended description,
adding more lines will corrupt the database and possibly corrupt memory
inside of Wildcat causing a crash. There is no ^Z terminator at the
end of the description as there was in previous versions of Wildcat.
The MsgBytes field in the TFileRec should be set to the total number of
bytes in the array including the end of line characters. Here is a
list of the keys and the IsamIndDescr structure you pass to
BtCreateFileBlock when creating the database:
const
FileAreaKey = 1;
FileNameKey = 2;
FileDateKey = 3;
FileUpKey = 4;
IID is a variable of type IsamIndDescr that is passed to BtCreateFileBlock.
IID[FileAreaKey].KeyL := 15;
IID[FileAreaKey].AllowDupK := False;
IID[FileNameKey].KeyL := 15;
IID[FileNameKey].AllowDupK := False;
IID[FileDateKey].KeyL := 12;
IID[FileDateKey].AllowDupK := True;
IID[FileUpKey].KeyL := 30;
IID[FileUpKey].AllowDupK := True;
Here is a sample routine to create the keys for a file record in the
file database:
function BuildKey(const FileRec : TFileRec; Key : Integer) : IsamKeyStr;
begin
with FileRec do
case Key of
FileAreaKey : BuildKey := Word2Key(Area)+StUpcase(Pad(FileName, 12));
FileNameKey : BuildKey := StUpcase(Pad(FileName, 12))+Word2Key(Area);
FileDateKey : BuildKey := Word2Key(Area)+Word2Key(FileTime.D)+Long2Key(FileTime.T);
FileUpKey : BuildKey := Pad(StUpCase(Uploader), 25)+Long2Key(UploaderId);
end;
end;
User Database
-------------
The main user database is a Btree Filer database with six keys. The username
key is no longer unique as we are now allowing users with duplicate names
to be in the database, there are now two unique keys, the users alias and the
users ID. The user database stores the highest user number in the MasterInfo
record of NODEINFO.DAT (record 0), the database also verifies the number by
comparing the highest user ID key with the number in MasterInfo. Here is the
layout for the new user database:
UserNameKey = 1;
UserSecKey = 2;
UserExpDateKey = 3;
UserAliasKey = 4;
UserIdKey = 5;
UserRealKey = 6;
IID is a variable of type IsamIndDescr that is passed to BtCreateFileBlock.
DataLen := SizeOf(TUserRec);
Keys := 6;
IID[1].KeyL := 30; {UserName + UserID Key}
IID[1].AllowDupK := False;
IID[2].KeyL := 35; {SecLevel + UserName Key}
IID[2].AllowDupK := True;
IID[3].KeyL := 3; {Expired Date Key}
IID[3].AllowDupK := True;
IID[4].KeyL := 25; {User Alias Key}
IID[4].AllowDupK := False;
IID[5].KeyL := 5; {User ID Key}
IID[5].AllowDupK := False;
IID[6].KeyL := 25; {User Real Name}
IID[6].AllowDupK := True;
Here is a sample routine to create the keys for a user record in the
user database:
function SwitchLast(const Name : Str25) : Str25;
var
X, Y : Byte;
begin
Y := Length(Name);
X := Y;
while (Y > 0) and (Name[Y] <> ' ') do
Dec(Y);
if Y = 0 then
SwitchLast := Name
else
SwitchLast := Copy(Name, Succ(Y), X - Y) + ' ' + Copy(Name, 1, Pred(Y));
end;
function BuildUserNameKey(const Name : String; UserID : LongInt) : IsamKeyStr;
begin
BuildUserNameKey := Pad(StUpCase(SwitchLast(Name)), 25)+Long2Key(UserID);
end;
function BuildUserIDKey(IDName : LongInt) : IsamKeyStr;
begin
BuildUserIDKey := Long2Key(IDName);
end;
function TUserDatabase.BuildKey(const Data; Key : Integer) : IsamKeyStr;
var
UserRec : TUserRec absolute Data;
begin
with UserRec do
case Key of
1 : BuildKey := BuildUserNameKey(UserName, UserID);
2 : BuildKey := Pad(SecLevel, 10)+StUpCase(SwitchLast(UserName));
3 : BuildKey := Word2Key(ExpireDate);
4 : if UserRec.Alias = '' then
BuildKey := ''
else
BuildKey := StUpCase(Alias);
5 : BuildKey := BuildUserIDKey(UserId);
6 : BuildKey := StUpCase(UserName);
end;
end;
function TUserDatabase.AddRecord(var RefNr : LongInt; var Data) : Boolean;
var
UserRec : TUserRec absolute Data;
ConfPage : TUserConfPage;
RefKey : IsamKeyStr;
UserRef : LongInt;
begin
AddRecord := False;
Lock;
if MwConfig.DupUserLevel <> duAllow then
if FindKey(UserRealKey, RefNr, BuildKey(UserRec, UserRealKey)) then
begin
Unlock;
Exit;
end;
Unlock;
ReadMInfo(True);
ClearKey(UserIDKey);
PrevKey(UserIDKey, UserRef, RefKey);
if IsamOk then
UserRef := Key2Long(RefKey)
else
UserRef := 0;
if UserRef > MInfo.HighestUserId then
MInfo.HighestUserId := UserRef + 1
else
Inc(MInfo.HighestUserId);
WriteMInfo;
Lock;
(*
we now have to recheck the duplicate situation, in weird cases we make
increment the highest user id without adding a new user but this is
required to prevent deadlock situations
*)
if MwConfig.DupUserLevel <> duAllow then
if FindKey(UserRealKey, RefNr, BuildKey(UserRec, UserRealKey)) then
begin
Unlock;
Exit;
end;
UserRec.UserId := MInfo.HighestUserId;
UserRec.UserConfData := 0;
if inherited AddRecord(RefNr, Data) then
begin
AddRecord := True;
UserConfDb.GetPage(UserRec, 0, ConfPage);
end;
Unlock;
end;
Security Profiles
-----------------
Wildcat 4.0 adds support for up to 32,760 conferences and 32,760 file
areas, as a result of this certain fields in the security profiles are
now variable sized. Also when a Wildcat is configured for a large
number of conferences or file areas the data structures for these
variable sized pieces of the security profile can get so large that it
is not possible to keep them in memory all at once. If your program
must conserve memory we recommend using a paging scheme to only keep
part of the variable sized data in memory at once. Wildcat uses a
scheme like this in which Wildcat only uses 2K to access 24K of data
that will exist in the worst case system. There are also two types of
security profiles, Primary and Secondary. Primary profiles are the
ones you edit and use to set a users options, the secondary is used for
setting a users access to certain areas, specifically those with bit
access. What Wildcat does is load the users primary profile and then
load each secondary and logically OR the bits for doors, nodes,
protocols and menu items, then it pages the conf/file bits and OR's
those with the primary file and when it is finished it writes the new
profile to the users wcwork/node directory where Wildcat uses it to
determine file and conference access. Use the TSec header to determine
what type of profile you are looking at.
Here is the layout of the security records in the SECLEVEL.DAT:
/* First record */
TSecRec record from WCTYPE.PAS
((Number of conferences * 3) - 1) div 8 + 1 of bytes of conference security info
((Number of file areas * 3) - 1) div 8 + 1 of bytes of conference security info
/* Second record */
TSecRec record from WCTYPE.PAS
((Number of conferences * 3) - 1) div 8 + 1 of bytes of file area security info
((Number of file areas * 3) - 1) div 8 + 1 of bytes of file area security info
And so on....
To compute the exact size of a record in the system you would do something
like this:
function SecRecSize : LongInt;
var
FileBitSize,
ConfBitSize : LongInt;
begin
ConfBitSize := ((LongInt(Number of conferences) * 3) - 1) div 8 + 1;
FileBitSize := ((LongInt(Number of file areas) * 3) - 1) div 8 + 1;
SecRecSize := LongInt(SizeOf(TSecRec)) + ConfBitSize + FileBitSize;
end;
What do the security bits mean?
-------------------------------
sConfRead = $01; {The first bit gives the user access to read messages in the conference}
sConfWrite = $02; {The second bit gives the user access to write messages in the conference}
sConfJoin = $04; {The third bit gives the user access to join the conference}
function GetConfAccess(Conf : Word) : Byte;
begin
I := Conf * 3;
GetConfAccess := (Word((address of conf data[I div 8])^) shr (I mod 8)) and $07;
end;
The above function will return the bits for the specified conference if you
point the function at where you load the conference data into memory. You
can then test for various options using the and operator like this:
if (GetConfAccess(9) and sConfRead = sConfRead) then begin
{user has conference read access in conference 9}
end;
sFileList = $01; {The first bit gives the user access list files in the area}
sFileDown = $02; {The second bit gives the user access to download files in the area}
sFileUp = $04; {The third bit gives the user access to upload files in the area}
function GetFileAccess(Area : Word) : Byte;
begin
I := (Area - 1) * 3;
{!! It is important to notice that we decrement the file area, this !!}
{!! is because file areas are numbered starting at 1, we decrement !!}
{!! the area so we don't skip the first three bits in the data !!}
{!! structure. !!}
GetAreaAccess := (Word((address of file data[I div 8])^) shr (I mod 8)) and $07;
end;
The above function will return the bits for the specified file area if you
point the function at where you load the file data into memory. You
can then test for various options using the and operator like this:
if (GetFileAccess(7) and sFileList = sFileList) then begin
{user has file list access in file area 7}
end;
Conference Definition Records
-----------------------------
The conference records in Wildcat 4.0 are also variable sized for the same
reasons metioned in the section on Security Profiles. The layout of the
conference records is as follows:
{first record}
TConfDesc record from WCTYPE.PAS
(Number of file areas - 1) div 8 + 1 of bytes of file area info
{second record}
TConfDesc record from WCTYPE.PAS
(Number of file areas - 1) div 8 + 1 of bytes of file area info
{... and so on}
To compute the actual size of each Conference record in the CONFDESC.DAT file
you can use the following function:
function ConfRecSize : Word;
var
FileRecSize : Word;
begin
FileRecSize := (Number of file areas - 1) div 8 + 1;
ConfRecSize := SizeOf(TConfDesc) + FileRecSize;
end;
What do the file area bits mean?
--------------------------------
Each bit in the file area data at the end of each TConfDesc is used to
determine whether that conference will allow the user to access the
particular file area. For example if the 10th bit is set the the conference
makes file area 10 available to the caller if their security access
permits it.
function GetConfFileAccess(Area : Word) : Boolean;
begin
I := Conf * 3;
GetConfFileAccess := (Word((address of file data[I div 8])^) shr (I mod 8)) and $01 = $01;
end;