Subversion Repositories oidplus

Rev

Rev 742 | Rev 744 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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