[Rt-commit] r17862 - in rt/3.999/branches/merge_to_3.8.2: . bin etc lib/RT lib/RT/Crypt lib/RT/Graph lib/RT/Interface
sunnavy at bestpractical.com
sunnavy at bestpractical.com
Wed Jan 21 10:01:31 EST 2009
Author: sunnavy
Date: Wed Jan 21 10:01:29 2009
New Revision: 17862
Modified:
rt/3.999/branches/merge_to_3.8.2/README
rt/3.999/branches/merge_to_3.8.2/bin/rt
rt/3.999/branches/merge_to_3.8.2/etc/initialdata
rt/3.999/branches/merge_to_3.8.2/lib/RT/Action/Install.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/Crypt/GnuPG.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/Dashboard.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/Date.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/EmailParser.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/Graph/Tickets.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/REST.pm
rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/Web.pm
Log:
redo the merge thing between 17847@ and 17859@ in the branch
Modified: rt/3.999/branches/merge_to_3.8.2/README
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/README (original)
+++ rt/3.999/branches/merge_to_3.8.2/README Wed Jan 21 10:01:29 2009
@@ -21,8 +21,7 @@
o Perl 5.8.3 or later (http://www.perl.com).
Perl versions prior to 5.8.3 contain bugs that could result
- in data corruption. We recommend strongly that you use 5.8.3
- or newer.
+ in data corruption. RT won't start on older versions.
o A supported SQL database
@@ -33,12 +32,8 @@
o Apache version 1.3.x or 2.x (http://httpd.apache.org)
with mod_perl -- (http://perl.apache.org )
- or a webserver with FastCGI support (www.fastcgi.com)
-
- Compiling mod_perl on Apache 1.3.x as a DSO has been known
- to have massive stability problems and is not recommended.
-
- mod_perl 1.x must be built with EVERYTHING=1
+ or with FastCGI -- (www.fastcgi.com)
+ or other webserver with FastCGI support
RT's FastCGI handler needs to access RT's configuration file.
@@ -77,6 +72,11 @@
default install directory in /opt/rt3 does not work under SELinux's
default configuration.
+ If you're upgrading RT then it worth to read UPGRADING document at this
+ moment. Some extension you're using may have been integrated into
+ core. It's recommended to use new clean directory when you're
+ upgrading to new major release (for example from 3.6.x to 3.8.x).
+
3 Make sure that RT has everything it needs to run.
Check for missing dependencies by running:
@@ -121,8 +121,9 @@
7 If you're upgrading from RT 3.0 or newer:
- Read through the UPGRADING document included in this distribution.
-
+ Read through the UPGRADING document included in this distribution. If
+ you're using MySQL, read through UPGRADING.mysql as well.
+
It includes special upgrade instructions that will help you get this
new version of RT up and running smoothly.
@@ -138,19 +139,16 @@
You'll need to add any new values you need to change from the defaults
in etc/RT_Config.pm
- You may also need to update RT's database. To find out, type:
+ You may also need to update RT's database. You can do this with
+ the rt-setup-database tool. Replace root with the name of the dba
+ user on your database (root is the default for MySQL).
- ls etc/upgrade
+ You will be prompted for your previous version of RT (such as 3.6.4)
+ so that we can calculate which database updates to apply
- For each item in that directory whose name is greater than
- your previously installed RT version, run:
+ You should back up your database before running this command.
- /opt/rt3/sbin/rt-setup-database --action schema \
- --datadir etc/upgrade/<version>
- /opt/rt3/sbin/rt-setup-database --action acl \
- --datadir etc/upgrade/<version>
- /opt/rt3/sbin/rt-setup-database --action insert \
- --datadir etc/upgrade/<version>
+ /opt/rt3/sbin/rt-setup-database --dba root --prompt-for-dba-password --action upgrade
Clear mason cache dir:
@@ -161,8 +159,9 @@
8 If you're upgrading from RT 2.0:
- Please upgrade from RT 2.0 to RT 3.2 and then follow the instructions
- for section 7.
+ Use the RT::Extension::RT2toRT3 module to upgrade to the current RT
+ release. You can download it from CPAN here:
+ http://search.cpan.org/dist/RT-Extension-RT2toRT3/
9 Configure the email and web gateways, as described below.
Modified: rt/3.999/branches/merge_to_3.8.2/bin/rt
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/bin/rt (original)
+++ rt/3.999/branches/merge_to_3.8.2/bin/rt Wed Jan 21 10:01:29 2009
@@ -60,6 +60,17 @@
use HTTP::Request::Common;
use HTTP::Headers;
use Term::ReadLine;
+use Time::Local; # used in prettyshow
+
+# strong (GSSAPI based) authentication is supported if the server does provide
+# it and the perl modules GSSAPI and LWP::Authen::Negotiate are installed
+# it can be suppressed by setting externalauth=0 (default is undef)
+eval { require GSSAPI };
+my $no_strong_auth = 'missing perl module GSSAPI';
+if ( ! $@ ) {
+ eval {require LWP::Authen::Negotiate};
+ $no_strong_auth = $@ ? 'missing perl module LWP::Authen::Negotiate' : 0;
+}
# We derive configuration information from hardwired defaults, dotfiles,
# and the RT* environment variables (in increasing order of precedence).
@@ -75,15 +86,23 @@
user => eval{(getpwuid($<))[0]} || $ENV{USER} || $ENV{USERNAME},
passwd => undef,
server => 'http://localhost/',
- query => undef,
- orderby => undef,
- externalauth => undef,
+ query => "Status!='resolved' and Status!='rejected'",
+ order_by => 'id',
+ queue => undef,
+# to protect against unlimited searches a better choice would be
+# queue => 'Unknown_Queue',
+# setting externalauth => undef will try GSSAPI auth if the corresponding perl
+# modules are installed, externalauth => 0 is the backward compatible choice
+ externalauth => 0,
+
),
config_from_file($ENV{RTCONFIG} || ".rtrc"),
config_from_env()
);
my $session = new Session("$HOME/.rt_sessions");
my $REST = "$config{server}/REST/1.0";
+$no_strong_auth = 'switched off by externalauth=0'
+ if defined $config{externalauth};
my $prompt = 'rt> ';
@@ -122,6 +141,8 @@
grant => ["grant", "revoke"],
take => ["take", "steal", "untake"],
quit => ["quit", "exit"],
+ setcommand => ["del", "delete", "give", "res", "resolve",
+ "subject"],
);
my %actions;
@@ -243,6 +264,9 @@
$data{order_by} = $config{order_by};
}
my $bad = 0;
+ my $rawprint = 0;
+ my $reverse_sort = 0;
+ my $queue = $config{queue};
while (@ARGV) {
$_ = shift @ARGV;
@@ -258,6 +282,13 @@
}
elsif (/^-([isl])$/) {
$data{format} = $1;
+ $rawprint = 1;
+ }
+ elsif (/^-q$/) {
+ $queue = shift @ARGV;
+ }
+ elsif (/^-r$/) {
+ $reverse_sort = 1;
}
elsif (/^-f$/) {
if ($ARGV[0] !~ /^(?:(?:$field,)*$field)$/) {
@@ -265,6 +296,8 @@
$bad = 1; last;
}
$data{fields} = shift @ARGV;
+ $data{format} = 's' if ! $data{format};
+ $rawprint = 1;
}
elsif (!defined $q && !/^-/) {
$q = $_;
@@ -275,10 +308,35 @@
$bad = 1; last;
}
}
+ if ( ! $rawprint and ! exists $data{format} ) {
+ $data{format} = 'l';
+ }
+ if ( $reverse_sort and $data{order_by} =~ /^-/ ) {
+ $data{order_by} =~ s/^-/+/;
+ } elsif ($reverse_sort) {
+ $data{order_by} =~ s/^\+?(.*)/-$1/;
+ }
+
if (!defined $q) {
$q = $config{query};
}
+ $q =~ s/^#//; # get rid of leading hash
+ if ($q =~ /^\d+$/) {
+ # only digits, must be an id, formulate a correct query
+ $q = "id=$q" if $q =~ /^\d+$/;
+ } else {
+ # a string only, take it as an owner or requestor (quoting done later)
+ $q = "(Owner=$q or Requestor like $q) and $config{query}"
+ if $q =~ /^[\w\-]+$/;
+ # always add a query for a specific queue or (comma separated) queues
+ $queue =~ s/,/ or Queue=/g if $queue;
+ $q .= " and (Queue=$queue)" if $queue and $q and $q !~ /Queue\s*=/i
+ and $q !~ /id\s*=/i;
+ }
+ # correctly quote strings in a query
+ $q =~ s/(=|like\s)\s*([^'\d\s]\S*)\b/$1\'$2\'/g;
+
$type ||= "ticket";
unless ($type && defined $q) {
my $item = $type ? "query string" : "object type";
@@ -288,8 +346,14 @@
#return help("list", $type) if $bad;
return suggest_help("list", $type) if $bad;
+ print "Query:$q\n" if ! $rawprint;
my $r = submit("$REST/search/$type", { query => $q, %data });
- print $r->content;
+ if ( $rawprint ) {
+ print $r->content;
+ } else {
+ my $forms = Form::parse($r->content);
+ prettylist ($forms);
+ }
}
# Displays selected information about a single object.
@@ -298,10 +362,12 @@
my ($type, @objects, %data);
my $slurped = 0;
my $bad = 0;
+ my $rawprint = 0;
+ my $histspec;
while (@ARGV) {
$_ = shift @ARGV;
-
+ s/^#// if /^#\d+/; # get rid of leading hash
if (/^-t$/) {
$bad = 1, last unless defined($type = get_type_argument());
}
@@ -310,6 +376,7 @@
}
elsif (/^-([isl])$/) {
$data{format} = $1;
+ $rawprint = 1;
}
elsif (/^-$/ && !$slurped) {
chomp(my @lines = <STDIN>);
@@ -328,9 +395,21 @@
$bad = 1; last;
}
$data{fields} = shift @ARGV;
+ # option f requires short raw listing format
+ $data{format} = 's';
+ $rawprint = 1;
+ }
+ elsif (/^\d+$/ and my $spc2 = is_object_spec("ticket/$_", $type)) {
+ push @objects, $spc2;
+ $histspec = is_object_spec("ticket/$_/history", $type);
+ }
+ elsif (/^\d+\// and my $spc3 = is_object_spec("ticket/$_", $type)) {
+ push @objects, $spc3;
+ $rawprint = 1 if $_ =~ /\/content$/;
}
elsif (my $spec = is_object_spec($_, $type)) {
push @objects, $spec;
+ $rawprint = 1 if $_ =~ /\/content$/ or $_ !~ /^ticket/;
}
else {
my $datum = /^-/ ? "option" : "argument";
@@ -338,6 +417,10 @@
$bad = 1; last;
}
}
+ if ( ! $rawprint ) {
+ push @objects, $histspec if $histspec;
+ $data{format} = 'l' if ! exists $data{format};
+ }
unless (@objects) {
whine "No objects specified.";
@@ -353,8 +436,16 @@
# show ticket/id/attachments/id/content > foo.tar.gz
if ($r->content_type !~ /^text\//) {
chomp($c);
+ $rawprint = 1;
+ }
+ if ( $rawprint ) {
+ print $c;
+ } else {
+ # I do not know how to get more than one form correctly returned
+ $c =~ s!^RT/[\d\.]+ 200 Ok$!--!mg;
+ my $forms = Form::parse($c);
+ prettyshow ($forms);
}
- print $c;
}
# To create a new Object, we ask the server for a form with the defaults
@@ -376,6 +467,7 @@
while (@ARGV) {
$_ = shift @ARGV;
+ s/^#// if /^#\d+/; # get rid of leading hash
if (/^-e$/) { $edit = 1 }
elsif (/^-i$/) { $input = 1 }
@@ -431,6 +523,9 @@
}
$cl = $vars;
}
+ elsif (/^\d+$/ and my $spc2 = is_object_spec("ticket/$_", $type)) {
+ push @objects, $spc2;
+ }
elsif (my $spec = is_object_spec($_, $type)) {
push @objects, $spec;
}
@@ -576,6 +671,54 @@
}
}
+# handler for special edit commands. A valid edit command is constructed and
+# further work is delegated to the edit handler
+
+sub setcommand {
+ my ($action) = @_;
+ my ($id, $bad, $what);
+ if ( @ARGV ) {
+ $_ = shift @ARGV;
+ $id = $1 if (m|^(?:ticket/)?($idlist)$|);
+ }
+ if ( ! $id ) {
+ $bad = 1;
+ whine "No ticket number specified.";
+ }
+ if ( @ARGV ) {
+ if ($action eq 'subject') {
+ my $subject = '"'.join (" ", @ARGV).'"';
+ @ARGV = ();
+ $what = "subject=$subject";
+ } elsif ($action eq 'give') {
+ my $owner = shift @ARGV;
+ $what = "owner=$owner";
+ }
+ } else {
+ if ( $action eq 'delete' or $action eq 'del' ) {
+ $what = "status=deleted";
+ } elsif ($action eq 'resolve' or $action eq 'res' ) {
+ $what = "status=resolved";
+ } elsif ($action eq 'take' ) {
+ $what = "owner=$config{user}";
+ } elsif ($action eq 'untake') {
+ $what = "owner=Nobody";
+ }
+ }
+ if (@ARGV) {
+ $bad = 1;
+ whine "Extraneous arguments for action $action: @ARGV.";
+ }
+ if ( ! $what ) {
+ $bad = 1;
+ whine "unrecognized action $action.";
+ }
+ return help("edit") if $bad;
+ @ARGV = ( $id, "set", $what );
+ print "Executing: rt edit @ARGV\n";
+ return edit("edit");
+}
+
# We roll "comment" and "correspond" into the same handler.
sub comment {
@@ -696,6 +839,7 @@
while (@ARGV) {
$_ = shift @ARGV;
+ s/^#// if /^#\d+/; # get rid of leading hash
if (/^\d+$/) {
push @id, $_;
@@ -854,12 +998,23 @@
$data = $content;
}
-
+ # Should we send authentication information to start a new session?
+ my $how = $config{server} =~ /^https/ ? 'over SSL' : 'unencrypted';
+ (my $server = $config{server}) =~ s/^.*\/\/([^\/]+)\/?/$1/;
if ($config{externalauth}) {
$h->authorization_basic($config{user}, $config{passwd} || read_passwd() );
- } elsif (!defined $session->cookie) {
- push @$data, ( user => $config{user} );
- push @$data, ( pass => $config{passwd} || read_passwd() );
+ print " Password will be sent to $server $how\n",
+ " Press CTRL-C now if you do not want to continue\n"
+ if ! $config{passwd};
+ } elsif ( $no_strong_auth ) {
+ if (!defined $session->cookie) {
+ print " Strong encryption not available, $no_strong_auth\n",
+ " Password will be sent to $server $how\n",
+ " Press CTRL-C now if you do not want to continue\n"
+ if ! $config{passwd};
+ push @$data, ( user => $config{user} );
+ push @$data, ( pass => $config{passwd} || read_passwd() );
+ }
}
# Now, we construct the request.
@@ -1058,7 +1213,7 @@
sub Form::parse {
my $state = 0;
my @forms = ();
- my @lines = split /\n/, $_[0];
+ my @lines = split /\n/, $_[0] if $_[0];
my ($c, $o, $k, $e) = ("", [], {}, "");
LINE:
@@ -1214,7 +1369,8 @@
sub config_from_env {
my %env;
- foreach my $k ("DEBUG", "USER", "PASSWD", "SERVER", "QUERY", "order_by") {
+ foreach my $k (qw(EXTERNALAUTH DEBUG USER PASSWD SERVER QUERY order_by)) {
+
if (exists $ENV{"RT$k"}) {
$env{lc $k} = $ENV{"RT$k"};
}
@@ -1266,7 +1422,8 @@
chomp;
next if (/^#/ || /^\s*$/);
- if (/^(externalauth|user|passwd|server|query|orderby)\s+(.*)\s?$/) {
+ if (/^(externalauth|user|passwd|server|query|order_by|queue)\s+(.*)\s?$/) {
+
$cfg{$1} = $2;
}
else {
@@ -1431,6 +1588,121 @@
print STDERR "rt: For help, run 'rt help $type'.\n" if defined $type;
}
+sub str2time {
+ # simplified procedure for parsing date, avoid loading Date::Parse
+ my %month = (Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5,
+ Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11);
+ $_ = shift;
+ my ($mon, $day, $hr, $min, $sec, $yr, $monstr);
+ if ( /(\w{3})\s+(\d\d?)\s+(\d\d):(\d\d):(\d\d)\s+(\d{4})/ ) {
+ ($monstr, $day, $hr, $min, $sec, $yr) = ($1, $2, $3, $4, $5, $6);
+ $mon = $month{$monstr} if exists $month{$monstr};
+ } elsif ( /(\d{4})-(\d\d)-(\d\d)\s+(\d\d):(\d\d):(\d\d)/ ) {
+ ($yr, $mon, $day, $hr, $min, $sec) = ($1, $2, $3, $4, $5, $6);
+ }
+ if ( $yr and defined $mon and $day and defined $hr and defined $sec ) {
+ return timelocal($sec,$min,$hr,$day,$mon,$yr);
+ } else {
+ print "Unknown date format in parsedate: $_\n";
+ return undef;
+ }
+}
+
+sub date_diff {
+ my ($old, $new) = @_;
+ $new = time() if ! $new;
+ $old = str2time($old) if $old !~ /^\d+$/;
+ $new = str2time($new) if $new !~ /^\d+$/;
+ return "???" if ! $old or ! $new;
+
+ my %seconds = (min => 60,
+ hr => 60*60,
+ day => 60*60*24,
+ wk => 60*60*24*7,
+ mth => 60*60*24*30,
+ yr => 60*60*24*365);
+
+ my $diff = $new - $old;
+ my $what = 'sec';
+ my $howmuch = $diff;
+ for ( sort {$seconds{$a} <=> $seconds{$b}} keys %seconds) {
+ last if $diff < $seconds{$_};
+ $what = $_;
+ $howmuch = int($diff/$seconds{$_});
+ }
+ return "$howmuch $what";
+}
+
+sub prettyshow {
+ my $forms = shift;
+ my ($form) = grep { exists $_->[2]->{Queue} } @$forms;
+ my $k = $form->[2];
+ # dates are in local time zone
+ if ( $k ) {
+ print "Date: $k->{Created}\n";
+ print "From: $k->{requestors}\n";
+ print "Cc: $k->{cc}\n" if $k->{cc};
+ print "X-AdminCc: $k->{AdminCc}\n" if $k->{AdminCc};
+ print "X-Queue: $k->{Queue}\n";
+ print "Subject: [rt #$k->{id}] $k->{Subject}\n\n";
+ }
+ # dates in these attributes are in GMT and will be converted
+ foreach my $form (@$forms) {
+ my ($c, $o, $k, $e) = @$form;
+ next if ! $k->{id} or exists $k->{Queue};
+ if ( exists $k->{Created} ) {
+ my ($y,$m,$d,$hh,$mm,$ss) = ($k->{Created} =~ /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/);
+ $m--;
+ my $created = localtime(timegm($ss,$mm,$hh,$d,$m,$y));
+ if ( exists $k->{Description} ) {
+ print "===> $k->{Description} on $created\n";
+ }
+ }
+ print "$k->{Content}\n" if exists $k->{Content} and
+ $k->{Content} !~ /to have no content$/ and
+ $k->{type} ne 'EmailRecord';
+ print "$k->{Attachments}\n" if exists $k->{Attachments} and
+ $k->{Attachments};
+ }
+}
+
+sub prettylist {
+ my $forms = shift;
+ my $heading = "Ticket Owner queue Age Told Status Requestor Subject\n";
+ $heading .= '-' x 80 . "\n";
+ my (@open, @me);
+ foreach my $form (@$forms) {
+ my ($c, $o, $k, $e) = @$form;
+ next if ! $k->{id};
+ print $heading if $heading;
+ $heading = '';
+ my $id = $k->{id};
+ $id =~ s!^ticket/!!;
+ my $owner = $k->{Owner} eq 'Nobody' ? '' : $k->{Owner};
+ $owner = substr($owner, 0, 5);
+ my $queue = substr($k->{Queue}, 0, 5);
+ my $subject = substr($k->{Subject}, 0, 30);
+ my $age = date_diff($k->{Created});
+ my $told = $k->{Told} eq 'Not set' ? '' : date_diff($k->{Told});
+ my $status = substr($k->{Status}, 0, 6);
+ my $requestor = substr($k->{requestors}, 0, 9);
+ my $line = sprintf "%6s %5s %5s %6s %6s %-6s %-9s %-30s\n",
+ $id, $owner, $queue, $age, $told, $status, $requestor, $subject;
+ if ( $k->{Owner} eq 'Nobody' ) {
+ push @open, $line;
+ } elsif ($k->{Owner} eq $config{user} ) {
+ push @me, $line;
+ } else {
+ print $line;
+ }
+ }
+ print "No matches found\n" if $heading;
+ printf "========== my %2d open tickets ==========\n", scalar @me if @me;
+ print @me if @me;
+ printf "========== %2d unowned tickets ==========\n", scalar @open if @open;
+ print @open if @open;
+}
+
__DATA__
Title: intro
@@ -1526,9 +1798,24 @@
- passwd <passwd> RT user's password.
- query <RT Query> Default RT Query for list action
- order_by <order> Default RT order for list action
+ - queue <queuename> default RT queue for list action
+ - externalauth <0|1> Use HTTP Basic authentication
+ explicitely setting externalauth to 0 inhibits also GSSAPI based
+ authentication, if LWP::Authen::Negotiate (and GSSAPI) is installed
+
Blank and #-commented lines are ignored.
+ Sample configuration file contents:
+
+ server https://rt.somewhere.com/
+ # more than one queue can be given (by adding a query expression)
+ queue helpdesk or queue=support
+ query Status != resolved and Owner=myaccount
+
+
+
+
Environment variables:
The following environment variables override any corresponding
@@ -1536,6 +1823,7 @@
- RTUSER
- RTPASSWD
+ - RTEXTERNALAUTH
- RTSERVER
- RTDEBUG Numeric debug level. (Set to 3 for full logs.)
- RTCONFIG Specifies a name other than ".rtrc" for the
@@ -1567,8 +1855,12 @@
"user/root,1-3,5,7-10,ams" is a list of ten users; the same list
can also be written as "user/ams,root,1,2,3,5,7,8-10".
+ If just a number is given as object specification it will be
+ interpreted as ticket/<number>
+
Examples:
+ 1 # the same as ticket/1
ticket/1
ticket/1/attachments
ticket/1/attachments/3
@@ -1606,6 +1898,22 @@
- rt help <action> (action-specific details)
- rt help types (a list of possible types)
+ The following actions on tickets are also possible:
+
+ - comment Add comments to a ticket
+ - correspond Add comments to a ticket
+ - merge Merge one ticket into another
+ - link Link one ticket to another
+ - take Take a ticket (steal and untake are possible as well)
+
+ For several edit set subcommands that are frequently used abbreviations
+ have been introduced. These abbreviations are:
+
+ - delete or del delete a ticket (edit set status=deleted)
+ - resolve or res resolve a ticket (edit set status=resolved)
+ - subject change subject of ticket (edit set subject=string)
+ - give give a ticket to somebody (edit set owner=user)
+
--
Title: types
@@ -1644,6 +1952,13 @@
- merge
- comment
- correspond
+ - take
+ - steal
+ - untake
+ - give
+ - resolve
+ - delete
+ - subject
Attributes:
@@ -1702,6 +2017,83 @@
--
+Title: subject
+Text:
+
+ Syntax:
+
+ rt subject <id> <new subject text>
+
+ Change the subject of a ticket whose ticket id is given.
+
+--
+
+Title: give
+Text:
+
+ Syntax:
+
+ rt give <id> <accountname>
+
+ Give a ticket whose ticket id is given to another user.
+
+--
+
+Title: steal
+Text:
+
+ rt steal <id>
+
+ Steal a ticket whose ticket id is given, i.e. set the owner to myself.
+
+--
+
+Title: take
+Text:
+
+ Syntax:
+
+ rt take <id>
+
+ Take a ticket whose ticket id is given, i.e. set the owner to myself.
+
+--
+
+Title: untake
+Text:
+
+ Syntax:
+
+ rt untake <id>
+
+ Untake a ticket whose ticket id is given, i.e. set the owner to Nobody.
+
+--
+
+Title: resolve
+Title: res
+Text:
+
+ Syntax:
+
+ rt resolve <id>
+
+ Resolves a ticket whose ticket id is given.
+
+--
+
+Title: delete
+Title: del
+Text:
+
+ Syntax:
+
+ rt delete <id>
+
+ Deletes a ticket whose ticket id is given.
+
+--
+
Title: logout
Text:
@@ -1740,25 +2132,31 @@
The following options control how much information is displayed
about each matching object:
- -i Numeric IDs only. (Useful for |rt edit -; see examples.)
- -s Short description.
- -l Longer description.
-
- In addition,
+ -i Numeric IDs only. (Useful for |rt edit -; see examples.)
+ -s Short description.
+ -l Longer description.
+ -f <field[s] Display only the fields listed and the ticket id
- -o +/-<field> orders the returned list by the specified field.
- -S var=val Submits the specified variable with the request.
- -t type Specifies the type of object to look for. (The
- default is "ticket".)
+ In addition,
+ -o +/-<field> orders the returned list by the specified field.
+ -r reversed order (useful if a default was given)
+ -q queue[s] restricts the query to the queue[s] given
+ multiple queues are separated by comma
+ -S var=val Submits the specified variable with the request.
+ -t type Specifies the type of object to look for. (The
+ default is "ticket".)
+
Examples:
- rt ls "Priority > 5 and Status='new'"
- rt ls -o +subject "Priority > 5 and Status='new'"
- rt ls -o -Created "Priority > 5 and Status='new'"
+ rt ls "Priority > 5 and Status=new"
+ rt ls -o +Subject "Priority > 5 and Status=new"
+ rt ls -o -Created "Priority > 5 and Status=new"
rt ls -i "Priority > 5"|rt edit - set status=resolved
rt ls -t ticket "subject like '[PATCH]%'"
-
+ rt ls -q systems
+ rt ls -f owner,subject
+
--
Title: show
@@ -1775,11 +2173,23 @@
that refers to the links for tickets 1-3). Consult "rt help <type>"
and "rt help objects" for further details.
+ If only a number is given it will be interpreted as the objects
+ ticket/number and ticket/number/history
+
This command writes a set of forms representing the requested object
data to STDOUT.
Options:
+ The following options control how much information is displayed
+ about each matching object:
+
+ Without any formatting options prettyprinted output is generated.
+ Giving any of the two options below reverts to raw output.
+ -s Short description (history and attachments only).
+ -l Longer description (history and attachments only).
+
+ In addition,
- Read IDs from STDIN instead of the command-line.
-t type Specifies object type.
-f a,b,c Restrict the display to the specified fields.
@@ -1794,6 +2204,7 @@
rt show ticket/3/history
rt show -v ticket/3/history
rt show -t user 2
+ rt show 2
--
@@ -1810,6 +2221,8 @@
Edits information corresponding to the specified objects.
+ A purely numeric object id nnn is translated into ticket/nnn
+
If, instead of "edit", an action of "new" or "create" is specified,
then a new Object is Created. In this case, no numeric object IDs
may be specified, but the syntax and behaviour remain otherwise
@@ -1945,6 +2358,35 @@
(XXX: I'm going to have to write it, aren't I?)
+ Until it exists here a short description of important constructs:
+
+ The two simple forms of query expressions are the constructs
+ Attribute like Value and
+ Attribute = Value or Attribute != Value
+
+ Whether attributes can be matched using like or using = is built into RT.
+ The attributes id, Queue, Owner Priority and Status require the = or !=
+ tests.
+
+ If Value is a string it must be quoted and may contain the wildcard
+ character %. If the string does not contain white space, the quoting
+ may however be omitted, it will be added automatically when parsing
+ the input.
+
+ Simple query expressions can be combined using and, or and parentheses
+ can be used to group expressions.
+
+ As a special case a standalone string (which would not form a correct
+ query) is transformed into (Owner='string' or Requestor like 'string%')
+ and added to the default query, i.e. the query is narrowed down.
+
+ If no Queue=name clause is contained in the query, a default clause
+ Queue=$config{queue} is added.
+
+ Examples:
+ Status!='resolved' and Status!='rejected'
+ (Owner='myaccount' or Requestor like 'myaccount%') and Status!='resolved'
+
--
Title: form
@@ -1999,10 +2441,43 @@
Title: examples
Text:
- This section will be filled in with useful examples, once it becomes
- more clear what examples may be useful.
+ some useful examples
+
+ All the following list requests will be restricted to the default queue.
+ That can be changed by adding the option -q queuename
- For the moment, please consult examples provided with each action.
+ List all tickets that are not rejected/resolved
+ rt ls
+ List all tickets that are new and do not have an owner
+ rt ls "status=new and owner=nobody"
+ List all tickets which I have sent or of which I am the owner
+ rt ls myaccount
+ List all attributes for the ticket 6977 (ls -l instead of ls)
+ rt ls -l 6977
+ Show the content of ticket 6977
+ rt show 6977
+ Show all attributes in the ticket and in the history of the ticket
+ rt show -l 6977
+ Comment a ticket (mail is sent to all queue watchers, i.e. AdminCc's)
+ rt comment 6977
+ This will open an editor and lets you add text (attribute Text:)
+ Other attributes may be changed as well, but usually don't do that.
+ Correspond a ticket (like comment, but mail is also sent to requestors)
+ rt correspond 6977
+ Edit a ticket (generic change, interactive using the editor)
+ rt edit 6977
+ Change the owner of a ticket non interactively
+ rt edit 6977 set owner=myaccount
+ or
+ rt give 6977 account
+ or
+ rt take 6977
+ Change the status of a ticket
+ rt edit 6977 set status=resolved
+ or
+ rt resolve 6977
+ Change the status of all tickets I own to resolved !!!
+ rt ls -i owner=myaccount | rt edit - set status=resolved
--
Modified: rt/3.999/branches/merge_to_3.8.2/etc/initialdata
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/etc/initialdata (original)
+++ rt/3.999/branches/merge_to_3.8.2/etc/initialdata Wed Jan 21 10:01:29 2009
@@ -208,11 +208,11 @@
a summary of which appears below.
There is no need to reply to this message right now. Your ticket has been
-assigned an ID of [{RT->config->get(\'rtname\')} #{$ticket->id()}].
+assigned an ID of [{$Ticket->queue_obj->SubjectTag || $rtname} #{$Ticket->id()}].
Please include the string:
- [{RT->config->get(\'rtname\')} #{$ticket->id}]
+ [{$Ticket->queue_obj->SubjectTag || $rtname} #{$Ticket->id}]
in the subject line of all future correspondence about this issue. To do so,
you may reply to this message.
@@ -327,24 +327,31 @@
{ queue => $approvals_id,
name => "Approval Passed", # loc
description =>
- "Notify owner of their ticket has been approved by some approver", # loc
+ "Notify Requestor of their ticket has been approved by some approver", # loc
content => 'Subject: Ticket Approved: {$ticket->subject}
Greetings,
Your ticket has been approved by { eval { $Approval->owner_obj->name } }.
Other approvals may be pending.
+
+Approver\'s notes: { $Notes }
+
'
},
{ queue => $approvals_id,
name => "All Approvals Passed", # loc
description =>
- "Notify owner of their ticket has been approved by all approvers", # loc
+ "Notify Requestor of their ticket has been approved by all approvers", # loc
+
content => 'Subject: Ticket Approved: {$ticket->subject}
Greetings,
-Your ticket has been approved. Its owner may now start to act on it.
+Your ticket has been approved by { eval { $Approval->owner_obj->name } }.
+Its Owner may now start to act on it.
+
+Approver\'s notes: { $Notes }
'
},
{ queue => $approvals_id,
@@ -356,6 +363,20 @@
Greetings,
Your ticket has been rejected by { eval { $Approval->owner_obj->name } }.
+
+Approver\'s notes: { $Notes }
+'
+ },
+ { queue => '___Approvals',
+ name => "Approval Ready for Owner", # loc
+ Description =>
+ "Notify Owner of their ticket has been approved and is ready to be acted on", # loc
+ Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+
+Greetings,
+
+The ticket has been approved, you may now start to act on it.
+
'
},
{ queue => 0,
@@ -509,173 +530,39 @@
ScripCondition => 'On Transaction',
ScripAction => 'Extract Subject Tag',
Template => 'Blank' },
- { description => "When an approval ticket is Created, notify the owner and admin_cc of the item awaiting their approval", # loc
- queue => $approvals_id,
- scrip_condition => 'User Defined',
- custom_is_applicable_code => q[
- $self->ticket_obj->type eq 'approval' and
- $self->transaction_obj->field eq 'Status' and
- $self->transaction_obj->new_value eq 'open' and
- eval { $T::Approving = ($self->ticket_obj->all_depended_on_by( type => 'ticket' ))[0] }
- ],
- scrip_action => 'Notify owner',
- template => 'New Pending Approval' },
- { description => "If an approval is rejected, reject the original and delete pending approvals", # loc
- queue => $approvals_id,
- scrip_condition => 'On Status Change',
- scrip_action => 'User Defined',
- custom_prepare_code => q[
-# ------------------------------------------------------------------- #
-return(0) unless ( lc($self->transaction_obj->new_value) eq "rejected" or
- lc($self->transaction_obj->new_value) eq "deleted" );
-
-my $rejected = 0;
-my $links = $self->ticket_obj->depended_on_by;
-foreach my $link (@{ $links->items_array_ref }) {
- my $obj = $link->base_obj;
- if ($obj->queue->is_active_status($obj->status)) {
- if ($obj->type eq 'ticket') {
- $obj->comment(
- content => _("Your request was rejected."),
- );
- $obj->set_status(
- Status => 'rejected',
- Force => 1,
- );
-
- $T::Approval = $self->ticket_obj; # so we can access it inside templates
- $self->{ticket_obj} = $obj; # we want the original id in the token line
- $rejected = 1;
- }
- else {
- $obj->set_status(
- Status => 'deleted',
- Force => 1,
- );
- }
- }
-}
+{
+ queue => 0,
+ name => "Error: Missing dashboard", # loc
+ Description =>
+ "Inform user that a dashboard he subscribed to is missing", # loc
+ Content => q{Subject: [{RT->config->get('rtname')}] Missing dashboard!
-$links = $self->ticket_obj->depends_on;
-foreach my $link (@{ $links->items_array_ref }) {
- my $obj = $link->target_obj;
- if ($obj->queue->is_active_status($obj->status)) {
- $obj->set_status(
- Status => 'deleted',
- Force => 1,
- );
- }
-}
+Greetings,
-# Now magically turn myself into a requestor Notify object...
-require RT::ScripAction::Notify; bless($self, 'RT::ScripAction::Notify');
-$self->{argument} = 'requestor'; $self->prepare;
+You are subscribed to a dashboard that is currently missing. Most likely, the dashboard was deleted.
-return $rejected;
-# ------------------------------------------------------------------- #
- ],
- custom_commit_code => '"never needed"',
- template => 'Approval Rejected', },
- { description => "When a ticket has been approved by any approver, add correspondence to the original ticket", # loc
- queue => $approvals_id,
- scrip_condition => 'On Resolve',
- scrip_action => 'User Defined',
- custom_prepare_code => q[
-# ------------------------------------------------------------------- #
-return(0) unless ($self->ticket_obj->type eq 'approval');
-
-my $note;
-my $t = $self->ticket_obj->transactions;
-while (my $o = $t->next) {
- $note .= $o->content . "\n" if $o->content_obj
- and $o->content !~ /Default Approval/;
-}
+RT will remove this subscription as it is no longer useful. Here's the information RT had about your subscription:
-foreach my $obj ($self->ticket_obj->all_depended_on_by( type => 'ticket' )) {
- $obj->comment(
- content => _( "Your request has been approved by %1. Other approvals may still be pending.", # loc
- $self->transaction_obj->creator_obj->name,
- ) . "\n" . _( "Approver's notes: %1", # loc
- $note
- ),
- );
- $T::Approval = $self->ticket_obj; # so we can access it inside templates
- $self->{ticket_obj} = $obj; # we want the original id in the token line
+DashboardID: { $subscription_obj->sub_value('Dashboardid') }
+Frequency: { $subscription_obj->sub_value('Frequency') }
+Hour: { $subscription_obj->sub_value('Hour') }
+{
+ $subscription_obj->sub_value('Frequency') eq 'weekly'
+ ? "Day of week: " . $subscription_obj->sub_value('Dow')
+ : $subscription_obj->sub_value('Frequency') eq 'monthly'
+ ? "Day of month: " . $subscription_obj->sub_value('Dom')
+ : ''
}
-
-# Now magically turn myself into a requestor Notify object...
-require RT::ScripAction::Notify; bless($self, 'RT::ScripAction::Notify');
-$self->{argument} = 'requestor'; $self->prepare;
-
-return 1;
-# ------------------------------------------------------------------- #
- ],
- custom_commit_code => '"never needed"',
- template => 'Approval Passed' },
- { description => "When a ticket has been approved by all approvers, add correspondence to the original ticket", # loc
- queue => $approvals_id,
- scrip_condition => 'On Resolve',
- scrip_action => 'User Defined',
- custom_prepare_code => q[
-# ------------------------------------------------------------------- #
-# Find all the tickets that depend on this (that this is approving)
-
-my $ticket = $self->ticket_obj;
-my @TOP = $ticket->all_depended_on_by( type => 'ticket' );
-my $links = $ticket->depended_on_by;
-my $passed = 0;
-
-while (my $link = $links->next) {
- my $obj = $link->base_obj;
- next if ($obj->has_unresolved_dependencies( type => 'approval' ));
-
- if ($obj->type eq 'ticket') {
- $obj->comment(
- content => _("Your request has been approved."),
- );
- $T::Approval = $ticket; # so we can access it inside templates
- $self->{ticket_obj} = $obj; # we want the original id in the token line
- $passed = 1;
- }
- elsif ($obj->type eq 'approval') {
- $obj->set_status( Status => 'open', Force => 1 );
- }
- elsif (RT->config->get('UseCodeTickets') and $obj->type eq 'code') {
- #XXX: RT->config->get('UseCodeTickets') used only once here!!!
- my $code = $obj->transactions->first->content;
- my $rv;
-
- foreach my $TOP (@TOP) {
- local $@;
- $rv++ if eval $code;
- Jifty->log->error("Cannot eval code: $@") if $@;
- }
-
- if ($rv or !@TOP) {
- $obj->set_status( Status => 'resolved', Force => 1,);
- }
- else {
- $obj->set_status( Status => 'rejected', Force => 1,);
- }
- }
}
-
-# Now magically turn myself into a requestor Notify object...
-require RT::ScripAction::Notify; bless($self, 'RT::ScripAction::Notify');
-$self->{argument} = 'requestor'; $self->prepare;
-
-return 0; # ignore $passed;
-# ------------------------------------------------------------------- #
- ],
- custom_commit_code => '"never needed"',
- template => 'All Approvals Passed', },
-
+},
);
@ACL = (
{ user_id => 'root', # - principalid
right => 'SuperUser', },
-
+ { GroupDomain => 'SystemInternal',
+ GroupType => 'privileged',
+ Right => 'ShowApprovalsTab', },
);
# Predefined searches
@@ -711,7 +598,7 @@
{ format => q{'<a href="__WebPath__/Ticket/Display.html?id=__id__">__id__</a>/TITLE:#',}
. q{'<a href="__WebPath__/Ticket/Display.html?id=__id__">__subject__</a>/TITLE:subject',}
. q{priority, queue_name, extended_status, bookmark},
- query => "__Bookmarks__",
+ query => "__Bookmarked__",
order_by => 'LastUpdated',
order => 'DESC' },
},
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Action/Install.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Action/Install.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Action/Install.pm Wed Jan 21 10:01:29 2009
@@ -17,14 +17,14 @@
use Jifty::Action schema {
param 'start';
param database_type =>
- label is 'Database type',
+ label is 'Database type', # loc
render as 'Select',
available are defer {
my %map = (
- mysql => 'MySQL',
- Pg => 'PostgreSQL',
- SQLite => 'SQLite',
- Oracle => 'Oracle',
+ mysql => 'MySQL', #loc
+ Pg => 'PostgreSQL', #loc
+ SQLite => 'SQLite', #loc
+ Oracle => 'Oracle', #loc
);
for ( keys %map ) {
@@ -36,19 +36,19 @@
},
default is defer { RT->config->get( 'database_type' ) };
param database_host =>
- label is 'Database host',
+ label is 'Database host', # loc
hints is "The domain name of your database server (like 'db.example.com')", #loc
default is defer {
RT->config->get('database_host')
};
param database_port =>
- label is 'Database port',
+ label is 'Database port', # loc
hints is 'Leave empty to use the default value for your database', #loc
default is defer { RT->config->get('database_port') };
param database_name =>
- label is 'Database name',
+ label is 'Database name', #loc
default is defer {
RT->config->get('database_name')
};
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Crypt/GnuPG.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Crypt/GnuPG.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Crypt/GnuPG.pm Wed Jan 21 10:01:29 2009
@@ -436,6 +436,11 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnuPGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined $args{'passphrase'};
+
$opt{'digest-algo'} ||= 'SHA1';
$opt{'default_key'} = $args{'signer'}
if $args{'sign'} && $args{'signer'};
@@ -447,10 +452,6 @@
my $entity = $args{'entity'};
- # handling passphrase in GnuPGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined $args{'passphrase'};
-
if ( $args{'sign'} && !defined $args{'passphrase'} ) {
$args{'passphrase'} = get_passphrase( address => $args{'signer'} );
}
@@ -479,8 +480,11 @@
my $pid =
safe_run_child { $gnupg->detach_sign( handles => $handles ) };
$entity->make_multipart( 'mixed', Force => 1 );
- $entity->parts(0)->print( $handle{'stdin'} );
- close $handle{'stdin'};
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $entity->parts(0)->print( $handle{'stdin'} );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
my $err = $@;
@@ -522,7 +526,7 @@
use_key_for_encryption($_) || $_, grep !$seen{$_}++, map
$_->address, map Email::Address->parse( $entity->head->get($_) ), qw(To Cc Bcc);
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my ( $handles, $handle_list ) = _make_gpg_handles( stdout => $tmp_fh );
@@ -538,8 +542,11 @@
: $gnupg->encrypt( handles => $handles );
};
$entity->make_multipart( 'mixed', Force => 1 );
- $entity->parts(0)->print( $handle{'stdin'} );
- close $handle{'stdin'};
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $entity->parts(0)->print( $handle{'stdin'} );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
@@ -618,6 +625,11 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnupGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined( $args{'passphrase'} );
+
$opt{'digest-algo'} ||= 'SHA1';
$opt{'default_key'} = $args{'signer'}
if $args{'sign'} && $args{'signer'};
@@ -627,10 +639,6 @@
meta_interactive => 0,
);
- # handling passphrase in GnupGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined( $args{'passphrase'} );
-
if ( $args{'sign'} && !defined $args{'passphrase'} ) {
$args{'passphrase'} = get_passphrase( address => $args{'signer'} );
}
@@ -643,7 +651,7 @@
my %res;
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my ( $handles, $handle_list ) = _make_gpg_handles( stdout => $tmp_fh );
@@ -660,8 +668,11 @@
? 'sign_and_encrypt'
: ( $args{'sign'} ? 'clearsign' : 'encrypt' );
my $pid = safe_run_child { $gnupg->$method( handles => $handles ) };
- $entity->bodyhandle->print( $handle{'stdin'} );
- close $handle{'stdin'};
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $entity->bodyhandle->print( $handle{'stdin'} );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
$res{'exit_code'} = $?;
@@ -706,6 +717,11 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnupGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined( $args{'passphrase'} );
+
$opt{'digest-algo'} ||= 'SHA1';
$opt{'default_key'} = $args{'signer'}
if $args{'sign'} && $args{'signer'};
@@ -715,10 +731,6 @@
meta_interactive => 0,
);
- # handling passphrase in GnupGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined( $args{'passphrase'} );
-
if ( $args{'sign'} && !defined $args{'passphrase'} ) {
$args{'passphrase'} = get_passphrase( address => $args{'signer'} );
}
@@ -732,7 +744,7 @@
my %res;
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my ( $handles, $handle_list ) = _make_gpg_handles( stdout => $tmp_fh );
@@ -747,8 +759,11 @@
? 'sign_and_encrypt'
: ( $args{'sign'} ? 'detach_sign' : 'encrypt' );
my $pid = safe_run_child { $gnupg->$method( handles => $handles ) };
- $entity->bodyhandle->print( $handle{'stdin'} );
- close $handle{'stdin'};
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $entity->bodyhandle->print( $handle{'stdin'} );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
$res{'exit_code'} = $?;
@@ -782,7 +797,7 @@
} else {
$entity->bodyhandle( new MIME::Body::File $tmp_fn );
$entity->effective_type('application/octet-stream');
- $args{'data'}->head->mime_attr( $_ => "$filename.pgp" ) foreach (qw(Content-Type.name Content-Disposition.filename));
+ $entity->head->mime_attr( $_ => "$filename.pgp" ) foreach (qw(Content-Type.name Content-Disposition.filename));
}
$entity->{'__store_tmp_handle_to_avoid_early_cleanup'} = $tmp_fh;
@@ -807,6 +822,11 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnupGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined( $args{'passphrase'} );
+
$opt{'digest-algo'} ||= 'SHA1';
$opt{'default_key'} = $args{'signer'}
if $args{'sign'} && $args{'signer'};
@@ -816,10 +836,6 @@
meta_interactive => 0,
);
- # handling passphrase in GnupGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined( $args{'passphrase'} );
-
if ( $args{'sign'} && !defined $args{'passphrase'} ) {
$args{'passphrase'} = get_passphrase( address => $args{'signer'} );
}
@@ -832,7 +848,7 @@
my %res;
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my ( $handles, $handle_list ) = _make_gpg_handles( stdout => $tmp_fh );
@@ -847,8 +863,11 @@
? 'sign_and_encrypt'
: ( $args{'sign'} ? 'clearsign' : 'encrypt' );
my $pid = safe_run_child { $gnupg->$method( handles => $handles ) };
- $handle{'stdin'}->print( ${ $args{'content'} } );
- close $handle{'stdin'};
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $handle{'stdin'}->print( ${ $args{'content'} } );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
$res{'exit_code'} = $?;
@@ -1057,7 +1076,7 @@
$opt{'digest-algo'} ||= 'SHA1';
$gnupg->options->hash_init( _prepare_gnupg_options(%opt), meta_interactive => 0, );
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
$args{'data'}->bodyhandle->print($tmp_fh);
$tmp_fh->flush;
@@ -1074,9 +1093,11 @@
command_args => [ '-', $tmp_fn ]
);
};
- $args{'signature'}->bodyhandle->print( $handle{'stdin'} );
- close $handle{'stdin'};
-
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $args{'signature'}->bodyhandle->print( $handle{'stdin'} );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
$res{'exit_code'} = $?;
@@ -1102,7 +1123,7 @@
$opt{'digest-algo'} ||= 'SHA1';
$gnupg->options->hash_init( _prepare_gnupg_options(%opt), meta_interactive => 0, );
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw:eol(CRLF?)';
$args{'data'}->print($tmp_fh);
$tmp_fh->flush;
@@ -1119,9 +1140,11 @@
command_args => [ '-', $tmp_fn ]
);
};
- $args{'signature'}->bodyhandle->print( $handle{'stdin'} );
- close $handle{'stdin'};
-
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $args{'signature'}->bodyhandle->print( $handle{'stdin'} );
+ close $handle{'stdin'};
+ }
waitpid $pid, 0;
};
$res{'exit_code'} = $?;
@@ -1150,6 +1173,11 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnupGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined( $args{'passphrase'} );
+
$opt{'digest-algo'} ||= 'SHA1';
$gnupg->options->hash_init( _prepare_gnupg_options(%opt), meta_interactive => 0, );
@@ -1158,14 +1186,10 @@
RT::EmailParser->_decode_body( $args{'data'} );
}
- # handling passphrase in GnupGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined( $args{'passphrase'} );
-
$args{'passphrase'} = get_passphrase()
unless defined $args{'passphrase'};
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my ( $handles, $handle_list ) = _make_gpg_handles(
@@ -1179,8 +1203,11 @@
local $SIG{'CHLD'} = 'DEFAULT';
$gnupg->passphrase( $args{'passphrase'} );
my $pid = safe_run_child { $gnupg->decrypt( handles => $handles ) };
- $args{'data'}->bodyhandle->print( $handle{'stdin'} );
- close $handle{'stdin'};
+ {
+ local $SIG{'PIPE'} = 'IGNORE';
+ $args{'data'}->bodyhandle->print( $handle{'stdin'} );
+ close $handle{'stdin'}
+ }
waitpid $pid, 0;
};
@@ -1223,6 +1250,11 @@
);
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnuPGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined($args{'passphrase'});
+
$opt{'digest-algo'} ||= 'SHA1';
$gnupg->options->hash_init(
_prepare_gnupg_options( %opt ),
@@ -1234,14 +1266,10 @@
RT::EmailParser->_decode_body($args{'data'});
}
- # handling passphrase in GnuPGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined($args{'passphrase'});
-
$args{'passphrase'} = get_passphrase()
unless defined $args{'passphrase'};
- my ($tmp_fh, $tmp_fn) = File::Temp::tempfile();
+ my ($tmp_fh, $tmp_fn) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my $io = $args{'data'}->open('r');
@@ -1250,7 +1278,7 @@
}
my ($had_literal, $in_block) = ('', 0);
- my ($block_fh, $block_fn) = File::Temp::tempfile();
+ my ($block_fh, $block_fn) = File::Temp::tempfile( UNLINK => 1 );
binmode $block_fh, ':raw';
my %res;
@@ -1273,7 +1301,7 @@
}
print $tmp_fh "-----END OF PART-----\n" if $had_literal;
- ($block_fh, $block_fn) = File::Temp::tempfile();
+ ($block_fh, $block_fn) = File::Temp::tempfile( UNLINK => 1 );
binmode $block_fh, ':raw';
$in_block = 0;
}
@@ -1354,6 +1382,11 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
+ # handling passphrase in GnuPGOptions
+ $args{'passphrase'} = delete $opt{'passphrase'}
+ if !defined( $args{'passphrase'} );
+
$opt{'digest-algo'} ||= 'SHA1';
$gnupg->options->hash_init( _prepare_gnupg_options(%opt),
meta_interactive => 0, );
@@ -1363,14 +1396,10 @@
RT::EmailParser->_decode_body( $args{'data'} );
}
- # handling passphrase in GnuPGOptions
- $args{'passphrase'} = delete $opt{'passphrase'}
- if !defined( $args{'passphrase'} );
-
$args{'passphrase'} = get_passphrase()
unless defined $args{'passphrase'};
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
$args{'data'}->bodyhandle->print($tmp_fh);
seek $tmp_fh, 0, 0;
@@ -1401,17 +1430,18 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
- $opt{'digest-algo'} ||= 'SHA1';
- $gnupg->options->hash_init( _prepare_gnupg_options(%opt), meta_interactive => 0, );
# handling passphrase in GnuPGOptions
$args{'passphrase'} = delete $opt{'passphrase'}
if !defined( $args{'passphrase'} );
+ $opt{'digest-algo'} ||= 'SHA1';
+ $gnupg->options->hash_init( _prepare_gnupg_options(%opt), meta_interactive => 0, );
+
$args{'passphrase'} = get_passphrase()
unless defined $args{'passphrase'};
- my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile();
+ my ( $tmp_fh, $tmp_fn ) = File::Temp::tempfile( UNLINK => 1 );
binmode $tmp_fh, ':raw';
my ( $handles, $handle_list ) = _make_gpg_handles( stdout => $tmp_fh );
@@ -2004,6 +2034,7 @@
my $gnupg = new GnuPG::Interface;
my %opt = RT->config->get('GnuPGOptions');
+
$opt{'digest-algo'} ||= 'SHA1';
$opt{'with-colons'} = undef; # parseable format
$opt{'fingerprint'} = undef; # show fingerprint
@@ -2355,12 +2386,24 @@
eval {
local $SIG{'CHLD'} = 'DEFAULT';
- my $pid = safe_run_child { $gnupg->version( handles => $handles ) };
+ my $pid = safe_run_child {
+ $gnupg->wrap_call( commands => ['--version'], handles => $handles );
+ };
close $handle{'stdin'};
waitpid $pid, 0;
};
- return 0 if $@;
- return 0 if $?;
+ if ($@) {
+ Jifty->log->debug(
+ "Probe for GPG failed." . " Couldn't run `gpg --version`: " . $@ );
+ return 0;
+ }
+ if ($?) {
+ Jifty->log->debug( "Probe for GPG failed."
+ . " Process exitted with code "
+ . ( $? >> 8 )
+ . ( $? & 127 ? ( " as recieved signal " . ( $? & 127 ) ) : '' ) );
+ return 0;
+ }
return 1;
}
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Dashboard.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Dashboard.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Dashboard.pm Wed Jan 21 10:01:29 2009
@@ -108,7 +108,8 @@
return $object->add_attribute(
'name' => 'Dashboard',
'description' => $args->{'name'},
- 'content' => { Searches => $args->{'searches'} },
+ 'content' => { Panes => $args->{'panes'} },
+
);
}
@@ -117,10 +118,9 @@
my $args = shift;
my ( $status, $msg ) = ( 1, undef );
- if ( defined $args->{'searches'} ) {
+ if ( defined $args->{'panes'} ) {
( $status, $msg ) =
- $self->{'attribute'}
- ->set_sub_values( searches => $args->{'searches'}, );
+ $self->{'attribute'}->set_sub_values( panes => $args->{'panes'}, );
}
if ( $status && $args->{'name'} ) {
@@ -141,68 +141,73 @@
( $status, $msg ) = $attr->set_object_id($new_obj_id);
}
$self->{'privacy'} = $args->{'privacy'} if $status;
+
}
return ( $status, $msg );
}
-=head2 searches
+=head2 panes
-Returns a list of loaded saved searches
+Returns a hashref of pane name to portlets
=cut
-sub searches {
+sub panes {
my $self = shift;
- return map {
- my $search = RT::SavedSearch->new( current_user => $self->current_user );
- $search->load( $_->[0], $_->[1] );
- $search
- } $self->search_ids;
+ return unless ref( $self->{'attribute'} ) eq 'RT::Model::Attribute';
+ return $self->{'attribute'}->sub_value('panes') || {};
+
}
-=head2 search_ids
+=head2 portlets
-Returns a list of array references, each being a saved-search privacy, ID, and
-description
+Returns the list of this dashboard's portlets, each a hashref with key
+C<portlet_type> being C<search> or C<component>.
=cut
-sub search_ids {
+sub portlets {
my $self = shift;
- return unless ref( $self->{'attribute'} ) eq 'RT::Model::Attribute';
- return @{ $self->{'attribute'}->sub_value('searches') || [] };
+ return map { @$_ } values %{ $self->panes };
}
-=head2 search_privacies
+=head2 searches
-Returns a list of array references, each one being suitable to pass to
-/Elements/ShowSearch.
+Returns a list of loaded saved searches
=cut
-sub search_privacies {
+sub searches {
my $self = shift;
- return map { [ $self->search_privacy(@$_) ] } $self->search_ids;
+ return map {
+ my $search = RT::SavedSearch->new;
+ $search->load( $_->{privacy}, $_->{id} );
+ $search
+ } grep { $_->{portlet_type} eq 'search' } $self->portlets;
}
-=head2 search_privacy TYPE, ID, DESC
+=head2 show_search_name portlet
Returns an array for one saved search, suitable for passing to
/Elements/ShowSearch.
=cut
-sub search_privacy {
- my $self = shift;
- my ( $type, $id, $desc ) = @_;
- if ( $type eq 'RT::System' ) {
- return name => $desc;
+sub show_search_name {
+ my $self = shift;
+ my $portlet = shift;
+
+ if ( $portlet->{privacy} eq 'RT::System' ) {
+ return name => $portlet->{description};
}
- return saved_search => join( '-', $type, 'SavedSearch', $id );
+ return saved_search =>
+ join( '-', $portlet->{privacy}, 'SavedSearch', $portlet->{id} );
}
+
+
=head2 possible_hidden_searches
This will return a list of saved searches that are potentially not visible by
@@ -219,8 +224,8 @@
}
# _privacy_objects: returns a list of objects that can be used to load
-# dashboards from. If the Modify parameter is true, then check modify rights.
-# If the Create parameter is true, then check create rights. Otherwise, check
+# dashboards from. If the modify parameter is true, then check modify rights.
+# If the create parameter is true, then check create rights. Otherwise, check
# read rights.
sub _privacy_objects {
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Date.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Date.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Date.pm Wed Jan 21 10:01:29 2009
@@ -185,10 +185,14 @@
require Time::ParseDate;
# the module supports only legacy timezones like PDT or EST...
- # so we parse date as GMT and later apply offset
+ # so we parse date as GMT and later apply offset, this only
+ # should be applied to absolute times, so compensate shift in NOW
+ my $now = time;
+ $now += ( $self->Localtime( $args{timezone}, $now ) )[9];
my $date = Time::ParseDate::parsedate(
$args{'value'},
GMT => 1,
+ NOW => $now,
UK => RT->config->get('DateDayBeforeMonth'),
PREFER_PAST => RT->config->get('AmbiguousDayInPast'),
PREFER_FUTURE => RT->config->get('AmbiguousDayInFuture'),
@@ -379,7 +383,8 @@
my $self = shift;
my $dow = shift;
- return _("$DAYS_OF_WEEK[$dow].") if $DAYS_OF_WEEK[$dow];
+ return _( $DAYS_OF_WEEK[$dow] )
+ if $DAYS_OF_WEEK[$dow];
return '';
}
@@ -394,7 +399,8 @@
my $self = shift;
my $mon = shift;
- return _("$MONTHS[$mon].") if $MONTHS[$mon];
+ return _( $MONTHS[$mon] )
+ if $MONTHS[$mon];
return '';
}
@@ -719,34 +725,45 @@
return $res;
}
-=head4 iCal
+=head4 ical
-Returns the date and time formatted as an ICalendar string -- that is,
-C<yyyymmddThhmmssZ>
+Returns the object's date and time in iCalendar format,
+
+Supports arguments: C<Date> and C<Time>.
+See </Output formatters> for description of arguments.
=cut
-sub iCal {
+sub ical {
my $self = shift;
my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $ydaym, $isdst, $offset )
= $self->localtime("UTC");
- return sprintf( '%04d%02d%02dT%02d%02d%02dZ',
- $year, $mon, $mday, $hour, $min, $sec );
+ #the month needs incrementing, as gmtime returns 0-11
+ $mon++;
+
+ my $res;
+ if ( $args{'date'} && !$args{'time'} ) {
+ $res = sprintf( '%04d%02d%02d', $year, $mon, $mday );
+ }
+ elsif ( !$args{'date'} && $args{'time'} ) {
+ $res = sprintf( 'T%02d%02d%02dZ', $hour, $min, $sec );
+ }
+ else {
+ $res = sprintf( '%04d%02d%02dT%02d%02d%02dZ',
+ $year, $mon, $mday, $hour, $min, $sec );
+ }
+ return $res;
+
}
-=head4 iCalDate
+=head4 ical_date
Returns the date formatted as an ICalendar string -- that is, C<yyyymmddZ>
=cut
-sub iCalDate {
- my $self = shift;
- my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $ydaym, $isdst, $offset )
- = $self->localtime("UTC");
- return sprintf( '%04d%02d%02dZ', $year, $mon, $mday );
-}
+sub ical_date { return (shift)->ical( time => 0, @_ ) }
sub _split_offset {
my ( $self, $offset ) = @_;
@@ -759,7 +776,7 @@
=head2 timezones handling
-=head3 Localtime $context [$time]
+=head3 localtime $context [$time]
Takes one mandatory argument C<$context>, which determines whether
we want "user local", "system" or "UTC" time. Also, takes optional
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/EmailParser.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/EmailParser.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/EmailParser.pm Wed Jan 21 10:01:29 2009
@@ -464,6 +464,52 @@
}
+=head2 parse_email_address string
+
+Returns a list of Email::Address objects
+Works around the bug that Email::Address 1.889 and earlier
+doesn't handle local-only email addresses (when users pass
+in just usernames on the RT system in fields that expect
+email Addresses)
+
+We don't handle the case of
+bob, fred at bestpractical.com
+because we don't want to fail parsing
+bob, "Falcone, Fred" <fred at bestpractical.com>
+The next release of Email::Address will have a new method
+we can use that removes the bandaid
+
+=cut
+
+sub parse_email_address {
+ my $self = shift;
+ my $address_string = shift;
+
+ $address_string =~ s/^\s+|\s+$//g;
+
+ my @addresses;
+
+ # if it looks like a username / local only email
+ if ( $address_string !~ /@/ && $address_string =~ /^\w+$/ ) {
+ my $user = RT::Model::User->new( current_user => RT->system_user );
+ my ( $id, $msg ) = $user->load($address_string);
+ if ($id) {
+ push @addresses, Email::Address->new( $user->name, $user->email );
+ }
+ else {
+ Jifty->log->error(
+ "Unable to parse an email address from $address_string: $msg");
+ }
+ }
+ else {
+ @addresses = Email::Address->parse($address_string);
+ }
+
+ return @addresses;
+
+}
+
+
sub DESTROY {
my $self = shift;
File::Path::rmtree( [ @{ $self->{'attachment_dirs'} } ], 0, 1 )
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Graph/Tickets.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Graph/Tickets.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Graph/Tickets.pm Wed Jan 21 10:01:29 2009
@@ -154,12 +154,16 @@
sub TicketProperties {
my $self = shift;
my $user = shift;
- my @res = (
- Basics => [qw(Subject Status Queue TimeLeft TimeWorked TimeEstimated)],
- People => [qw(Owner Requestors Ccs AdminCcs Creator LastUpdatedBy)],
- Dates => [qw(Created Starts Started Due Resolved Told LastUpdated)],
+ my @res = (
+ Basics => [qw(Subject Status queue TimeLeft TimeWorked TimeEstimated)]
+ , # loc_qw
+ People => [qw(Owner Requestors Ccs AdminCcs Creator LastUpdatedBy)]
+ , # loc_qw
+ Dates => [qw(Created Starts Started Due Resolved Told LastUpdated)]
+ , # loc_qw
Links =>
- [qw(MemberOf Members DependsOn DependedOnBy RefersTo ReferredToBy)],
+ [qw(MemberOf Members DependsOn DependedOnBy RefersTo ReferredToBy)]
+ , # loc_qw
);
my $cfs = RT::Model::CustomFieldCollection->new($user);
$cfs->limit_to_lookup_type('RT::Model::Queue-RT::Model::Ticket');
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/REST.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/REST.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/REST.pm Wed Jan 21 10:01:29 2009
@@ -178,7 +178,7 @@
vpush( $k, $f, join( "\n", @v ) );
$state = 1;
- } elsif ( $line !~ /^#/ ) {
+ } elsif ( $line =~ /^#/ ) {
# We've found a syntax error, so we'll reconstruct the
# form parsed thus far, and add an error marker. (>>)
@@ -296,7 +296,9 @@
my ($val) = @_;
my ( $line, $word, @words );
- foreach $line ( map { split /\n/ } ( ref $val eq 'ARRAY' ) ? @$val : $val ) {
+ foreach $line ( map { split /\n/ }
+ ( ref $val eq 'ARRAY' ) ? @$val : ( $val || '' ) )
+ {
# XXX: This should become a real parser, ? la Text::ParseWords.
$line =~ s/^\s+//;
Modified: rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/Web.pm
==============================================================================
--- rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/Web.pm (original)
+++ rt/3.999/branches/merge_to_3.8.2/lib/RT/Interface/Web.pm Wed Jan 21 10:01:29 2009
@@ -186,7 +186,8 @@
$uri->scheme('http');
}
- $uri->host( $ENV{'HTTP_HOST'} );
+ # [rt3.fsck.com #12716] Apache recommends use of $SERVER_HOST
+ $uri->host( $ENV{'SERVER_HOST'} || $ENV{'HTTP_HOST'} );
$uri->port( $ENV{'SERVER_PORT'} );
}
@@ -255,6 +256,81 @@
return $content;
}
+=head2 send_static_file
+
+Takes a File => path and a type => Content-type
+
+If type isn't provided and File is an image, it will
+figure out a sane Content-type, otherwise it will
+send application/octet-stream
+
+Will set caching headers using StaticFileHeaders
+
+=cut
+
+sub send_static_file {
+ my $self = shift;
+ my %args = @_;
+ my $file = $args{file};
+ my $type = $args{type};
+
+ $self->static_file_headers();
+
+ unless ($type) {
+ if ( $file =~ /\.(gif|png|jpe?g)$/i ) {
+ $type = "image/$1";
+ $type =~ s/jpg/jpeg/gi;
+ }
+ $type ||= "application/octet-stream";
+ }
+ $HTML::Mason::Commands::r->content_type($type);
+ open my $fh, "<$file" or die "couldn't open file: $!";
+ binmode($fh);
+ {
+ local $/ = \16384;
+ $HTML::Mason::Commands::m->out($_) while (<$fh>);
+ $HTML::Mason::Commands::m->flush_buffer;
+ }
+ close $fh;
+}
+
+sub strip_content {
+ my %args = @_;
+ my $content = $args{content};
+ my $html = ( ( $args{content_type} || '' ) eq "text/html" );
+ my $sigonly = $args{strip_signature};
+
+ # Save us from undef warnings
+ return '' unless defined $content;
+
+ # Make the content have no 'weird' newlines in it
+ $content =~ s/\r+\n/\n/g;
+
+ # Filter empty content when type is text/html
+ return '' if $html && $content =~ m{^\s*(?:<br[^>]*/?>)*\s*$}s;
+
+ # If we aren't supposed to strip the sig, just bail now.
+ return $content unless $sigonly;
+
+ # Find the signature
+ my $sig = $args{'current_user'}->user_object->Signature || '';
+ $sig =~ s/^\s+//;
+ $sig =~ s/\s+$//;
+
+ # Check for plaintext sig
+ return '' if not $html and $content =~ /^\s*(--)?\s*\Q$sig\E\s*$/;
+
+ # Check for html-formatted sig
+ RT::Interface::Web::EscapeUTF8( \$sig );
+ return ''
+ if $html
+ and $content =~
+ m{^\s*<p>\s*(--)?\s*<br[^>]*?/?>\s*\Q$sig\E\s*</p>\s*$}s;
+
+ # Pass it through
+ return $content;
+}
+
package HTML::Mason::Commands;
use vars qw/$r $m %session/;
@@ -608,6 +684,7 @@
);
unless ( $args{'args_ref'}->{'UpdateIgnoreAddressCheckboxes'} ) {
+
foreach my $key ( keys %{ $args{args_ref} } ) {
next unless $key =~ /^Update(cc|Bcc)-(.*)$/;
@@ -650,7 +727,6 @@
sub make_mime_entity {
- #TODO document what else this takes.
my %args = (
subject => undef,
from => undef,
@@ -699,14 +775,21 @@
# Prefer the cached name first over CGI.pm stringification.
my $filename = $RT::Mason::CGI::Filename;
$filename = "$filehandle" unless defined($filename);
-
- $filename =~ s#^.*[\\/]##;
+ $filename = Encode::decode_utf8($filename);
+ $filename =~ s{^.*[\\/]}{};
+
$Message->attach(
Type => $uploadinfo->{'Content-Type'},
- Filename => Encode::decode_utf8($filename),
+ Filename => $filename,
Data => \@content,
);
+ if ( !$args{'subject'}
+ && !( defined $args{'body'} && length $args{'body'} ) )
+ {
+ $Message->head->set( 'Subject' => $filename );
+ }
+
}
}
@@ -1352,7 +1435,8 @@
for my $luri ( split( / /, $args_ref->{ $Record->id . "-$linktype" } ) ) {
next unless $luri;
- $luri =~ s/\s*$//; # Strip trailing whitespace
+ $luri =~ s/\s+$//; # Strip trailing whitespace
+
my ( $val, $msg ) = $Record->add_link(
target => $luri,
type => $linktype
More information about the Rt-commit
mailing list