#!/usr/local/bin/perl # qp -- "Quoted printable" decoder/encoder # Brian Katzung 9 February 1996 # # This software is provided on a strictly as-is basis. # Use it at your own risk. # # Options: # -d Decode (default) # -e Encode # -l Quote line breaks (\r, \n) # -m Quote mail constructs (., From ) # -t Quote tabs (\t) # -u Quote unsafe (most punctuation, etc.) $True = 1; $False = 0; ###################################################################### # Decode printed-quotable input sub Decode { local(@Parts); while (<>) { s/[ \t]+(\r?\n)/\1/; # Strip trailing white space s/=\r?\n//; # Strip soft line breaks # Split the line at quoted characters # (s/pattern/expression/eg leaks in Perl 4) @Parts = split(/(=[0-9A-F][0-9A-F])/); for (@Parts) { # Decode quoted characters $_ = pack('c', hex($1)) if /^=([0-9A-F][0-9A-F])$/; } # All the King's horses and all the King's men... print join('', @Parts); } } ###################################################################### # Encode input as quoted-printable sub Encode { local(@Parts); local($Term); # Part of soft line breaks when real breaks are encoded $Term = "\n" if $QuoteBreaks == $True; while (<>) { # Split the line into text and termination ($_, $Term) = /([^\r\n]*)([\r\n]*)/ unless $QuoteBreaks == $True; # Quote "unsafe" characters # (avoid Perl 4 s///eg leak as above) if ($QuoteUnsafe == $True) { @Parts = split(/([^ A-Za-z0-9'()+,-.\/:?])/); } else { @Parts = split(/([^ -<>-~])/); } for (@Parts) { if ($QuoteUnsafe == $True? ($_ =~ /[^ A-Za-z0-9'()+,-.\/:?]/): ($_ =~ /[^ -<>-~]/)) { $_ = sprintf("=%02X", ord()) unless $_ eq "\t" && $QuoteTabs == $False; } } $_ = join('', @Parts); # Quote a trailing blank or tab to avoid losing them # at gateways s/\t$/=09/; s/ $/=20/; # Quote things that sometimes trouble mail, if requested if ($QuoteMail == $True) { s/^From /=46rom /; s/^\.((=0A|=0D)*)$/=2E\1/; } # Real line breaks are encoded, so add a soft line break $_ .= '=' if $QuoteBreaks == $True; # Output the line in pieces no longer than 76 characters while (length() > 76) { # Grab 73 to 75 characters such that neither of # the last two contain the start of an encoded # character, and append a soft line break /^(.{71,73}[^=][^=])(.*)/; print "$1=\n"; # Try again with the remainder of the line $_ = $2; } print "$_$Term"; } } ###################################################################### # Main program $Mode = 'decode'; $QuoteBreaks = $False; $QuoteMail = $False; $QuoteTabs = $False; $QuoteUnsafe = $False; while ($ARGV[0] =~ /^-/) { $Arg = shift; last if $Arg eq '--'; $Mode = 'decode' if $Arg =~ /d/; $Mode = 'encode' if $Arg =~ /e/; $QuoteBreaks = $True if $Arg =~ /l/; # Quote \r and \n $QuoteMail = $True if $Arg =~ /m/; # Quote "^From " and "^.$" $QuoteTabs = $True if $Arg =~ /t/; # Quote \t $QuoteUnsafe = $True if $Arg =~ /u/; # Quote most punctuation, etc. } if ($Mode eq 'encode') { &Encode; } else { &Decode; }