#!/usr/bin/perl -w # # $Id$ # ############################################################################ # The following preferences may be modified to match the local environment # ############################################################################ # Directory with the users data. $TMPDIR = '/tmp/asn1c-cgi-jail/'; $SUIDHelper = './asn1c-suid-helper'; $SkeletonsDir = '/usr/local/share/asn1c'; # Will be needed only once $CompilerLocation = '/usr/local/bin/asn1c'; # asn1c binary location $HelpDBFile = $TMPDIR . '/var/db/Help-DB'; # Help requests database $HashProgramPath = 'md5'; # Program to hash the input $DM = 0750; # Directory mode for all mkdirs $MaxHistoryItems = 5; # Number of items in History $DynamicHistory = 'yes'; # Full/Short history $safeFilenameRE = '[a-zA-Z0-9_]+[.a-zA-Z0-9_-]{0,200}'; # Safe filename regex $safeTimeRE = '[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}'; $ASN1C_Page = 'http://lionet.info/asn1c'; $HelpEmail = 'asn1c@lionet.info'; $defaultUserEmail = 'your@email-for-reply'; $DataERR = 65; # EX_DATAERR from $warn = '
'; $unwarn = '
'; $OpEnvFailed = 'Failed to create the operations\' environment:'; $RandFailed = 'No source of randomness'; $SandBoxInitFailed = 'User playground initialization failed'; $myName = $ENV{SCRIPT_NAME}; # URL of this particular script (without args) $homePath = "" . "Home" . " → ASN.1" . " → Online ASN.1 Compiler" . "

"; ################################################### # The code below rarely requires any modification # ################################################### use CGI qw/param cookie header upload escapeHTML/; $|=1; # Enable AutoFlush (for older versions of Perl) my %binaryDecoders = ( x509 => { order => 1, shorder => 6, type => 'X.509 Certificate', typeExt => 'X.509 Certificate', description => 'X.509 in DER (not PEM!)', exe => 'x509dump', cmdopts => '-x', msg => '' }, tap0311 => { order => 2, shorder => 4, type => TAP3, typeExt => 'GSM TAP3-11 data', description => 'GSM TAP3-11 binary file', exe => 'tap3dump-11', cmdopts => '-x', msg => '' }, tap0310 => { order => 3, shorder => 3, type => TAP3, typeExt => 'GSM TAP3-10 data', description => 'GSM TAP3-10 binary file', exe => 'tap3dump-10', cmdopts => '-x', msg => '' }, tap0309 => { order => 4, shorder => 2, type => TAP3, typeExt => 'GSM TAP3-09 data', description => 'GSM TAP3-09 binary file', exe => 'tap3dump-09', cmdopts => '-x', msg => '' }, mheg5 => { order => 5, shorder => 5, type => 'MHEG-5', typeExt => 'ISO MHEG-5 data', description => 'ISO MHEG-5 stream file', exe => 'mheg5dump', cmdopts => '-x', msg => '' }, ber => { order => 6, shorder => 1, type => BER, typeExt => 'BER encoded data', description => 'BER/DER/CER binary file', exe => 'unber', cmdopts => '', msg => "\n" }, rrcDLCCCH => { order => -1, # Not automatic shorder => 7, type => 'RRC DL-CCCH-Message', typeExt => 'RRC DL-CCCH-Message frame', description => '3GPP RRC DL-CCCH-Message', exe => 'rrc-dump', cmdopts => '-p DL-CCCH-Message -oxer', msg => '' }, rrcULCCCH => { order => -1, shorder => 8, type => 'RRC UL-CCCH-Message', typeExt => 'RRC UL-CCCH-Message frame', description => '3GPP RRC UL-CCCH-Message', exe => 'rrc-dump', cmdopts => '-p UL-CCCH-Message -oxer', msg => '' }, rrcDLDCCH => { order => -1, shorder => 9, type => 'RRC DL-DCCH-Message -oxer', typeExt => 'RRC DL-DCCH-Message frame', description => '3GPP RRC DL-DCCH-Message', exe => 'rrc-dump', cmdopts => '-p DL-DCCH-Message -oxer', msg => '' }, rrcULDCCH => { order => -1, shorder => 10, type => 'RRC UL-DCCH-Message', typeExt => 'RRC UL-DCCH-Message frame', description => '3GPP RRC UL-DCCH-Message', exe => 'rrc-dump', cmdopts => '-p UL-DCCH-Message -oxer', msg => '' }, rrcPCCH => { order => -1, shorder => 11, type => 'RRC PCCH-Message', typeExt => 'RRC PCCH-Message frame', description => '3GPP RRC PCCH-Message', exe => 'rrc-dump', cmdopts => '-p PCCH-Message -oxer', msg => '' } ); my $redirect = ''; # No redirection by default my $redirect_bottom = ''; # No redirection text by default my $content = ''; # Default content is empty sub IssueRedirect() { $redirect = ""; $redirect_bottom = "

This page will disappear in 5 seconds.
" } # If something goes wrong, this function is invoked to display the error message sub bark($@) { local $_ = join("
\n", @_); $content = $warn . $_ . $unwarn; goto PRINTOUT; } # Make the directory name containing session files for the given Session ID sub makeSessionDirName($$) { my $pfx = shift; # Prefix is the name of the top-level directory my $sid = shift; # Session identifier (md5) $pfx . '/sessions/' . $sid . '/'; } # Create ISO 8601 time string: "YYYY-MM-DDThh:mm:ss" my $cachedTime; sub isoTime() { return $cachedTime if $cachedTime; my @tm = localtime(time); $tm[5] += 1900; $tm[4] += 1; # Insert leading zeros for(my $i = 0; $i < 5; $i++) { $tm[$i] =~ s/^(.)$/0$1/; } $cachedTime = "$tm[5]-$tm[4]-$tm[3]T$tm[2]:$tm[1]:$tm[0]"; } # Create the necessary environment for chrooting into. sub prepareChrootEnvironment() { return 1 if(-d $TMPDIR); # Envuronment already exists mkdir $TMPDIR, $DM, or bark($OpEnvFailed, $!); # Global directory mkdir $TMPDIR . 'sessions', $DM or bark($OpEnvFailed, $!); # sessions mkdir $TMPDIR . 'bin', $DM or bark($OpEnvFailed, $!); # asn1c location mkdir $TMPDIR . 'skeletons', $DM or bark($OpEnvFailed, $!); # asn1c data mkdir $TMPDIR . 'var', $DM or bark($OpEnvFailed, $!); mkdir $TMPDIR . 'var/db', $DM or bark($OpEnvFailed, $!); if(-d '/lib') { # Merge in dynamic libc mkdir $TMPDIR . 'lib', $DM or bark($OpEnvFailed, $!); system("cd $TMPDIR/lib && " . "for i in" . " /lib/ld-linux.*" # Linux ELF loader . " /lib/libc.*" # Standard C library . " /lib/libm.*" # Math library . '; do ln $i; done'); } elsif(-d '/usr/lib') { # There's no /lib on MacOS mkdir $TMPDIR . 'usr', $DM or bark($OpEnvFailed, $!); mkdir $TMPDIR . 'usr/lib', $DM or bark($OpEnvFailed, $!); mkdir $TMPDIR . 'usr/lib/system', $DM or bark($OpEnvFailed, $!); system("cd $TMPDIR/usr/lib && " . "for i in" . " /usr/lib/libc.*" . " /usr/lib/libSystem.*" . " /usr/lib/system/libmath*" . " /usr/lib/dy*" . '; do ln $i; done'); } if(-d '/usr/libexec') { # FreeBSD ELF loader mkdir $TMPDIR . 'usr', $DM; mkdir $TMPDIR . 'usr/libexec',$DM or bark($OpEnvFailed, $!); system("cd $TMPDIR/usr/libexec && " . 'for i in /usr/libexec/ld-elf.*; do ln $i; done'); } system("cp $CompilerLocation $TMPDIR/bin 2>/dev/null") == 0 or bark($OpEnvFailed, $!); system("cp -r $SkeletonsDir/* $TMPDIR/skeletons >/dev/null 2>&1") == 0 or bark($OpEnvFailed, $!); return 1; } sub makeArchive($$) { my $TMPDIR = shift; my $sandbox = shift; my $archName = $sandbox . '/+Archive.tgz'; if(! -f $archName) { system("cd $sandbox && " . "for i in ./*.[ch]; do if [ -L \$i ]; then" . " cp $TMPDIR/skeletons/\$i \$i.-;" . " mv \$i.- \$i;" . " fi done" . " && find . -name '*.[ch]' -print0" . " > ./+tmp." . $$ . ".files" . " && tar --dereference --ignore-failed-read --owner nobody --group nobody -zcf +tmp." . $$ . ".arch --null --files-from +tmp." . $$ . ".files Makefile* +Compiler.Log *.asn *.asn1 *.ber *.cer *.der *.bin *.dat *.mhg *.txt" . " && (cat ./+tmp.". $$ .".files | xargs -0 rm -f)" . " && rm -f ./Makefile* ./+tmp.". $$ .".files" . " && mv ./+tmp." . $$ . ".arch $archName" . " || rm -f ./+tmp." . $$ . ".*" ); undef unless -f $archName; } $archName; } my $EnvironmentSetOK = prepareChrootEnvironment(); # # Record user's email. # $userEmail = cookie('userEmail'); $userEmail = $defaultUserEmail unless defined($userEmail); $tmpEmail = param('email'); if(defined($tmpEmail)) { unless($tmpEmail =~ /^\s*([a-z0-9._+-]+@[a-z0-9.+-]+)\s*$/i) { bark("Invalid email address: " . "$tmpEmail"); } my $previousEmail = $userEmail; $userEmail = $1; if($userEmail eq $defaultUserEmail) { IssueRedirect(); bark("Please enter your own " . "valid email address, " . "instead of default \"$defaultUserEmail\""); } if($userEmail ne $previousEmail) { # Refresh cookie contents. my $ck = cookie(-name=>'userEmail', -value=>$userEmail, -path=>'/', -expires=>'+1d'); print "Set-Cookie: " . $ck . "\n"; } } # # Check if full history requested. # $HistoryShow = cookie('HistoryShow'); $HistoryShow = '' unless $HistoryShow; $tmpHSParam = param('history'); # Control cookie setting if (defined($tmpHSParam) && $tmpHSParam ne $HistoryShow && $tmpHSParam =~ /^(full|short)$/) { $HistoryShow = $tmpHSParam; my $ck = cookie(-name=>'HistoryShow', -value=>$HistoryShow, -path=>'/', -expires=>'+1h'); print "Set-Cookie: " . $ck . "\n"; } # # Prepare the session and create the session directory. # If session exists, perfom arguments checking and execute historic views. # $session = cookie('SessionID'); unless($session) { $session = ''; open(R, '/dev/urandom') or open(R, '/dev/random') or bark($RandFailed); read(R, $session, 16) == 16 or bark("Not enough randomness"); if($ENV{HTTP_USER_AGENT}) { $session .= $ENV{HTTP_USER_AGENT}; # Add randomness } my $pid = open(R, "-|"); if($pid == 0) { # Child open(W, "| $HashProgramPath") or die; print W $session; exit(0); } $session = ; $session =~ s/[^a-f0-9]//ig; bark("md5 program is rotten here") if(length($session) != 32); $sessionDir = makeSessionDirName($TMPDIR, $session); mkdir($sessionDir, $DM) or bark($SandBoxInitFailed); my $ck = cookie(-name=>'SessionID', -value=>$session, -path=>'/', -expires=>'+1y'); print "Set-Cookie: " . $ck . "\n"; } else { $session =~ s/[^a-f0-9]//ig; bark("Nope, try again") if(length($session) != 32); # cool hacker? # Make sure the session directory exists $sessionDir = makeSessionDirName($TMPDIR, $session); mkdir($sessionDir, $DM) or bark($SandBoxInitFailed) unless(-d $sessionDir); my $t = param('time'); my $file = param('file'); my $fetch = param('fetch'); my $show = param('show'); my $remove = param('remove'); unless(defined($t) && defined($file) && $t =~ /^${safeTimeRE}$/ && $file =~ /^${safeFilenameRE}$/ && ($fetch eq '' or $fetch =~ /^${safeFilenameRE}$/) ) { $file = ''; $fetch = ''; $show = ''; $remove = ''; } if($fetch ne '' or $show =~ /^(log|unber|tgz)$/ or $remove ne '') { my $sandbox = $sessionDir . '/' . $t . '--' . $file; my $targetFile = ''; if($show eq 'tgz') { my $tarball = makeArchive($TMPDIR, $sandbox); defined $tarball or bark("Cannot create archive [$sandbox]"); printf("Content-Type: application/x-tar\n"); printf("Content-Encoding: gzip\n\n"); exec("cat $tarball"); exit(0); } elsif($show eq 'unber') { $targetFile = $sandbox . '/+UNBER'; } elsif($show eq 'log') { $targetFile = $sandbox . '/+Compiler.Log'; } elsif($remove ne '') { print "Status: 303 See Other\n"; print "Location: $myName\n"; print "\n"; rename($sandbox, $sessionDir . '/' . $t . '-R--' . $file); exit(0); } else { $targetFile = $sandbox . '/' . $fetch; } if($targetFile ne '') { open(I, '< ' . $targetFile) or bark("Invalid or outdated request $!"); printf "Content-Type: text/plain\n\n"; print while ; exit(0); } } } # # Check if transaction help is requested. # $transHelp = param('transHelp'); if(defined($transHelp) && $transHelp =~ /^([0-9]+)--($safeTimeRE)--($safeFilenameRE)$/) { open(S, "| sendmail -it") or bark("Cannot perform help request, " . "please email to the address below"); print S "From: $userEmail\n"; print S "To: $HelpEmail\n"; print S "Subject: asn1c help requested for $3 ($1) by $userEmail\n"; print S "\n"; print S "\n-- \n"; print S "User $userEmail requested help with\n"; print S "$session/$2--$3 ($1)\n"; close(S); open(S, '>> ' . $sessionDir . '/' . $2 . '--' . $3 . '/+HelpReq') or bark("Cannot perform help request, " . "please email to the address below"); print S "$userEmail\n"; close(S); open(S, '>> ' . $HelpDBFile); # Susceptible to race condition. print S "$session/$2--$1--$3\n"; close(S); $content = '
Transaction ' . "$1 ($3) is marked for manual processing.
" . "Results will be mailed to " . "$userEmail shortly." . ""; IssueRedirect(); goto PRINTOUT; } open(LOG, ">> $sessionDir/+logfile") or bark("Sandbox error: $!"); print LOG isoTime() . "\tIP=$ENV{REMOTE_ADDR}"; print LOG "\tEMAIL=$userEmail" if($userEmail ne $defaultUserEmail); @gotSafeNames = (); @gotNames = param('file'); if($#gotNames != -1 && $gotNames[0] ne "") { $gotFile = param('file'); @gotFiles = upload('file'); } else { @gotNames = (); @gotFiles = (); $gotFile = undef; } my $asnText = param('text'); if($#gotNames == -1) { push(@gotNames, 'module.asn1') if $asnText; } # Make safe filenames foreach my $fname (@gotNames) { local $_ = $fname; s/.*\///g; # Strip directory components s/.*\\//g; # Strip directory components (DOS version) s/^[.-]/_/g; # Don't allow filenames starting with a dot or a dash s/[^._a-zA-Z0-9-]/_/g; if(!length($_)) { print LOG "\n"; bark("Too strange filename: \"$fname\""); } $_ .= '.asn1' unless(/[.](asn[1]?|[bcd]er|bin|dat|mhg|txt)$/i); @gotSafeNames = (@gotSafeNames, $_); print LOG "\t" . $_; } # # Save the files and start compilation process. # if($#gotSafeNames >= 0) { $transactionDir = isoTime() . '--' . join("-", @gotSafeNames); print LOG "\tDST=$transactionDir"; my $sandbox = $sessionDir . '/' . $transactionDir; mkdir($sandbox, $DM) or bark($SandBoxInitFailed); open(O, '> ' . $sandbox . '/+Names'); print O join("\n", @gotNames); open(O, '> ' . $sandbox . '/+safeNames'); print O join("\n", @gotSafeNames); for(my $i = 0; $i <= $#gotSafeNames; $i++) { my $name = $gotSafeNames[$i]; open(O, '> ' . $sandbox . '/'. $name); if($#gotFiles == -1) { print O $asnText; # param(text) unlink $sessionDir . '/lastText'; symlink $transactionDir . '/' . $name, $sessionDir . '/lastText'; } else { # Save the uploaded data into specified file print O while <$gotFile>; } } close(O); my $inChDir = makeSessionDirName("/", $session) . $transactionDir; my $options = ''; my $optDebugL = param('optDebugL'); my $optE = param('optE'); my $optEF = param('optEF'); my $optNT = param('optNT'); my $optCN = param('optCN'); my $optMin = param('optMin'); my $optNoXER = param('optNoXER'); $options .= " -Wdebug-lexer" if(defined($optDebugL) && $optDebugL eq "on"); $options .= " -E" if(defined($optE) && $optE eq "on"); $options .= " -EF" if(defined($optEF) && $optEF eq "on"); $options .= " -fnative-types" if(defined($optNT) && $optNT eq "on"); $options .= " -fcompound-names" if(defined($optCN) && $optNT eq "on"); my $CompileASN = "$TMPDIR/bin/asn1c -v | sed -e 's/^/-- /'" . " > $sandbox/+Compiler.Log 2>&1" . "; $SUIDHelper $TMPDIR $inChDir asn1c $options @gotSafeNames " . " >> $sandbox/+Compiler.Log 2>&1" . "; ec=\$?; echo \$ec > $sandbox/+ExitCode" . "; exit \$ec"; my $fType = param('fileType'); $fType = 'auto' unless $fType; # Compile as ASN.1 text if($fType eq 'auto' || $fType eq 'asn1') { my $ec = system($CompileASN); bark("Failed to initiate compilation process: $!") if(!-r $sandbox . '/+ExitCode'); if($ec != (256 * $DataERR)) { makeArchive($TMPDIR, $sandbox) unless $ec; goto REGET; # Issue a clean GET request. } } # Unrecognized ASN.1 module format. # Try out several BER decoders. foreach my $t (sort { $binaryDecoders{$a}{order} <=> $binaryDecoders{$b}{order} } keys %binaryDecoders) { my %dec = %{$binaryDecoders{$t}}; next unless ($fType eq 'auto' or $fType eq $t); next if($fType eq 'auto' and $dec{order} < 0); $options = $dec{cmdopts}; $options .= "-m" if($dec{type} eq 'BER' && $optMin eq "on"); if($dec{type} ne 'BER' && $optNoXER eq "on") { $options =~ s/-x/-p/g; # Old way $options =~ s/-oxer/-otext/g; # New way } my $ec = system("$SUIDHelper $TMPDIR $inChDir $dec{exe} $options @gotSafeNames > $TMPDIR/$inChDir/+UNBER.tmp 2>&1"); next if ($ec != 0 and $t ne $fType and (-s "$TMPDIR/$inChDir/+UNBER.tmp" < 1000)); last unless open(U, "> $TMPDIR/$inChDir/+UNBER"); my $fnames = escapeHTML(join(", ", @gotNames)); print U "\n" . $dec{msg}; open(T, "< $TMPDIR/$inChDir/+UNBER.tmp"); print U while ; close(U); close(T); open(U, "> $TMPDIR/$inChDir/+UNBER.TYPE"); print U $dec{typeExt}; close(U); if($ec) { # Indicate unclean exit. open(U, "> $TMPDIR/$inChDir/+UNBER.EXIT"); print U $ec; close(U); } last; } unlink("$TMPDIR/$inChDir/+UNBER.tmp"); REGET: if($ENV{REQUEST_METHOD} ne 'GET') { print "Status: 303 See Other\n"; print "Location: $myName\n"; } } my $rtt = ''; if(-f $sessionDir . '/lastText') { if(param('resetText')) { unlink $sessionDir . '/lastText'; } else { $rtt = "
[refill with sample ASN.1 module text]"; } } $form = << "EOM";
Pick the ASN.1 module text or binary encoded data file:
  
Or paste the ASN.1 text into the area below:$rtt
These options may be used to control the compiler's behavior:
Debug lexer (-Wdebug-lexer)
Just parse and dump (do not verify) (-E)
Parse, verify validity, and dump (-E -F)
Use native machine types (e.g. double instead of REAL_t) (-fnative-types)
Prevent name clashes in compiled output (-fcompound-names)
... the command line ASN.1 compiler, asn1c, supports many other parameters.
Generate terser output while still preserving BER encoding information (BER decoder specific, -m)
Generate simple text dump instead of XER (no effect on BER decoder)
EOM ; # # Gather previous transactions to generate the history page. # The history page contains a list of several last ASN.1 files # which were uploaded for compilation into the system # by this particular browser (cookie-tracked). # opendir(SD, $sessionDir) or bark("Cannot open sandbox: $!"); my @transactions = sort { $b cmp $a } (grep {/^${safeTimeRE}(-R)?--${safeFilenameRE}?$/} readdir(SD)); my $CountHistoryItems = 0; my $CountGlobalItems = 0; my $CountShownItems = 0; my $fullresp = param("fullresp"); foreach my $trans (sort { $b cmp $a } @transactions) { $CountGlobalItems++; next unless($trans =~ /^($safeTimeRE)--($safeFilenameRE)$/); $CountHistoryItems++; next if($CountHistoryItems > $MaxHistoryItems && $HistoryShow ne 'full'); $CountShownItems++; my ($t, $f) = ($1, $2); my $origTime = $t; $t =~ s/T/ /; # "1999-01-02T13:53:12" => "1999-01-02 13:53:12" # Global transaction number my $tNum = 2 + $#transactions - $CountGlobalItems; # Open the list of file names under which these files are known # at the remote system. open(I, '< ' . $sessionDir . '/' . $trans . '/+Names'); my @Names = ; # Open the list of "safe" file names under which these files # are known to our file system. open(I, '< ' . $sessionDir . '/' . $trans . '/+safeNames'); my @safeNames = ; # Create a list of real file names whith appropriate links to the # "safe" file names for subsequent file fetching. my @markedNames = (); for(my $i = 0; $i <= $#Names; $i++) { local $_ = "" . escapeHTML($Names[$i]) . ""; @markedNames = (@markedNames, $_); } my $ec = ''; open(I, '< ' . $sessionDir . '/' . $trans . '/+ExitCode') and chop($ec = ); my $resCode = "log"; my $resText = "Show compiler log"; if($ec eq "0") { $results = "" . "Compiled OK
\n"; } elsif(open(U, $sessionDir . '/' . $trans . '/+UNBER.TYPE')) { my $type = ; close(U); my $msg; if($ec eq '') { $msg = 'Treating input as ' . $type; } else { $msg = 'This looks like ' . $type; } $results = "$msg
\n"; if(-f $sessionDir . '/' . $trans . '/+UNBER.EXIT') { $results = "" . "$type: " . "Broken encoding
\n"; $ec = 'broken-input'; $resText = "Show $type decoding attempt"; } else { $ec = 0; $resText = "Show $type contents"; } $resCode = "unber"; } else { my $why = $ec; $why = "Broken input file" if $ec == $DataERR; $results = "" . "ASN.1 compiler error: " . "$why
\n"; } $allowFetchResults = $ec eq "0" && (-f $sessionDir . '/' . $trans . '/+Archive.tgz' || -f $sessionDir . '/' . $trans . '/Makefile.am.sample'); $results .= "" . ($allowFetchResults ? '1. ' : '') . "" . "$resText" . ($ec ? ' ←' : '') . ""; $results .= "
\n" . "2. " . "Fetch compiled C sources (.tgz)" if $allowFetchResults; if($ec ne "0") { my ($eml, @resp); open(H, '< ' . $sessionDir . '/' . $trans . '/+HelpResp') and @resp = ; open(H, '< ' . $sessionDir . '/' . $trans . '/+HelpReq') and chomp($eml = ); if($#resp >= 0) { shift(@resp) while($resp[0] =~ /^$/); if($fullresp eq $tNum) { my $r = join("
", @resp); $r =~ s/ / /g; $results .= "

Analysis:"; $results .= "
(Hide full explanation)"; $results .= "

"; $results .= $r; $results .= "
"; $results .= "(Hide full explanation)"; } else { $results .= "

Analysis: $resp[0]
"; $results .= "(Show full explanation)"; } } elsif($eml) { $results .= "

" . "Status: manual help requested
" . " by $eml,
" . "expect results in a few hours.
"; } else { $results .= '

' . "To get free help, leave a return address:
" . "
" . "" . '' ; $atLeastOneError = 1; } } $trColor = ' BGCOLOR=#f8f8f8'; $trColor = ' BGCOLOR=#d0ffe0' if $CountHistoryItems == 1; $history .= "" . "$tNum" . "
[×]" . "" . "" . join(", ", @markedNames) . "" . "

" . $results . "" . "" ; } if($DynamicHistory eq 'yes') { # [Un-]limit number of history items $HistoryItemsHidden = $CountHistoryItems - $CountShownItems; if($HistoryItemsHidden > 0) { # Propose to expand the list. my $item = 'item'; $HistoryItemsHidden == 1 or $item = 'items'; $history .= "" . "" . "Show full history " . "($HistoryItemsHidden hidden $item)" . "\n"; } elsif($HistoryShow eq "full" && $#transactions >= $MaxHistoryItems) { # Propose to shorten the list. my $item = 'item'; $MaxHistoryItems == 1 or $item = 'items'; $history .= "" . "" . "Short history ($MaxHistoryItems $item)" . "\n"; } } if($history) { $history = "

History

" . "
" . "\n" . "" . "\n" . "\n" . $history . "
NFiles processedResult

\n"; if($atLeastOneError) { $history .= "" . "Bottom line: ASN.1 compiler was unable to process some of the input.
" . "This is typically caused by syntax errors in the input files.\n" . "Such errors are normally fixed by removing or adding a couple of characters in the ASN.1 module.
\n" . "
⇒ Please consider clicking on the appropriate "Help me fix it!" button above.
\n" . "An email will be sent to a live person who will fix the ASN.1 module for you. (The typical turn-around time is less than 24 hours.)\n" . "
This is free, and highly advisable.\n" . "
Your request will help us make a better compiler!\n" . "
Thank you." . "
"; } } unless($history) { $history = "" . "[compiled results will appear here]"; $histValign = 'center'; } else { $histValign = 'top'; } $content .= "
\n" . "

ASN.1 Input

\n" . "$form" . "
$history \n" . "
" . "Privacy Note: this page is tailored " . "to your browser. " . "Other users will see their own (different) data. " . "(Read more...)" . "
"; $ua = $ENV{HTTP_USER_AGENT}; $ua =~ s/\\/\\\\/; $ua =~ s/"/\\"/; print LOG "\tUA=\"$ua\""; print LOG "\n"; # Finalize logging record PRINTOUT: print header(-expires=>'-1y'); # If environment has never been set up completely, remove it. if($EnvironmentSetOK != 1 && $TMPDIR ne "/") { system("rm -rf $TMPDIR/ >/dev/null 2>&1"); } print<<"EOM"; Free Online ASN.1 Compiler $redirect $homePath $content $redirect_bottom
The ASN.1 Compiler Copyright © 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>
EOM