Subversion Repositories oidplus

Rev

Rev 739 | Rev 741 | 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-14                         *)
  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-14';
  17.   DEFAULT_STATUSBAR      = '(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.';
  18.   TITLEBAR_LEFT_TEXT     = 'OIDplus';
  19.   DISKIO_SOUND_DEBUGGING = false;
  20.   DISKIO_SOUND_DELAY     = 500;
  21.   ASNEDIT_LINES          = 10;
  22.   DESCEDIT_LINES         = 10;
  23.   DESCEDIT_PADDING       = 3;
  24.   ACTIONMENU_SIZE        = 5;
  25.   MAINMENU_WIDTH         = 15;
  26.   MAINMENU_HEIGHT        = 3;
  27.   MAINMENU_ALLOW_ESC     = false;
  28.   TREEVIEW_INDENT        = 0;
  29.   TREEVIEW_INCLUDE_DESC  = true;
  30.   TREEVIEW_WIDTH         = 80;
  31.  
  32. procedure _WriteOidFile(filename: string; oid: POid);
  33. begin
  34.   DrawStatusBar('Write file ' + filename + '...');
  35.   WriteOidFile(filename, oid);
  36.  
  37.   if DISKIO_SOUND_DEBUGGING then
  38.   begin
  39.     Sound(70);
  40.     Delay(DISKIO_SOUND_DELAY - 10);
  41.     NoSound;
  42.     Delay(10);
  43.   end;
  44.  
  45.   DrawStatusBar(DEFAULT_STATUSBAR);
  46. end;
  47.  
  48. procedure _ReadOidFile(filename: string; oid: POid);
  49. begin
  50.   DrawStatusBar('Read file ' + filename + '...');
  51.   ReadOidFile(filename, oid);
  52.  
  53.   if DISKIO_SOUND_DEBUGGING then
  54.   begin
  55.     Sound(50);
  56.     Delay(DISKIO_SOUND_DELAY - 10);
  57.     NoSound;
  58.     Delay(10);
  59.   end;
  60.  
  61.   DrawStatusBar(DEFAULT_STATUSBAR);
  62. end;
  63.  
  64. procedure _Pause;
  65. var
  66.   bakX, bakY: integer;
  67. begin
  68.   bakX := WhereX;
  69.   bakY := WhereY;
  70.   DrawStatusBar('Press any key to continue');
  71.   GoToXY(bakX, bakY);
  72.   ReadKey;
  73.   DrawStatusBar(DEFAULT_STATUSBAR);
  74. end;
  75.  
  76. function _ShowASNIds(childOID: POID): string;
  77. var
  78.   j, jmax: integer;
  79.   sTmp: string;
  80. begin
  81.   sTmp := '';
  82.   jmax := ListCount(childOID^.ASNIds)-1;
  83.   for j := 0 to jmax do
  84.   begin
  85.     if j = 0 then sTmp := sTmp + ' (';
  86.     sTmp := sTmp + ListGetElement(childOID^.ASNIds, j);
  87.     if j = jmax then
  88.       sTmp := sTmp + ')'
  89.     else
  90.       sTmp := sTmp + ', ';
  91.   end;
  92.   _ShowASNIds := sTmp;
  93. end;
  94.  
  95. function AsnAlreadyExisting(oid: POID; asnid: string): boolean;
  96. var
  97.   sTmp: string;
  98.   i: integer;
  99. begin
  100.   for i := 0 to ListCount(oid^.AsnIds)-1 do
  101.   begin
  102.     sTmp := ListGetElement(oid^.AsnIds, i);
  103.     if sTmp = asnid then
  104.     begin
  105.       AsnAlreadyExisting := true;
  106.       exit;
  107.     end;
  108.   end;
  109.   AsnAlreadyExisting := false;
  110. end;
  111.  
  112. function AsnEditor(oid: POID): boolean;
  113. var
  114.   asnList: PStringList;
  115.   i: integer;
  116.   x, y, w, h: integer;
  117.   res: integer;
  118.   sInput: string;
  119.   menuIdNew, menuIdSave, menuIdExit: integer;
  120. begin
  121.   AsnEditor := false;
  122.  
  123.   repeat
  124.     CreateList(asnList);
  125.  
  126.     for i := 0 to ListCount(oid^.ASNIds)-1 do
  127.     begin
  128.       ListAppend(asnList, ListGetElement(oid^.ASNIDs, i));
  129.     end;
  130.     menuIdNew  := ListAppend(asnList, '<NEW>');
  131.     menuIdSave := ListAppend(asnList, '<SAVE>');
  132.     menuIdExit := ListAppend(asnList, '<CANCEL>');
  133.  
  134.     DrawStatusBar(DEFAULT_STATUSBAR);
  135.     x := SINGLE_LINE_BOX_PADDING;
  136.     y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
  137.     w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
  138.     h := ASNEDIT_LINES;
  139.     res := DrawSelectionList(x, y, w, h,
  140.                              asnList, true,
  141.                              'EDIT ASN.1 IDENTIFIERS',
  142.                              2);
  143.     FreeList(asnList);
  144.  
  145.     (* Change double-border to thin-border *)
  146.     DrawThinBorder(x-1, y-1, w+2, h+2);
  147.     GoToXY(x+1, y-1);
  148.     Write('EDIT ASN.1 IDENTIFIERS');
  149.  
  150.     if res = -1 then
  151.     begin
  152.       exit;
  153.     end
  154.     else if res = menuIdNew then
  155.     begin
  156.       (* "NEW" item was selected *)
  157.       sInput := '';
  158.       repeat
  159.         if QueryVal(sInput,
  160.                     SINGLE_LINE_BOX_PADDING_INNER,
  161.                     ScreenHeight div 2,
  162.                     ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
  163.                     1,
  164.                     'ADD SINGLE ASN.1 ID',
  165.                     2) then
  166.         begin
  167.           if sInput = '' then continue;
  168.           if not ASN1IDValid(sInput) then
  169.           begin
  170.             ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
  171.             _Pause;
  172.           end
  173.           else if AsnAlreadyExisting(oid, sInput) then
  174.           begin
  175.             ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
  176.             _Pause;
  177.           end
  178.           else
  179.           begin
  180.             ListAppend(oid^.ASNIDs, sInput);
  181.             break;
  182.           end;
  183.         end
  184.         else break;
  185.       until false;
  186.     end
  187.     else if res = menuIdSave then
  188.     begin
  189.       (* "SAVE" item was selected *)
  190.       AsnEditor := true;
  191.       Exit;
  192.     end
  193.     else if res = menuIdExit then
  194.     begin
  195.       (* "CANCEL" item was selected *)
  196.       AsnEditor := false;
  197.       Exit;
  198.     end
  199.     else
  200.     begin
  201.       DrawStatusBar('Note: Remove the text to delete the ASN.1 identifier');
  202.       sInput := ListGetElement(oid^.ASNIDs, res);
  203.       repeat
  204.         if QueryVal(sInput,
  205.                     SINGLE_LINE_BOX_PADDING_INNER,
  206.                     ScreenHeight div 2,
  207.                     ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
  208.                     1,
  209.                     'EDIT SINGLE ASN.1 ID',
  210.                     2) then
  211.         begin
  212.           if sInput = '' then
  213.           begin
  214.             (* Empty input = Delete ASN.1 ID *)
  215.             ListDeleteElementByIndex(oid^.ASNIDs, res);
  216.             break;
  217.           end
  218.           else if not ASN1IDValid(sInput) then
  219.           begin
  220.             ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
  221.             _Pause;
  222.           end
  223.           else if AsnAlreadyExisting(oid, sInput) and
  224.               not (ListGetElement(oid^.ASNIDs, res) = sInput) then
  225.           begin
  226.             ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
  227.             _Pause;
  228.           end
  229.           else
  230.           begin
  231.             ListSetElement(oid^.ASNIDs, res, sInput);
  232.             break;
  233.           end;
  234.         end
  235.         else break;
  236.       until false;
  237.     end;
  238.   until false;
  239. end;
  240.  
  241. function DescEditor(oid: POID): boolean;
  242. var
  243.   sInput: string;
  244. begin
  245.   DescEditor := false;
  246.  
  247.   DrawStatusBar('Note: Press Ctrl+Return for a line-break.');
  248.   sInput := oid^.description;
  249.   if QueryVal(sInput,
  250.               DESCEDIT_PADDING,
  251.               ScreenHeight div 2 - DESCEDIT_LINES div 2,
  252.               ScreenWidth - (DESCEDIT_PADDING-1)*2,
  253.               DESCEDIT_LINES,
  254.               'EDIT DESCRIPTION',
  255.               2) then
  256.   begin
  257.     oid^.description := sInput;
  258.     DescEditor := true; (* request caller to save <oid> *)
  259.   end;
  260. end;
  261.  
  262. function NextPossibleFileID: string;
  263. var
  264.   DirInfo: SearchRec;
  265.   list: PStringList;
  266.   iId: LongInt;
  267.   sId: string;
  268. begin
  269.   (* Put all found files into a list *)
  270.   CreateList(list);
  271.   FindFirst('????????.OID', Archive, DirInfo);
  272.   while DosError = 0 do
  273.   begin
  274.     sId := Copy(DirInfo.Name, 1, 8);
  275.     ListAppend(list, sId);
  276.     FindNext(DirInfo);
  277.   end;
  278.  
  279.   (* Search for the first non existing item in the list *)
  280.   sId := '';
  281.   for iId := 0 to 99999999 do
  282.   begin
  283.     sId := ZeroPad(iId, 8);
  284.     if not ListContains(list, sId) then break;
  285.   end;
  286.   NextPossibleFileId := sId;
  287.   FreeList(list);
  288. end;
  289.  
  290. function NumIdAlreadyExisting(parentOID: POID; sInput: string): boolean;
  291. var
  292.   searchDotNotation: string;
  293.   sTmp: string;
  294.   i: integer;
  295. begin
  296.   if parentOID^.DotNotation = '' then
  297.     searchDotNotation := sInput
  298.   else
  299.     searchDotNotation := parentOID^.DotNotation + '.' + sInput;
  300.   for i := 0 to ListCount(parentOID^.SubIds)-1 do
  301.   begin
  302.     sTmp := ListGetElement(parentOID^.SubIds, i);
  303.     if DotNotationPart(sTmp) = searchDotNotation then
  304.     begin
  305.       NumIdAlreadyExisting := true;
  306.       exit;
  307.     end;
  308.   end;
  309.   NumIdAlreadyExisting := false;
  310. end;
  311.  
  312. function NumIdEditor(oid: POID; parentOID: POID): boolean;
  313. var
  314.   sInput: string;
  315. begin
  316.   NumIdEditor := false;
  317.   sInput := '';
  318.  
  319.   repeat
  320.     if QueryVal(sInput,
  321.                 SINGLE_LINE_BOX_PADDING_INNER,
  322.                 ScreenHeight div 2,
  323.                 ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
  324.                 1,
  325.                 'ENTER NUMERIC ID',
  326.                 2) then
  327.     begin
  328.       if sInput = '' then continue;
  329.       if not IsPositiveInteger(sInput) then
  330.       begin
  331.         ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
  332.         _Pause;
  333.       end
  334.       else if (parentOID^.DotNotation='') and (StrToInt(sInput) > 2) then
  335.       begin
  336.         ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
  337.         _Pause;
  338.       end
  339.       else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and (StrToInt(sInput) > 39) then
  340.       begin
  341.         ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
  342.         _Pause;
  343.       end
  344.       else if NumIdAlreadyExisting(parentOID, sInput) then
  345.       begin
  346.         ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
  347.         _Pause;
  348.       end
  349.       else
  350.       begin
  351.         if parentOID^.DotNotation = '' then
  352.           oid^.DotNotation := sInput
  353.         else
  354.           oid^.DotNotation := parentOID^.DotNotation + '.' + sInput;
  355.         NumIdEditor := true; (* request caller to save <oid> *)
  356.         Exit;
  357.       end;
  358.     end
  359.     else
  360.     begin
  361.       Exit;
  362.     end;
  363.   until false;
  364. end;
  365.  
  366. function NewOidEditor(oid: POID): boolean;
  367. var
  368.   newfilename: string;
  369.   newOID: POID;
  370. begin
  371.   NewOidEditor := false;
  372.  
  373.   CreateOidDef(newOID);
  374.   newOID^.FileId := NextPossibleFileID;
  375.   newOID^.Parent := oid^.FileId + oid^.DotNotation;
  376.   if NumIdEditor(newOID, oid) and
  377.      AsnEditor(newOID) and
  378.      DescEditor(newOID) then
  379.   begin
  380.     newfilename := newOID^.FileId + '.OID';
  381.     _WriteOidFile(newfilename, newOID);
  382.  
  383.     (* Add link to original file and enable the saving of it *)
  384.     ListAppend(oid^.SubIds, newOID^.FileId + newOID^.DotNotation);
  385.     NewOidEditor := true; (* request caller to save <oid> *)
  386.   end;
  387.   FreeOidDef(newOID);
  388. end;
  389.  
  390. procedure DeleteChildrenRecursive(oid: POID);
  391. var
  392.   i: integer;
  393.   childOID: POID;
  394.   filenameChild: string;
  395. begin
  396.   for i := 0 to ListCount(oid^.SubIds)-1 do
  397.   begin
  398.     filenameChild := FileIdPart(ListGetElement(oid^.SubIds, i)) + '.OID';
  399.     if FileExists(filenameChild) then
  400.     begin
  401.       CreateOidDef(childOID);
  402.       _ReadOidFile(filenameChild, childOID);
  403.       DeleteChildrenRecursive(childOID);
  404.       FreeOidDef(childOID);
  405.       DeleteFile(filenameChild);
  406.     end;
  407.   end;
  408.   ListClear(oid^.SubIds);
  409. end;
  410.  
  411. procedure DeleteOidRecursive(selfOID: POID);
  412. var
  413.   i: integer;
  414.   parentOID: POID;
  415.   filenameSelf, filenameParent: string;
  416. begin
  417.   (* Remove all children and their files recursively *)
  418.   DeleteChildrenRecursive(selfOID);
  419.  
  420.   (* Remove forward reference in parent OID *)
  421.   filenameParent := FileIdPart(selfOID^.Parent) + '.OID';
  422.   if FileExists(filenameParent) then
  423.   begin
  424.     CreateOidDef(parentOID);
  425.     _ReadOidFile(filenameParent, parentOID);
  426.     if ListDeleteElementByValue(parentOID^.SubIds, selfOID^.FileId + selfOID^.DotNotation) then
  427.     begin
  428.       _WriteOidFile(filenameParent, parentOID);
  429.     end;
  430.     FreeOidDef(parentOID);
  431.   end;
  432.  
  433.   (* Delete own file *)
  434.   filenameSelf := selfOID^.FileId + '.OID';
  435.   if FileExists(filenameSelf) then
  436.   begin
  437.     DeleteFile(filenameSelf);
  438.   end;
  439. end;
  440.  
  441. function _DeleteConfirmation: boolean;
  442. var
  443.   sc: Char;
  444. begin
  445.   repeat
  446.     ShowMessage('Are you sure you want to delete this OID? (Y/N)', 'DELETE OID', true);
  447.     DrawStatusBar('Y=Yes, N=No');
  448.  
  449.     sc := ReadKey;
  450.     if sc = #0 then
  451.     begin
  452.       (* Extended key. Nothing we care about. *)
  453.       ReadKey;
  454.       continue;
  455.     end;
  456.  
  457.     if UpCase(sc) = 'Y' then
  458.     begin
  459.       _DeleteConfirmation := true;
  460.       break;
  461.     end
  462.     else if UpCase(sc) = 'N' then
  463.     begin
  464.       _DeleteConfirmation := false;
  465.       break;
  466.     end;
  467.   until false;
  468. end;
  469.  
  470. procedure _DrawOidTitleBar(filename: string; oid: POID);
  471. begin
  472.   if oid^.DotNotation = '' then
  473.     DrawTitleBar('OID ROOT', TITLEBAR_LEFT_TEXT, filename)
  474.   else
  475.     DrawTitleBar('OID ' + oid^.DotNotation, TITLEBAR_LEFT_TEXT, filename);
  476. end;
  477.  
  478. procedure DisplayOIDFile(filename: string);
  479. var
  480.   isRoot: boolean;
  481.   oid, tmpOID: POID;
  482.   i, menuX, menuY: integer;
  483.   linesLeft, linesRequired: integer;
  484.   sTmp, subfile: string;
  485.   subsel, subfiles: PStringList;
  486.   subselres: integer;
  487.   exitRequest: boolean;
  488.   menuIdExit, menuIdAsnEdit, menuIdDescEdit, menuIdAdd, menuIdDelete: integer;
  489. begin
  490.   exitRequest := false;
  491.   repeat
  492.     if not FileExists(filename) then
  493.     begin
  494.       ShowMessage('File ' + filename + ' not found', 'ERROR', true);
  495.       _Pause;
  496.       exit;
  497.     end;
  498.  
  499.     CreateOidDef(oid);
  500.     _ReadOidFile(filename, oid);
  501.  
  502.     (* Print OID information *)
  503.  
  504.     ClrScr;
  505.     _DrawOidTitleBar(filename, oid);
  506.     DrawStatusBar(DEFAULT_STATUSBAR);
  507.     GotoXY(1,2);
  508.  
  509.     if oid^.DotNotation <> '' then
  510.     begin
  511.       WriteLn('Dot-Notation:');
  512.       WriteLn(oid^.DotNotation);
  513.       WriteLn('');
  514.     end;
  515.  
  516.     if Trim(oid^.Description) <> '' then
  517.     begin
  518.       WriteLn('Description:');
  519.       WriteLn(oid^.Description);
  520.       WriteLn('');
  521.     end;
  522.  
  523.     menuX := WhereX + 1;
  524.     menuY := ScreenHeight - ACTIONMENU_SIZE - 1;
  525.  
  526.     if ListCount(oid^.ASNIDs) > 0 then
  527.     begin
  528.       linesLeft := menuY - WhereY - 1;
  529.       linesRequired := 1 + ListCount(oid^.ASNIds);
  530.  
  531.       if LinesLeft < LinesRequired then
  532.       begin
  533.         (* Compact display of ASN.1 identifiers *)
  534.         Write('ASN.1-Identifiers: ');
  535.         for i := 0 to ListCount(oid^.ASNIds)-1 do
  536.         begin
  537.           if i > 0 then Write(', ');
  538.           Write(ListGetElement(oid^.ASNIds, i));
  539.         end;
  540.         WriteLn('');
  541.       end
  542.       else
  543.       begin
  544.         (* Long display of ASN.1 identifiers *)
  545.         WriteLn('ASN.1-Identifiers:');
  546.         for i := 0 to ListCount(oid^.ASNIds)-1 do
  547.         begin
  548.           WriteLn('- '+ListGetElement(oid^.ASNIds, i));
  549.         end;
  550.         WriteLn('');
  551.       end;
  552.     end;
  553.  
  554.     (* Now prepare the menu entries *)
  555.  
  556.     CreateList(subsel);   (* Contains the human readable OID name *)
  557.     CreateList(subfiles); (* Contains the file name               *)
  558.  
  559.     if oid^.Parent = '' then
  560.     begin
  561.       isRoot := true;
  562.     end
  563.     else
  564.     begin
  565.       isRoot := DotNotationPart(oid^.Parent) = oid^.DotNotation;
  566.     end;
  567.  
  568.     if (oid^.Parent <> '') and not isRoot then
  569.     begin
  570.       sTmp := oid^.Parent;
  571.       subfile := FileIdPart(sTmp) + '.OID';
  572.       if FileExists(subfile) then
  573.       begin
  574.         CreateOidDef(tmpOID);
  575.         _ReadOidFile(subfile, tmpOID);
  576.         ListAppend(subsel, 'Go to parent ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
  577.         FreeOidDef(tmpOID);
  578.       end
  579.       else
  580.       begin
  581.         ListAppend(subsel, 'Go to parent ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
  582.       end;
  583.       ListAppend(subfiles, subfile);
  584.     end;
  585.  
  586.     if isRoot then
  587.     begin
  588.       menuIdExit := ListAppend(subsel, 'Back to main menu');
  589.       ListAppend(subfiles, '');
  590.     end
  591.     else menuIdExit := -99;
  592.  
  593.     for i := 0 to ListCount(oid^.SubIds)-1 do
  594.     begin
  595.       sTmp := ListGetElement(oid^.SubIds, i);
  596.       subfile := FileIdPart(sTmp) + '.OID';
  597.       if FileExists(subfile) then
  598.       begin
  599.         CreateOidDef(tmpOID);
  600.         _ReadOidFile(subfile, tmpOID);
  601.         ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
  602.         FreeOidDef(tmpOID);
  603.       end
  604.       else
  605.       begin
  606.         ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
  607.       end;
  608.       ListAppend(subfiles, subfile);
  609.     end;
  610.  
  611.     if oid^.DotNotation <> '' then
  612.     begin
  613.       menuIdAsnEdit := ListAppend(subsel, 'Edit ASN.1 identifiers');
  614.       ListAppend(subfiles, '');
  615.     end
  616.     else menuIdAsnEdit := -99;
  617.  
  618.     menuIdDescEdit := ListAppend(subsel, 'Edit description');
  619.     ListAppend(subfiles, '');
  620.  
  621.     menuIdAdd := ListAppend(subsel, 'Add child');
  622.     ListAppend(subfiles, '');
  623.  
  624.     if not isRoot then
  625.     begin
  626.       menuIdDelete := ListAppend(subsel, 'Delete OID');
  627.       ListAppend(subfiles, '');
  628.     end
  629.     else menuIdDelete := -99;
  630.  
  631.     (* Show menu *)
  632.  
  633.     subselres := DrawSelectionList(menuX, menuY,
  634.                                    ScreenWidth-2,
  635.                                    ACTIONMENU_SIZE,
  636.                                    subsel,
  637.                                    true,
  638.                                    'SELECT ACTION',
  639.                                    1);
  640.  
  641.     (* Process user selection *)
  642.  
  643.     if subselres = -1 then
  644.     begin
  645.       exitRequest := true;
  646.     end
  647.     else if subselres = menuIdAsnEdit then
  648.     begin
  649.       if AsnEditor(oid) then
  650.         _WriteOidFile(filename, oid);
  651.     end
  652.     else if subselres = menuIdDescEdit then
  653.     begin
  654.       if DescEditor(oid) then
  655.         _WriteOidFile(filename, oid);
  656.     end
  657.     else if subselres = menuIdAdd then
  658.     begin
  659.       if NewOidEditor(oid) then
  660.         _WriteOidFile(filename, oid);
  661.     end
  662.     else if subselres = menuIdDelete then
  663.     begin
  664.       if _DeleteConfirmation then
  665.       begin
  666.         sTmp := FileIdPart(oid^.Parent) + '.OID';
  667.         DeleteOidRecursive(oid);
  668.         if FileExists(sTmp) then
  669.         begin
  670.           filename := sTmp;
  671.         end
  672.         else
  673.         begin
  674.           ShowMessage('Parent file ' + filename + ' not found', 'ERROR', true);
  675.           _Pause;
  676.           exitRequest := true;
  677.         end;
  678.       end;
  679.     end
  680.     else if subselres = menuIdExit then
  681.     begin
  682.       exitRequest := true;
  683.     end
  684.     else
  685.     begin
  686.       (* Normal OID *)
  687.       sTmp := ListGetElement(subfiles, subselres);
  688.       if FileExists(sTmp) then
  689.       begin
  690.         filename := sTmp;
  691.       end
  692.       else
  693.       begin
  694.         ShowMessage('File ' + filename + ' not found', 'ERROR', true);
  695.         (* TODO: With PatchCRT, there will be an infinite loop here *)
  696.         _Pause;
  697.       end;
  698.     end;
  699.     FreeList(subsel);
  700.     FreeList(subfiles);
  701.  
  702.     FreeOidDef(oid);
  703.   until exitRequest;
  704. end;
  705.  
  706. procedure CreateInitOIDFile(filename: string);
  707. var
  708.   oid: POID;
  709. begin
  710.   CreateOidDef(oid);
  711.   oid^.Description := 'This is the root of the OID tree.' +#13#10 +
  712.                       #13#10 +
  713.                       'Valid subsequent arcs are per definition:' + #13#10 +
  714.                       '- 0 (itu-t)' + #13#10 +
  715.                       '- 1 (iso)' + #13#10 +
  716.                       '- 2 (joint-iso-itu-t)';
  717.   oid^.FileId      := ZeroPad(0, 8);
  718.   oid^.DotNotation := '';
  719.   oid^.Parent      := ZeroPad(0, 8);
  720.   _WriteOidFile(filename, oid);
  721.   FreeOidDef(oid);
  722. end;
  723.  
  724. function _GetInitFile: string;
  725. var
  726.   initFile: string;
  727. begin
  728.   initFile := ZeroPad(0, 8) + '.OID';
  729.   if not FileExists(initFile) then
  730.   begin
  731.     CreateInitOIDFile(initFile);
  732.   end;
  733.   _GetInitFile := initFile;
  734. end;
  735.  
  736. procedure OP_ManageOIDs;
  737. begin
  738.   ClrScr;
  739.   DrawTitleBar('Manage Object Identifiers', TITLEBAR_LEFT_TEXT, '');
  740.   DrawStatusBar('Loading data... please wait...');
  741.  
  742.   DisplayOIDFile(_GetInitFile);
  743. end;
  744.  
  745. procedure OP_ManageRAs;
  746. begin
  747.   ClrScr;
  748.   DrawTitleBar('Manage Registration Authorities', TITLEBAR_LEFT_TEXT, '');
  749.   DrawStatusBar('');
  750.  
  751.   (* TODO: Implement "Manage RAs" feature *)
  752. end;
  753.  
  754. procedure OP_ReturnToMSDOS;
  755. begin
  756.   ClrScr;
  757. end;
  758.  
  759. function _GetExportLine(oid: POID; indent: integer): string;
  760. var
  761.   i: integer;
  762.   sTmp: string;
  763. begin
  764.   (* Build line *)
  765.   sTmp := RepeatStr(' ', indent*TREEVIEW_INDENT);
  766.   if oid^.DotNotation = '' then
  767.     sTmp := sTmp + 'Object Identifiers'
  768.   else
  769.     sTmp := sTmp + oid^.DotNotation;
  770.   sTmp := sTmp + _ShowAsnIds(oid);
  771.   if TREEVIEW_INCLUDE_DESC then
  772.   begin
  773.     if Trim(oid^.Description) <> '' then
  774.     begin
  775.       sTmp := sTmp + ': ' + oid^.Description;
  776.     end;
  777.   end;
  778.   for i := 1 to Length(sTmp) do
  779.   begin
  780.     if (sTmp[i]=#13) or (sTmp[i]=#10) then sTmp[i] := ' ';
  781.   end;
  782.   if Length(sTmp) > TREEVIEW_WIDTH then
  783.   begin
  784.     sTmp := Copy(sTmp, 1, TREEVIEW_WIDTH-3) + '...';
  785.   end;
  786.   _GetExportLine := sTmp;
  787. end;
  788.  
  789. procedure _RecTreeExport(oid: POID; var F: Text; indent: integer);
  790. var
  791.   i: integer;
  792.   sTmp: string;
  793.   suboid: POID;
  794.   childFilename: string;
  795. begin
  796.   sTmp := _GetExportLine(oid, indent);
  797.   sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
  798.   WriteLn(F, sTmp);
  799.  
  800.   (* Recursively call children *)
  801.   for i := 0 to ListCount(oid^.SubIds)-1 do
  802.   begin
  803.     sTmp := ListGetElement(oid^.SubIds, i);
  804.     CreateOidDef(suboid);
  805.     childFilename := FileIdPart(sTmp) + '.OID';
  806.     if FileExists(childFilename) then
  807.     begin
  808.       _ReadOidFile(childFilename, suboid);
  809.       _RecTreeExport(suboid, F, indent+1);
  810.       FreeOidDef(suboid);
  811.     end
  812.     else
  813.     begin
  814.       sTmp := 'ERROR: FILE ' + childFilename + ' CONTAINING CHILD OID ' + DotNotationPart(sTmp) + ' WAS NOT FOUND!';
  815.       sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
  816.       WriteLn(F, sTmp);
  817.     end;
  818.   end;
  819. end;
  820.  
  821. procedure OP_TreeView;
  822. var
  823.   F: Text;
  824.   rootoid: POID;
  825. begin
  826.   ClrScr;
  827.   DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, '');
  828.   DrawStatusBar('Exporting data... please wait...');
  829.  
  830.   Assign(F, 'OIDTREE.TXT');
  831.   Rewrite(F);
  832.  
  833.   CreateOidDef(rootoid);
  834.   _ReadOidFile(_GetInitFile, rootoid);
  835.   _RecTreeExport(rootoid, F, 0);
  836.   FreeOidDef(rootoid);
  837.  
  838.   DrawStatusBar(DEFAULT_STATUSBAR);
  839.   ShowMessage('TreeView successfully exported as OIDTREE.TXT', 'TREEVIEW EXPORT', true);
  840.   _Pause;
  841.  
  842.   Close(F);
  843. end;
  844.  
  845. procedure OP_MainMenu;
  846. var
  847.   menu: PStringList;
  848.   menuRes, menuLeft, menuTop: integer;
  849.   menuIdOID, menuIdRA, menuIdTree, menuIdExit: integer;
  850. begin
  851.   repeat
  852.     ClrScr;
  853.  
  854.     DrawTitleBar('Welcome to OIDplus for DOS', '', '');
  855.     DrawStatusBar(DEFAULT_STATUSBAR);
  856.     GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
  857.     Write(VERSIONINFO);
  858.  
  859.     CreateList(menu);
  860.  
  861.     menuIdOID  := ListAppend(menu, 'Manage OIDs');
  862.     menuIdRA   := -99; (*ListAppend(menu, 'Manage RAs');*)
  863.     menuIdTree := ListAppend(menu, 'Export TreeView');
  864.     menuIdExit := ListAppend(menu, 'Return to DOS');
  865.  
  866.     menuLeft := round(ScreenWidth/2 -MAINMENU_WIDTH/2);
  867.     menuTop  := round(ScreenHeight/2-MAINMENU_HEIGHT/2);
  868.     menuRes  := DrawSelectionList(menuLeft, menuTop,
  869.                                   MAINMENU_WIDTH, MAINMENU_HEIGHT,
  870.                                   menu, true, 'MAIN MENU', 2);
  871.     FreeList(menu);
  872.  
  873.     if menuRes = menuIdOID then
  874.     begin
  875.       OP_ManageOIDs;
  876.     end
  877.     else if menuRes = menuIdRA then
  878.     begin
  879.       OP_ManageRAs;
  880.     end
  881.     else if menuRes = menuIdTree then
  882.     begin
  883.       OP_Treeview;
  884.     end;
  885.   until (menuRes = menuIdExit) or (MAINMENU_ALLOW_ESC and (menuRes = -1));
  886.  
  887.   OP_ReturnToMSDOS;
  888. end;
  889.  
  890. begin
  891.   OP_MainMenu;
  892. end.
  893.