Subversion Repositories oidplus

Rev

Rev 734 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. program OIDPLUS;
  2.  
  3. (************************************************)
  4. (* OIDPLUS.PAS                                  *)
  5. (* Author:   Daniel Marschall                   *)
  6. (* Revision: 2022-02-13                         *)
  7. (* License:  Apache 2.0                         *)
  8. (* This file contains:                          *)
  9. (* - "OIDplus for DOS" program                  *)
  10. (************************************************)
  11.  
  12. uses
  13.   Dos, Crt, StrList, VtsFuncs, VtsCui, OidFile, OidUtils;
  14.  
  15. const
  16.   VERSIONINFO = 'Revision: 2022-02-13';
  17.   DEFAULT_STATUSBAR = '(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.';
  18.   DISKIO_SOUND_DEBUGGING = false;
  19.   DISKIO_SOUND_DELAY = 500;
  20.   ASNEDIT_LINES = 10;
  21.   DESCEDIT_LINES = 10;
  22.   DESCEDIT_PADDING = 3;
  23.  
  24. procedure _WriteOidFile(filename: string; oid: POid);
  25. begin
  26.   DrawStatusBar('Write file ' + filename + '...');
  27.   WriteOidFile(filename, oid);
  28.  
  29.   if DISKIO_SOUND_DEBUGGING then
  30.   begin
  31.     Sound(70);
  32.     Delay(DISKIO_SOUND_DELAY - 10);
  33.     NoSound;
  34.     Delay(10);
  35.   end;
  36.  
  37.   DrawStatusBar(DEFAULT_STATUSBAR);
  38. end;
  39.  
  40. procedure _ReadOidFile(filename: string; oid: POid);
  41. begin
  42.   DrawStatusBar('Read file ' + filename + '...');
  43.   ReadOidFile(filename, oid);
  44.  
  45.   if DISKIO_SOUND_DEBUGGING then
  46.   begin
  47.     Sound(50);
  48.     Delay(DISKIO_SOUND_DELAY - 10);
  49.     NoSound;
  50.     Delay(10);
  51.   end;
  52.  
  53.   DrawStatusBar(DEFAULT_STATUSBAR);
  54. end;
  55.  
  56. procedure _Pause;
  57. var
  58.   bakX, bakY: integer;
  59. begin
  60.   bakX := WhereX;
  61.   bakY := WhereY;
  62.   DrawStatusBar('Press any key to continue');
  63.   GoToXY(bakX, bakY);
  64.   ReadKey;
  65.   DrawStatusBar(DEFAULT_STATUSBAR);
  66. end;
  67.  
  68. function _ShowASNIds(subfile: string): string;
  69. var
  70.   coid: TOID;
  71.   j, jmax: integer;
  72.   sTmp: string;
  73. begin
  74.   sTmp := '';
  75.   InitOidDef(@coid);
  76.   _ReadOidFile(subfile, @coid);
  77.   jmax := ListCount(coid.ASNIds)-1;
  78.   for j := 0 to jmax do
  79.   begin
  80.     if j = 0 then sTmp := sTmp + ' (';
  81.     sTmp := sTmp + ListGetElement(coid.ASNIds, j);
  82.     if j = jmax then
  83.       sTmp := sTmp + ')'
  84.     else
  85.       sTmp := sTmp + ', ';
  86.   end;
  87.   FreeOidDef(@coid);
  88.   _ShowASNIds := sTmp;
  89. end;
  90.  
  91. function AsnAlreadyExisting(oid: POID; asnid: string): boolean;
  92. var
  93.   sTmp: string;
  94.   i: integer;
  95. begin
  96.   for i := 0 to ListCount(oid^.AsnIds)-1 do
  97.   begin
  98.     sTmp := ListGetElement(oid^.AsnIds, i);
  99.     if sTmp = asnid then
  100.     begin
  101.       AsnAlreadyExisting := true;
  102.       exit;
  103.     end;
  104.   end;
  105.   AsnAlreadyExisting := false;
  106. end;
  107.  
  108. function AsnEditor(oid: POID): boolean;
  109. var
  110.   asnList: PStringList;
  111.   i: integer;
  112.   x, y, w, h: integer;
  113.   res: integer;
  114.   sInput: string;
  115. begin
  116.   AsnEditor := false;
  117.  
  118.   repeat
  119.     InitList(asnList);
  120.  
  121.     for i := 0 to ListCount(oid^.ASNIds)-1 do
  122.     begin
  123.       ListAppend(asnList, ListGetElement(oid^.ASNIDs, i));
  124.     end;
  125.     ListAppend(asnList, '<NEW>');
  126.     ListAppend(asnList, '<SAVE>');
  127.     ListAppend(asnList, '<CANCEL>');
  128.  
  129.     DrawStatusBar(DEFAULT_STATUSBAR);
  130.     x := SINGLE_LINE_BOX_PADDING;
  131.     y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
  132.     w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
  133.     h := ASNEDIT_LINES;
  134.     res := DrawSelectionList(x, y, w, h,
  135.                              asnList, true,
  136.                              'EDIT ASN.1 IDENTIFIERS',
  137.                              2);
  138.  
  139.     (* Change double-border to thin-border *)
  140.     DrawThinBorder(x-1, y-1, w+2, h+2);
  141.     GoToXY(x+1, y-1);
  142.     Write('EDIT ASN.1 IDENTIFIERS');
  143.  
  144.     if res = -1 then
  145.     begin
  146.       exit;
  147.     end
  148.     else if res = ListCount(oid^.ASNIDs) then
  149.     begin
  150.       (* "NEW" item was selected *)
  151.       sInput := '';
  152.       repeat
  153.         if QueryVal(sInput,
  154.                     SINGLE_LINE_BOX_PADDING_INNER,
  155.                     ScreenHeight div 2,
  156.                     ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
  157.                     1,
  158.                     'ADD SINGLE ASN.1 ID',
  159.                     2) then
  160.         begin
  161.           if sInput = '' then continue;
  162.           if not ASN1IDValid(sInput) then
  163.           begin
  164.             ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
  165.             _Pause;
  166.           end
  167.           else if AsnAlreadyExisting(oid, sInput) then
  168.           begin
  169.             ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
  170.             _Pause;
  171.           end
  172.           else
  173.           begin
  174.             ListAppend(oid^.ASNIDs, sInput);
  175.             break;
  176.           end;
  177.         end
  178.         else break;
  179.       until false;
  180.     end
  181.     else if res = ListCount(oid^.ASNIDs)+1 then
  182.     begin
  183.       (* "SAVE" item was selected *)
  184.       AsnEditor := true;
  185.       Exit;
  186.     end
  187.     else if res = ListCount(oid^.ASNIDs)+2 then
  188.     begin
  189.       (* "CANCEL" item was selected *)
  190.       AsnEditor := false;
  191.       Exit;
  192.     end
  193.     else
  194.     begin
  195.       DrawStatusBar('Note: Remove the text to delete the ASN.1 identifier');
  196.       sInput := ListGetElement(oid^.ASNIDs, res);
  197.       repeat
  198.         if QueryVal(sInput,
  199.                     SINGLE_LINE_BOX_PADDING_INNER,
  200.                     ScreenHeight div 2,
  201.                     ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
  202.                     1,
  203.                     'EDIT SINGLE ASN.1 ID',
  204.                     2) then
  205.         begin
  206.           if sInput = '' then
  207.           begin
  208.             (* Empty input = Delete ASN.1 ID *)
  209.             ListDeleteElement(oid^.ASNIDs, res);
  210.             break;
  211.           end
  212.           else if not ASN1IDValid(sInput) then
  213.           begin
  214.             ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
  215.             _Pause;
  216.           end
  217.           else if AsnAlreadyExisting(oid, sInput) and
  218.               not (ListGetElement(oid^.ASNIDs, res) = sInput) then
  219.           begin
  220.             ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
  221.             _Pause;
  222.           end
  223.           else
  224.           begin
  225.             ListSetElement(oid^.ASNIDs, res, sInput);
  226.             break;
  227.           end;
  228.         end
  229.         else break;
  230.       until false;
  231.     end;
  232.   until false;
  233. end;
  234.  
  235. function DescEditor(oid: POID): boolean;
  236. var
  237.   sInput: string;
  238. begin
  239.   DescEditor := false;
  240.  
  241.   DrawStatusBar('Note: Press Ctrl+Return for a line-break.');
  242.   sInput := oid^.description;
  243.   if QueryVal(sInput,
  244.               DESCEDIT_PADDING,
  245.               ScreenHeight div 2 - DESCEDIT_LINES div 2,
  246.               ScreenWidth - (DESCEDIT_PADDING-1)*2,
  247.               DESCEDIT_LINES,
  248.               'EDIT DESCRIPTION',
  249.               2) then
  250.   begin
  251.     oid^.description := sInput;
  252.     DescEditor := true; (* enable write file *)
  253.   end;
  254. end;
  255.  
  256. function NextPossibleFileID: string;
  257. var
  258.   DirInfo: SearchRec;
  259.   list: PStringList;
  260.   iId: LongInt;
  261.   sId: string;
  262. begin
  263.   (* Put all found files into a list *)
  264.   InitList(list);
  265.   FindFirst('????????.OID', Archive, DirInfo);
  266.   while DosError = 0 do
  267.   begin
  268.     sId := Copy(DirInfo.Name, 1, 8);
  269.     ListAppend(list, sId);
  270.     FindNext(DirInfo);
  271.   end;
  272.  
  273.   (* Search for the first non existing item in the list *)
  274.   sId := '';
  275.   for iId := 0 to 99999999 do
  276.   begin
  277.     sId := ZeroPad(iId, 8);
  278.     if not ListContains(list, sId) then break;
  279.   end;
  280.   NextPossibleFileId := sId;
  281.   FreeList(list);
  282. end;
  283.  
  284. function NumIdAlreadyExisting(parentOID: POID; sInput: string): boolean;
  285. var
  286.   searchDotNotation: string;
  287.   sTmp: string;
  288.   i: integer;
  289. begin
  290.   if parentOID^.DotNotation = '' then
  291.     searchDotNotation := sInput
  292.   else
  293.     searchDotNotation := parentOID^.DotNotation + '.' + sInput;
  294.   for i := 0 to ListCount(parentOID^.SubIds)-1 do
  295.   begin
  296.     sTmp := ListGetElement(parentOID^.SubIds, i);
  297.     Delete(sTmp, 1, 8);
  298.     if sTmp = searchDotNotation then
  299.     begin
  300.       NumIdAlreadyExisting := true;
  301.       exit;
  302.     end;
  303.   end;
  304.   NumIdAlreadyExisting := false;
  305. end;
  306.  
  307. function NumIdEditor(oid: POID; parentOID: POID): boolean;
  308. var
  309.   sInput: string;
  310. begin
  311.   NumIdEditor := false;
  312.   sInput := '';
  313.  
  314.   repeat
  315.     if QueryVal(sInput,
  316.                 SINGLE_LINE_BOX_PADDING_INNER,
  317.                 ScreenHeight div 2,
  318.                 ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
  319.                 1,
  320.                 'ENTER NUMERIC ID',
  321.                 2) then
  322.     begin
  323.       if sInput = '' then continue;
  324.       if not IsNumeric(sInput) then
  325.       begin
  326.         ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
  327.         _Pause;
  328.       end
  329.       else if (parentOID^.DotNotation='') and (StrToInt(sInput) > 2) then
  330.       begin
  331.         ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
  332.         _Pause;
  333.       end
  334.       else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and (StrToInt(sInput) > 39) then
  335.       begin
  336.         ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
  337.         _Pause;
  338.       end
  339.       else if NumIdAlreadyExisting(parentOID, sInput) then
  340.       begin
  341.         ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
  342.         _Pause;
  343.       end
  344.       else
  345.       begin
  346.         if parentOID^.DotNotation = '' then
  347.           oid^.DotNotation := sInput
  348.         else
  349.           oid^.DotNotation := parentOID^.DotNotation + '.' + sInput;
  350.         NumIdEditor := true;
  351.         Exit;
  352.       end;
  353.     end
  354.     else
  355.     begin
  356.       Exit;
  357.     end;
  358.   until false;
  359. end;
  360.  
  361. function NewOidEditor(oid: POID): boolean;
  362. var
  363.   newfilename: string;
  364.   newoid: TOID;
  365. begin
  366.   NewOidEditor := false;
  367.  
  368.   InitOidDef(@newoid);
  369.   newoid.FileId := NextPossibleFileID;
  370.   newoid.Parent := oid^.FileId + oid^.DotNotation;
  371.   if not NumIdEditor(@newoid, oid) then exit;
  372.   if not AsnEditor(@newoid) then exit;
  373.   if not DescEditor(@newoid) then exit;
  374.  
  375.   newfilename := newoid.FileId + '.OID';
  376.   _WriteOidFile(newfilename, @newoid);
  377.  
  378.   (* Add link to original file and enable the saving of it *)
  379.   ListAppend(oid^.SubIds, newoid.FileId + newoid.DotNotation);
  380.   NewOidEditor := true;
  381. end;
  382.  
  383. procedure DeleteChildrenRecursive(oid: POID);
  384. var
  385.   i: integer;
  386.   childOID: TOID;
  387.   filenameChild: string;
  388. begin
  389.   for i := 0 to ListCount(oid^.SubIds)-1 do
  390.   begin
  391.     filenameChild := Copy(ListGetElement(oid^.SubIds, i), 1, 8) + '.OID';
  392.     InitOidDef(@childOID);
  393.     _ReadOidFile(filenameChild, @childOID);
  394.     DeleteChildrenRecursive(@childOID);
  395.     FreeOidDef(@childOID);
  396.     DeleteFile(filenameChild);
  397.   end;
  398.   ListClear(oid^.SubIds);
  399. end;
  400.  
  401. procedure DeleteOidRecursive(selfOID: POID);
  402. var
  403.   i: integer;
  404.   parentOID: TOID;
  405.   filenameSelf, filenameParent: string;
  406.   fileIdToDelete: string;
  407. begin
  408.   (* Remove all children and their files recursively *)
  409.   DeleteChildrenRecursive(selfOID);
  410.  
  411.   (* Remove forward reference in parent OID *)
  412.   filenameParent := Copy(selfOID^.Parent, 1, 8)+'.OID';
  413.   InitOidDef(@parentOID);
  414.   _ReadOidFile(filenameParent, @parentOID);
  415.   for i := 0 to ListCount(parentOID.SubIds)-1 do
  416.   begin
  417.     if Copy(ListGetElement(parentOID.SubIds, i), 1, 8) = selfOID^.FileId then
  418.     begin
  419.       ListDeleteElement(parentOID.SubIds, i);
  420.       _WriteOidFile(filenameParent, @parentOID);
  421.       break;
  422.     end;
  423.   end;
  424.   FreeOidDef(@parentOID);
  425.  
  426.   (* Delete own file *)
  427.   fileIdToDelete := selfOID^.FileId;
  428.   filenameSelf := fileIdToDelete+'.OID';
  429.   DeleteFile(filenameSelf);
  430. end;
  431.  
  432. procedure DisplayOIDFile(filename: string);
  433. const
  434.   ID_EXIT     = '?EXIT';
  435.   ID_ASNEDIT  = '?ASN1';
  436.   ID_DESCEDIT = '?DESC';
  437.   ID_ADDCHILD = '?ADDC';
  438.   ID_DELETE   = '?DELE';
  439.   NAVBAR_SIZE = 5;
  440. var
  441.   isRoot: boolean;
  442.   f: Text;
  443.   line, cmd: string;
  444.   oid: TOID;
  445.   i, menuX, menuY: integer;
  446.   linesLeft, linesRequired: integer;
  447.   sTmp, subfile: string;
  448.   sAsn: string;
  449.   subsel, subfiles: PStringList;
  450.   subselres: integer;
  451.   sTmp1: string;
  452. begin
  453.   repeat
  454.     InitOidDef(@oid);
  455.     _ReadOidFile(filename, @oid);
  456.  
  457.     (* Print OID information *)
  458.  
  459.     ClrScr;
  460.  
  461.     if oid.DotNotation = '' then
  462.       DrawTitleBar('OID ROOT')
  463.     else
  464.       DrawTitleBar('OID ' + oid.DotNotation);
  465.     GotoXY(ScreenWidth-Length(filename)+1,1);
  466.     TextBackground(White);
  467.     TextColor(Black);
  468.     WriteLn(filename);
  469.     TextBackground(Black);
  470.     TextColor(White);
  471.     DrawStatusBar(DEFAULT_STATUSBAR);
  472.     GotoXY(1,2);
  473.  
  474.     if oid.DotNotation <> '' then
  475.     begin
  476.       WriteLn('Dot-Notation:');
  477.       WriteLn(oid.DotNotation);
  478.       WriteLn('');
  479.     end;
  480.  
  481.     if Trim(oid.Description) <> '' then
  482.     begin
  483.       WriteLn('Description:');
  484.       WriteLn(oid.Description);
  485.       WriteLn('');
  486.     end;
  487.  
  488.     menuX := WhereX + 1;
  489.     menuY := ScreenHeight - NAVBAR_SIZE - 1;
  490.  
  491.     if ListCount(oid.ASNIDs) > 0 then
  492.     begin
  493.       linesLeft := menuY - WhereY - 1;
  494.       linesRequired := 1 + ListCount(oid.ASNIds);
  495.  
  496.       if LinesLeft < LinesRequired then
  497.       begin
  498.         (* Compact display of ASN.1 identifiers *)
  499.         Write('ASN.1-Identifiers: ');
  500.         for i := 0 to ListCount(oid.ASNIds)-1 do
  501.         begin
  502.           if i > 0 then Write(', ');
  503.           Write(ListGetElement(oid.ASNIds, i));
  504.         end;
  505.         WriteLn('');
  506.       end
  507.       else
  508.       begin
  509.         (* Long display of ASN.1 identifiers *)
  510.         WriteLn('ASN.1-Identifiers:');
  511.         for i := 0 to ListCount(oid.ASNIds)-1 do
  512.         begin
  513.           WriteLn('- '+ListGetElement(oid.ASNIds, i));
  514.         end;
  515.         WriteLn('');
  516.       end;
  517.     end;
  518.  
  519.     (* Now prepare the menu entries *)
  520.  
  521.     InitList(subsel);
  522.     InitList(subfiles);
  523.  
  524.     sTmp := oid.Parent;
  525.     if sTmp = '' then
  526.     begin
  527.       isRoot := true;
  528.     end
  529.     else
  530.     begin
  531.       Delete(sTmp, 1, 8);
  532.       isRoot := sTmp = oid.DotNotation;
  533.     end;
  534.  
  535.     if (oid.Parent <> '') and not isRoot then
  536.     begin
  537.       sTmp := oid.Parent;
  538.       subfile := Copy(sTmp, 1, 8)+'.OID';
  539.       Delete(sTmp, 1, 8);
  540.       sTmp := sTmp + _ShowASNIds(subfile);
  541.       ListAppend(subsel, 'Go to parent ' + sTmp);
  542.       ListAppend(subfiles, subfile);
  543.     end;
  544.  
  545.     if isRoot then
  546.     begin
  547.       ListAppend(subsel, 'Back to main menu');
  548.       ListAppend(subfiles, ID_EXIT);
  549.     end;
  550.  
  551.     for i := 0 to ListCount(oid.SubIds)-1 do
  552.     begin
  553.       sTmp := ListGetElement(oid.SubIds, i);
  554.       subfile := Copy(sTmp, 1, 8)+'.OID';
  555.       Delete(sTmp, 1, 8);
  556.       sTmp := sTmp + _ShowASNIds(subfile);
  557.       ListAppend(subsel, 'Go to child  ' + sTmp);
  558.       ListAppend(subfiles, subfile);
  559.     end;
  560.  
  561.     if oid.DotNotation <> '' then
  562.     begin
  563.       ListAppend(subsel, 'Edit ASN.1 identifiers');
  564.       ListAppend(subfiles, ID_ASNEDIT);
  565.     end;
  566.  
  567.     ListAppend(subsel, 'Edit description');
  568.     ListAppend(subfiles, ID_DESCEDIT);
  569.  
  570.     ListAppend(subsel, 'Add child');
  571.     ListAppend(subfiles, ID_ADDCHILD);
  572.  
  573.     if not isRoot then
  574.     begin
  575.       ListAppend(subsel, 'Delete OID');
  576.       ListAppend(subfiles, ID_DELETE);
  577.     end;
  578.  
  579.     subselres := DrawSelectionList(menuX, menuY,
  580.                                    ScreenWidth-2,
  581.                                    NAVBAR_SIZE,
  582.                                    subsel,
  583.                                    true,
  584.                                    'SELECT ACTION',
  585.                                    1);
  586.     if subselres = -1 then
  587.     begin
  588.       exit;
  589.     end
  590.     else
  591.     begin
  592.       sTmp1 := ListGetElement(subfiles, subselres);
  593.       if sTmp1 = ID_ASNEDIT then
  594.       begin
  595.         if AsnEditor(@oid) then
  596.           _WriteOidFile(filename, @oid);
  597.       end
  598.       else if sTmp1 = ID_DESCEDIT then
  599.       begin
  600.         if DescEditor(@oid) then
  601.           _WriteOidFile(filename, @oid);
  602.       end
  603.       else if sTmp1 = ID_ADDCHILD then
  604.       begin
  605.         if NewOidEditor(@oid) then
  606.         begin
  607.           _WriteOidFile(filename, @oid);
  608.         end;
  609.       end
  610.       else if sTmp1 = ID_DELETE then
  611.       begin
  612.         ShowMessage('Are you sure you want to delete this OID?', 'DELETE OID', true);
  613.         DrawStatusBar('Y = Yes; any other key = No');
  614.         if UpCase(ReadKey) = 'Y' then
  615.         begin
  616.           filename := Copy(oid.Parent,1,8)+'.OID';
  617.           DeleteOidRecursive(@oid);
  618.         end;
  619.       end
  620.       else if sTmp1 = ID_EXIT then
  621.       begin
  622.         exit;
  623.       end
  624.       else
  625.       begin
  626.         filename := sTmp1;
  627.       end;
  628.     end;
  629.     FreeList(subsel);
  630.     FreeList(subfiles);
  631.  
  632.     FreeOidDef(@oid);
  633.   until false;
  634. end;
  635.  
  636. procedure CreateInitOIDFile(filename: string);
  637. var
  638.   oid: TOID;
  639. begin
  640.   InitOidDef(@oid);
  641.   oid.Description := 'This is the root of the OID tree.' +#13#10 +
  642.                      #13#10 +
  643.                      'Valid subsequent arcs are per definition:' + #13#10 +
  644.                      '- 0 (itu-t)' + #13#10 +
  645.                      '- 1 (iso)' + #13#10 +
  646.                      '- 2 (joint-iso-itu-t)';
  647.   oid.FileId      := '00000000';
  648.   oid.DotNotation := '';
  649.   oid.Parent      := '00000000';
  650.   _WriteOidFile(filename, @oid);
  651.   FreeOidDef(@oid);
  652. end;
  653.  
  654. procedure OP_ManageOIDs;
  655. begin
  656.   ClrScr;
  657.   DrawTitleBar('Manage Object Identifiers');
  658.   DrawStatusBar('');
  659.  
  660.   if not FileExists('00000000.OID') then
  661.   begin
  662.     CreateInitOIDFile('00000000.OID');
  663.   end;
  664.   DisplayOIDFile('00000000.OID');
  665. end;
  666.  
  667. procedure OP_ManageRAs;
  668. begin
  669.   ClrScr;
  670.   DrawTitleBar('Manage Registration Authorities');
  671.   DrawStatusBar('');
  672.  
  673.   (* TODO: Implement "Manage RAs" feature *)
  674.   ShowMessage('This feature has not yet been implemented!', 'NOTICE', true);
  675.   _Pause;
  676. end;
  677.  
  678. procedure OP_ReturnToMSDOS;
  679. begin
  680.   ClrScr;
  681. end;
  682.  
  683. procedure OP_MainMenu;
  684. const
  685.   MenuWidth = 15;
  686.   MenuHeight = 3;
  687. var
  688.   menu: PStringList;
  689.   menuRes, menuLeft, menuTop: integer;
  690. begin
  691.   repeat
  692.     ClrScr;
  693.  
  694.     DrawTitleBar('Welcome to OIDplus for DOS');
  695.     DrawStatusBar(DEFAULT_STATUSBAR);
  696.     GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
  697.     Write(VERSIONINFO);
  698.  
  699.     InitList(menu);
  700.     ListAppend(menu, 'Manage OIDs');
  701.     ListAppend(menu, 'Manage RAs');
  702.     ListAppend(menu, 'Return to DOS');
  703.     menuLeft := round(ScreenWidth/2 -MenuWidth/2);
  704.     menuTop  := round(ScreenHeight/2-MenuHeight/2);
  705.     menuRes  := DrawSelectionList(menuLeft, menuTop, MenuWidth, MenuHeight, menu, true, 'MAIN MENU', 2);
  706.     FreeList(menu);
  707.  
  708.     if menuRes = 0 then
  709.     begin
  710.       OP_ManageOIDs;
  711.     end;
  712.  
  713.     if menuRes = 1 then
  714.     begin
  715.       OP_ManageRAs;
  716.     end;
  717.   until (menuRes = 2) or (menuRes = -1);
  718.  
  719.   OP_ReturnToMSDOS;
  720. end;
  721.  
  722. begin
  723.   OP_MainMenu;
  724. end.
  725.