#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2017 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
use RT::Interface::Web;
use File::Temp 'tempdir';
use HTML::Scrubber;
+use URI::QueryParam;
sub MailDashboards {
my $self = shift;
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} };
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)
$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,
);
# 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");
}
Disposition => 'inline',
Name => RT::Interface::Email::EncodeToMIME( String => $filename ),
'Content-Id' => $cid_of{$uri},
+ @extra,
);
return "cid:$cid_of{$uri}";
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;
}
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 );
}
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");
$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;