home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 15 / CD_ASCQ_15_070894.iso / vrac / wc40rec.zip / WC40REC.DOC < prev    next >
Text File  |  1994-06-01  |  13KB  |  384 lines

  1. General Routines
  2. ----------------
  3. With the release of 4.0 we have made changes to help support those people
  4. who want to program in other languages like C.  This means that when you
  5. create keys for the Wildcat! 4 databases you must first pack them using the
  6. standard WordToKey routine (or LongToKey) and then call the Filer routine
  7. CStyleNumKey.  This strips all the nulls from the key and makes it ascii
  8. compliant. Here are the two routines used in the database modules:
  9.  
  10.  
  11. function Word2Key(Num : Word) : String;
  12. begin
  13.   Word2Key := CStyleNumKey(WordToKey(Num));
  14. end;
  15.  
  16. function Long2Key(Num : LongInt) : String;
  17. begin
  18.   Long2Key := CStyleNumKey(LongToKey(Num));
  19. end;
  20.  
  21.  
  22. If you need to do a KeyToWord (or KeyToLong) first call the PascalStyleNumKey
  23. routine and then call KeyToWord.
  24.  
  25. *** READ THE FOLLOWING ***
  26.  
  27. You will want to add a two lines of code to the CStyleNumKey and the
  28. PascalStyleNumKey to fix a problem with the Btree Filer 5.41 routines,
  29. In the CStyleNumKeys add this line:
  30.  
  31.  
  32. OrigLen := Length(S);
  33. if (OrigLen = 0) or (OrigLen > MaxInpStrLen) then begin
  34.   CStyleNumKey := '';
  35.   Exit;
  36. end;
  37. S[OrigLen+1] := #0;  <---- Add This Line
  38.  
  39.  
  40. And in the PascalStyleNumKeys add the same line:
  41.  
  42.  
  43. OrigLen := Length(S);
  44. if OrigLen = 0 then begin
  45.   PascalStyleNumKey := '';
  46.   Exit;
  47. end;
  48. S[OrigLen+1] := #0;  <---- Add This Line
  49.  
  50.  
  51.  
  52. File Database
  53. -------------
  54.  
  55. The main file database is a Btree Filer database with four keys.  There
  56. is also a secondary index file that is not generated with Filer to
  57. support fast searching of the file database.  This secondary index will
  58. be documented in later versions of this file.  This Filer database is a
  59. variable record sized Filer database.  The section size of this
  60. database is 291 bytes, this is the number that must be passed to
  61. BtCreateFileBlock when creating a file database.  The extended
  62. description of a file is an array of characters layed out in the
  63. following format:  1) There is a line length limit of 79 characters,
  64. each line is ended with a CR character making the length of a full line
  65. 80 bytes. 2) There may be up to 15 lines in the extended description,
  66. adding more lines will corrupt the database and possibly corrupt memory
  67. inside of Wildcat causing a crash.  There is no ^Z terminator at the
  68. end of the description as there was in previous versions of Wildcat.
  69. The MsgBytes field in the TFileRec should be set to the total number of
  70. bytes in the array including the end of line characters.  Here is a
  71. list of the keys and the IsamIndDescr structure you pass to
  72. BtCreateFileBlock when creating the database:
  73.  
  74. const
  75.   FileAreaKey = 1;
  76.   FileNameKey = 2;
  77.   FileDateKey = 3;
  78.   FileUpKey   = 4;
  79.  
  80. IID is a variable of type IsamIndDescr that is passed to BtCreateFileBlock.
  81.  
  82. IID[FileAreaKey].KeyL := 15;
  83. IID[FileAreaKey].AllowDupK := False;
  84. IID[FileNameKey].KeyL := 15;
  85. IID[FileNameKey].AllowDupK := False;
  86. IID[FileDateKey].KeyL := 12;
  87. IID[FileDateKey].AllowDupK := True;
  88. IID[FileUpKey].KeyL := 30;
  89. IID[FileUpKey].AllowDupK := True;
  90.  
  91. Here is a sample routine to create the keys for a file record in the
  92. file database:
  93.  
  94. function BuildKey(const FileRec : TFileRec; Key : Integer) : IsamKeyStr;
  95. begin
  96.   with FileRec do
  97.     case Key of
  98.       FileAreaKey : BuildKey := Word2Key(Area)+StUpcase(Pad(FileName, 12));
  99.       FileNameKey : BuildKey := StUpcase(Pad(FileName, 12))+Word2Key(Area);
  100.       FileDateKey : BuildKey := Word2Key(Area)+Word2Key(FileTime.D)+Long2Key(FileTime.T);
  101.       FileUpKey   : BuildKey := Pad(StUpCase(Uploader), 25)+Long2Key(UploaderId);
  102.     end;
  103. end;
  104.  
  105.  
  106. User Database
  107. -------------
  108.  
  109. The main user database is a Btree Filer database with six keys. The username
  110. key is no longer unique as we are now allowing users with duplicate names
  111. to be in the database, there are now two unique keys, the users alias and the
  112. users ID. The user database stores the highest user number in the MasterInfo
  113. record of NODEINFO.DAT (record 0), the database also verifies the number by
  114. comparing the highest user ID key with the number in MasterInfo. Here is the
  115. layout for the new user database:
  116.  
  117. UserNameKey    = 1;
  118. UserSecKey     = 2;
  119. UserExpDateKey = 3;
  120. UserAliasKey   = 4;
  121. UserIdKey      = 5;
  122. UserRealKey    = 6;
  123.  
  124. IID is a variable of type IsamIndDescr that is passed to BtCreateFileBlock.
  125.  
  126. DataLen := SizeOf(TUserRec);
  127. Keys := 6;
  128. IID[1].KeyL := 30;         {UserName + UserID Key}
  129. IID[1].AllowDupK := False;
  130. IID[2].KeyL := 35;         {SecLevel + UserName Key}
  131. IID[2].AllowDupK := True;
  132. IID[3].KeyL := 3;          {Expired Date Key}
  133. IID[3].AllowDupK := True;
  134. IID[4].KeyL := 25;         {User Alias Key}
  135. IID[4].AllowDupK := False;
  136. IID[5].KeyL := 5;          {User ID Key}
  137. IID[5].AllowDupK := False;
  138. IID[6].KeyL := 25;         {User Real Name}
  139. IID[6].AllowDupK := True;
  140.  
  141.  
  142. Here is a sample routine to create the keys for a user record in the
  143. user database:
  144.  
  145. function SwitchLast(const Name : Str25) : Str25;
  146. var
  147.   X, Y : Byte;
  148.  
  149. begin
  150.   Y := Length(Name);
  151.   X := Y;
  152.   while (Y > 0) and (Name[Y] <> ' ') do
  153.     Dec(Y);
  154.   if Y = 0 then
  155.     SwitchLast := Name
  156.   else
  157.     SwitchLast := Copy(Name, Succ(Y), X - Y) + ' ' + Copy(Name, 1, Pred(Y));
  158. end;
  159.  
  160. function BuildUserNameKey(const Name : String; UserID : LongInt) : IsamKeyStr;
  161. begin
  162.   BuildUserNameKey := Pad(StUpCase(SwitchLast(Name)), 25)+Long2Key(UserID);
  163. end;
  164.  
  165.  
  166. function BuildUserIDKey(IDName : LongInt) : IsamKeyStr;
  167. begin
  168.   BuildUserIDKey := Long2Key(IDName);
  169. end;
  170.  
  171.  
  172. function TUserDatabase.BuildKey(const Data; Key : Integer) : IsamKeyStr;
  173. var
  174.   UserRec : TUserRec absolute Data;
  175.  
  176. begin
  177.   with UserRec do
  178.     case Key of
  179.       1 : BuildKey := BuildUserNameKey(UserName, UserID);
  180.       2 : BuildKey := Pad(SecLevel, 10)+StUpCase(SwitchLast(UserName));
  181.       3 : BuildKey := Word2Key(ExpireDate);
  182.       4 : if UserRec.Alias = '' then
  183.             BuildKey := ''
  184.           else
  185.             BuildKey := StUpCase(Alias);
  186.       5 : BuildKey  := BuildUserIDKey(UserId);
  187.       6 : BuildKey  := StUpCase(UserName);
  188.     end;
  189. end;
  190.  
  191.  
  192. function TUserDatabase.AddRecord(var RefNr : LongInt; var Data) : Boolean;
  193. var
  194.   UserRec  : TUserRec absolute Data;
  195.   ConfPage : TUserConfPage;
  196.   RefKey   : IsamKeyStr;
  197.   UserRef  : LongInt;
  198.  
  199. begin
  200.   AddRecord := False;
  201.   Lock;
  202.   if MwConfig.DupUserLevel <> duAllow then
  203.     if FindKey(UserRealKey, RefNr, BuildKey(UserRec, UserRealKey)) then
  204.       begin
  205.         Unlock;
  206.         Exit;
  207.       end;
  208.   Unlock;
  209.   ReadMInfo(True);
  210.   ClearKey(UserIDKey);
  211.   PrevKey(UserIDKey, UserRef, RefKey);
  212.   if IsamOk then
  213.     UserRef := Key2Long(RefKey)
  214.   else
  215.     UserRef := 0;
  216.   if UserRef > MInfo.HighestUserId then
  217.     MInfo.HighestUserId := UserRef + 1
  218.   else
  219.     Inc(MInfo.HighestUserId);
  220.   WriteMInfo;
  221.   Lock;
  222.     (*
  223.       we now have to recheck the duplicate situation, in weird cases we make
  224.       increment the highest user id without adding a new user but this is
  225.       required to prevent deadlock situations
  226.     *)
  227.   if MwConfig.DupUserLevel <> duAllow then
  228.     if FindKey(UserRealKey, RefNr, BuildKey(UserRec, UserRealKey)) then
  229.       begin
  230.         Unlock;
  231.         Exit;
  232.       end;
  233.   UserRec.UserId := MInfo.HighestUserId;
  234.   UserRec.UserConfData := 0;
  235.   if inherited AddRecord(RefNr, Data) then
  236.     begin
  237.       AddRecord := True;
  238.       UserConfDb.GetPage(UserRec, 0, ConfPage);
  239.     end;
  240.   Unlock;
  241. end;
  242.  
  243.  
  244. Security Profiles
  245. -----------------
  246.  
  247. Wildcat 4.0 adds support for up to 32,760 conferences and 32,760 file
  248. areas, as a result of this certain fields in the security profiles are
  249. now variable sized.  Also when a Wildcat is configured for a large
  250. number of conferences or file areas the data structures for these
  251. variable sized pieces of the security profile can get so large that it
  252. is not possible to keep them in memory all at once.  If your program
  253. must conserve memory we recommend using a paging scheme to only keep
  254. part of the variable sized data in memory at once.  Wildcat uses a
  255. scheme like this in which Wildcat only uses 2K to access 24K of data
  256. that will exist in the worst case system.  There are also two types of
  257. security profiles, Primary and Secondary.  Primary profiles are the
  258. ones you edit and use to set a users options, the secondary is used for
  259. setting a users access to certain areas, specifically those with bit
  260. access.  What Wildcat does is load the users primary profile and then
  261. load each secondary and logically OR the bits for doors, nodes,
  262. protocols and menu items, then it pages the conf/file bits and OR's
  263. those with the primary file and when it is finished it writes the new
  264. profile to the users wcwork/node directory where Wildcat uses it to
  265. determine file and conference access.  Use the TSec header to determine
  266. what type of profile you are looking at.
  267.  
  268. Here is the layout of the security records in the SECLEVEL.DAT:
  269.  
  270. /* First record */
  271. TSecRec record from WCTYPE.PAS
  272. ((Number of conferences * 3) - 1) div 8 + 1 of bytes of conference security info
  273. ((Number of file areas * 3) - 1) div 8 + 1 of bytes of conference security info
  274.  
  275. /* Second record */
  276. TSecRec record from WCTYPE.PAS
  277. ((Number of conferences * 3) - 1) div 8 + 1 of bytes of file area security info
  278. ((Number of file areas * 3) - 1) div 8 + 1 of bytes of file area security info
  279.  
  280. And so on....
  281.  
  282. To compute the exact size of a record in the system you would do something
  283. like this:
  284.  
  285. function SecRecSize : LongInt;
  286. var
  287.   FileBitSize,
  288.   ConfBitSize : LongInt;
  289.  
  290. begin
  291.   ConfBitSize := ((LongInt(Number of conferences) * 3) - 1) div 8 + 1;
  292.   FileBitSize := ((LongInt(Number of file areas) * 3) - 1) div 8 + 1;
  293.   SecRecSize := LongInt(SizeOf(TSecRec)) + ConfBitSize + FileBitSize;
  294. end;
  295.  
  296. What do the security bits mean?
  297. -------------------------------
  298.  
  299. sConfRead  = $01; {The first bit gives the user access to read messages in the conference}
  300. sConfWrite = $02; {The second bit gives the user access to write messages in the conference}
  301. sConfJoin  = $04; {The third bit gives the user access to join the conference}
  302.  
  303. function GetConfAccess(Conf : Word) : Byte;
  304. begin
  305.   I := Conf * 3;
  306.   GetConfAccess := (Word((address of conf data[I div 8])^) shr (I mod 8)) and $07;
  307. end;
  308.  
  309. The above function will return the bits for the specified conference if you
  310. point the function at where you load the conference data into memory. You
  311. can then test for various options using the and operator like this:
  312.  
  313. if (GetConfAccess(9) and sConfRead = sConfRead) then begin
  314.   {user has conference read access in conference 9}
  315. end;
  316.  
  317. sFileList  = $01; {The first bit gives the user access list files in the area}
  318. sFileDown  = $02; {The second bit gives the user access to download files in the area}
  319. sFileUp    = $04; {The third bit gives the user access to upload files in the area}
  320.  
  321. function GetFileAccess(Area : Word) : Byte;
  322. begin
  323.   I := (Area - 1) * 3;
  324.   {!! It is important to notice that we decrement the file area, this !!}
  325.   {!! is because file areas are numbered starting at 1, we decrement  !!}
  326.   {!! the area so we don't skip the first three bits in the data      !!}
  327.   {!! structure.                                                      !!}
  328.   GetAreaAccess := (Word((address of file data[I div 8])^) shr (I mod 8)) and $07;
  329. end;
  330.  
  331. The above function will return the bits for the specified file area if you
  332. point the function at where you load the file data into memory. You
  333. can then test for various options using the and operator like this:
  334.  
  335. if (GetFileAccess(7) and sFileList = sFileList) then begin
  336.   {user has file list access in file area 7}
  337. end;
  338.  
  339. Conference Definition Records
  340. -----------------------------
  341.  
  342. The conference records in Wildcat 4.0 are also variable sized for the same
  343. reasons metioned in the section on Security Profiles. The layout of the
  344. conference records is as follows:
  345.  
  346. {first record}
  347. TConfDesc record from WCTYPE.PAS
  348. (Number of file areas - 1) div 8 + 1 of bytes of file area info
  349.  
  350. {second record}
  351. TConfDesc record from WCTYPE.PAS
  352. (Number of file areas - 1) div 8 + 1 of bytes of file area info
  353.  
  354. {... and so on}
  355.  
  356. To compute the actual size of each Conference record in the CONFDESC.DAT file
  357. you can use the following function:
  358.  
  359. function ConfRecSize : Word;
  360. var
  361.   FileRecSize : Word;
  362.  
  363. begin
  364.   FileRecSize := (Number of file areas - 1) div 8 + 1;
  365.   ConfRecSize := SizeOf(TConfDesc) + FileRecSize;
  366. end;
  367.  
  368.  
  369. What do the file area bits mean?
  370. --------------------------------
  371.  
  372. Each bit in the file area data at the end of each TConfDesc is used to
  373. determine whether that conference will allow the user to access the
  374. particular file area. For example if the 10th bit is set the the conference
  375. makes file area 10 available to the caller if their security access
  376. permits it.
  377.  
  378. function GetConfFileAccess(Area : Word) : Boolean;
  379. begin
  380.   I := Conf * 3;
  381.   GetConfFileAccess := (Word((address of file data[I div 8])^) shr (I mod 8)) and $01 = $01;
  382. end;
  383.  
  384.