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. |