X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FDashboard%2FMailer.pm;h=fd89c88da8e97123c86ddc5c88cae701f0b600f9;hb=44dd00a3ff974a17999e86e64488e996edc71e3c;hp=9d28c4942d0059b509cc9f4a46211d171d696a21;hpb=7588a4ac90a9b07c08a3107cd1107d773be1c991;p=freeside.git diff --git a/rt/lib/RT/Dashboard/Mailer.pm b/rt/lib/RT/Dashboard/Mailer.pm index 9d28c4942..fd89c88da 100644 --- a/rt/lib/RT/Dashboard/Mailer.pm +++ b/rt/lib/RT/Dashboard/Mailer.pm @@ -2,7 +2,7 @@ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC # # # (Except where explicitly superseded by other copyright notices) @@ -60,6 +60,7 @@ use RT::Interface::Web::Handler; use RT::Interface::Web; use File::Temp 'tempdir'; use HTML::Scrubber; +use URI::QueryParam; sub MailDashboards { my $self = shift; @@ -146,7 +147,7 @@ sub IsSubscriptionReady { my $sub_hour = $subscription->SubValue('Hour'); my $sub_dow = $subscription->SubValue('Dow'); my $sub_dom = $subscription->SubValue('Dom'); - my $sub_fow = $subscription->SubValue('Fow'); + my $sub_fow = $subscription->SubValue('Fow') || 1; my ($hour, $dow, $dom) = @{ $args{LocalTime} }; @@ -165,8 +166,6 @@ sub IsSubscriptionReady { return 0 if $sub_dow ne $dow; # does it match the "every N weeks" clause? - $sub_fow = 1 if !$sub_fow; - return 1 if $counter % $sub_fow == 0; $subscription->SetSubValues(Counter => $counter + 1) @@ -351,6 +350,7 @@ sub EmailDashboard { $RT::Logger->debug('Mailing dashboard "'.$dashboard->Name.'" to user '.$currentuser->Name." <$email>"); my $ok = RT::Interface::Email::SendEmail( + %{ RT->Config->Get('Crypt')->{'Dashboards'} || {} }, Entity => $entity, ); @@ -381,12 +381,19 @@ sub BuildEmail { # already attached this object return "cid:$cid_of{$uri}" if $cid_of{$uri}; - $cid_of{$uri} = time() . $$ . int(rand(1e6)); my ($data, $filename, $mimetype, $encoding) = GetResource($uri); + return $uri unless defined $data; + + $cid_of{$uri} = time() . $$ . int(rand(1e6)); - # downgrade non-text strings, because all strings are utf8 by - # default, which is wrong for non-text strings. - if ( $mimetype !~ m{text/} ) { + # Encode textual data in UTF-8, and downgrade (treat + # codepoints as codepoints, and ensure the UTF-8 flag is + # off) everything else. + my @extra; + if ( $mimetype =~ m{text/} ) { + $data = Encode::encode( "UTF-8", $data ); + @extra = ( Charset => "UTF-8" ); + } else { utf8::downgrade( $data, 1 ) or $RT::Logger->warning("downgrade $data failed"); } @@ -398,6 +405,7 @@ sub BuildEmail { Disposition => 'inline', Name => RT::Interface::Email::EncodeToMIME( String => $filename ), 'Content-Id' => $cid_of{$uri}, + @extra, ); return "cid:$cid_of{$uri}"; @@ -405,29 +413,32 @@ sub BuildEmail { inline_css => sub { my $uri = shift; my ($content) = GetResource($uri); - return $content; + return defined $content ? $content : ""; }, inline_imports => 1, ); my $entity = MIME::Entity->build( - From => Encode::encode_utf8($args{From}), - To => Encode::encode_utf8($args{To}), + From => Encode::encode("UTF-8", $args{From}), + To => Encode::encode("UTF-8", $args{To}), Subject => RT::Interface::Email::EncodeToMIME( String => $args{Subject} ), Type => "multipart/mixed", ); $entity->attach( - Data => Encode::encode_utf8($content), Type => 'text/html', Charset => 'UTF-8', + Data => Encode::encode("UTF-8", $content), Disposition => 'inline', + Encoding => "base64", ); for my $part (@parts) { $entity->add_part($part); } + $entity->make_singlepart; + return $entity; } @@ -450,7 +461,7 @@ sub BuildEmail { autohandler_name => '', # disable forced login and more data_dir => $data_dir, ); - $mason->set_escape( h => \&RT::Interface::Web::EscapeUTF8 ); + $mason->set_escape( h => \&RT::Interface::Web::EscapeHTML ); $mason->set_escape( u => \&RT::Interface::Web::EscapeURI ); $mason->set_escape( j => \&RT::Interface::Web::EscapeJS ); } @@ -523,7 +534,13 @@ sub BuildEmail { sub GetResource { my $uri = URI->new(shift); - my ($content, $filename, $mimetype, $encoding); + my ($content, $content_type, $filename, $mimetype, $encoding); + + # Avoid trying to inline any remote URIs. We absolutified all URIs + # using WebURL in SendDashboard() above, so choose the simpler match on + # that rather than testing a bunch of URI accessors. + my $WebURL = RT->Config->Get("WebURL"); + return unless $uri =~ /^\Q$WebURL/; $RT::Logger->debug("Getting resource $uri"); @@ -536,40 +553,35 @@ sub GetResource { $path = "/$path" unless $path =~ m{^/}; - $HTML::Mason::Commands::r->path_info($path); - - # grab the query arguments - my %args; - for (split /&/, ($uri->query||'')) { - my ($k, $v) = /^(.*?)=(.*)$/ - or die "Unable to parse query parameter '$_'"; - - for ($k, $v) { s/%(..)/chr hex $1/ge } - - # no value yet, simple key=value - if (!exists $args{$k}) { - $args{$k} = $v; - } - # already have key=value, need to upgrade it to key=[value1, value2] - elsif (!ref($args{$k})) { - $args{$k} = [$args{$k}, $v]; - } - # already key=[value1, value2], just add the new value - else { - push @{ $args{$k} }, $v; - } + # Try the static handler first for non-Mason CSS, JS, etc. + my $res = RT::Interface::Web::Handler->GetStatic($path); + if ($res->is_success) { + RT->Logger->debug("Fetched '$path' from the static handler"); + $content = $res->decoded_content; + $content_type = $res->headers->content_type; + } else { + # Try it through Mason instead... + $HTML::Mason::Commands::r->path_info($path); + + # grab the query arguments + my %args = map { $_ => [ map {Encode::decode("UTF-8",$_)} + $uri->query_param($_) ] } $uri->query_param; + # Convert empty and single element arrayrefs to a non-ref scalar + @$_ < 2 and $_ = $_->[0] + for values %args; + + $RT::Logger->debug("Running component '$path'"); + $content = RunComponent($path, %args); + + $content_type = $HTML::Mason::Commands::r->content_type; } - $RT::Logger->debug("Running component '$path'"); - $content = RunComponent($path, %args); - # guess at the filename from the component name $filename = $1 if $path =~ m{^.*/(.*?)$}; # the rest of this was taken from Email::MIME::CreateHTML::Resolver::LWP ($mimetype, $encoding) = MIME::Types::by_suffix($filename); - my $content_type = $HTML::Mason::Commands::r->content_type; if ($content_type) { $mimetype = $content_type;