+ my $var = lc(shift); $var =~ s/^\$//; $var =~ s/:$//;
+
+ if ($var eq 'message_body' && !defined($self->{_vars}{message_body})) {
+ $self->_parse_body()
+ } elsif ($var =~ s|^([rb]?h)(eader)?_|${1}eader_| &&
+ exists($self->{_vars}{$var}) && !defined($self->{_vars}{$var}))
+ {
+ if ((my $type = $1) eq 'rh') {
+ $self->{_vars}{$var} = join('', @{$self->{_vars_raw}{$var}{vals}});
+ } else {
+ # both bh_ and h_ build their strings from rh_. Do common work here
+ my $rh = $var; $rh =~ s|^b?|r|;
+ my $comma = 1 if ($self->{_vars_raw}{$rh}{type} =~ /^[BCFRST]$/);
+ foreach (@{$self->{_vars_raw}{$rh}{vals}}) {
+ my $x = $_; # editing $_ here would change the original, which is bad
+ $x =~ s|^\s+||;
+ $x =~ s|\s+$||;
+ if ($comma) { chomp($x); $self->{_vars}{$var} .= "$x,\n"; }
+ else { $self->{_vars}{$var} .= $x; }
+ }
+ $self->{_vars}{$var} =~ s|[\s\n]*$||;
+ $self->{_vars}{$var} =~ s|,$|| if ($comma);
+ # ok, that's the preprocessing, not do specific processing for h type
+ if ($type eq 'bh') {
+ $self->{_vars}{$var} = $self->_decode_2047($self->{_vars}{$var});
+ } else {
+ $self->{_vars}{$var} =
+ $self->_decode_2047($self->{_vars}{$var}, $charset);
+ }
+ }
+ }
+ elsif ($var eq 'received_count' && !defined($self->{_vars}{received_count}))
+ {
+ $self->{_vars}{received_count} =
+ scalar(@{$self->{_vars_raw}{rheader_received}{vals}});
+ }
+ elsif ($var eq 'message_headers' && !defined($self->{_vars}{message_headers}))
+ {
+ $self->{_vars}{$var} =
+ $self->_decode_2047($self->{_vars}{message_headers_raw}, $charset);
+ chomp($self->{_vars}{$var});
+ }
+ elsif ($var eq 'reply_address' && !defined($self->{_vars}{reply_address}))
+ {
+ $self->{_vars}{reply_address} = exists($self->{_vars}{"header_reply-to"})
+ ? $self->get_var("header_reply-to") : $self->get_var("header_from");
+ }
+
+ #chomp($self->{_vars}{$var}); # I think this was only for headers, obsolete
+ return $self->{_vars}{$var};
+}
+
+sub _decode_2047 {
+ my $self = shift;
+ my $s = shift; # string to decode
+ my $c = shift; # target charset. If empty, just decode, don't convert
+ my $t = ''; # the translated string
+ my $e = 0; # set to true if we get an error in here anywhere
+
+ return($s) if ($s !~ /=\?/); # don't even bother to look if there's no sign
+
+ my @p = ();
+ foreach my $mw (split(/(=\?[^\?]{3,}\?[BQ]\?[^\?]{1,74}\?=)/i, $s)) {
+ next if ($mw eq '');
+ if ($mw =~ /=\?([^\?]{3,})\?([BQ])\?([^\?]{1,74})\?=/i) {
+ push(@p, { data => $3, encoding => uc($2), charset => uc($1),
+ is_mime => 1 });
+ if ($p[-1]{encoding} eq 'Q') {
+ my @ow = split('', $p[-1]{data});
+ my @nw = ();
+ for (my $i = 0; $i < @ow; $i++) {
+ if ($ow[$i] eq '_') { push(@nw, ' '); }
+ elsif ($ow[$i] eq '=') {
+ if (scalar(@ow) - ($i+1) < 2) { # ran out of characters
+ $e = 1; last;
+ } elsif ($ow[$i+1] !~ /[\dA-F]/i || $ow[$i+2] !~ /[\dA-F]/i) {
+ $e = 1; last;
+ } else {
+ #push(@nw, chr('0x'.$ow[$i+1].$ow[$i+2]));
+ push(@nw, pack("C", hex($ow[$i+1].$ow[$i+2])));
+ $i += 2;
+ }
+ }
+ elsif ($ow[$i] =~ /\s/) { # whitspace is illegal
+ $e = 1;
+ last;
+ }
+ else { push(@nw, $ow[$i]); }
+ }
+ $p[-1]{data} = join('', @nw);
+ } elsif ($p[-1]{encoding} eq 'B') {
+ my $x = $p[-1]{data};
+ $x =~ tr#A-Za-z0-9+/##cd;
+ $x =~ s|=+$||;
+ $x =~ tr#A-Za-z0-9+/# -_#;
+ my $r = '';
+ while ($x =~ s/(.{1,60})//s) {
+ $r .= unpack("u", chr(32 + int(length($1)*3/4)) . $1);
+ }
+ $p[-1]{data} = $r;
+ }
+ } else {
+ push(@p, { data => $mw, is_mime => 0,
+ is_ws => ($mw =~ m|^[\s\n]+|sm) ? 1 : 0 });
+ }
+ }