diff options
Diffstat (limited to 'rt/lib')
39 files changed, 5826 insertions, 3156 deletions
diff --git a/rt/lib/RT/ACE.pm b/rt/lib/RT/ACE.pm index 1501a125e..dca50c359 100755 --- a/rt/lib/RT/ACE.pm +++ b/rt/lib/RT/ACE.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -44,11 +69,7 @@ RT::ACE =cut package RT::ACE; -use RT::Record; - - -use vars qw( @ISA ); -@ISA= qw( RT::Record ); +use base 'RT::Record'; sub _Init { my $self = shift; @@ -61,7 +82,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -104,7 +125,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -113,14 +134,14 @@ Returns the current value of id. =cut -=item PrincipalType +=head2 PrincipalType Returns the current value of PrincipalType. (In the database, PrincipalType is stored as varchar(25).) -=item SetPrincipalType VALUE +=head2 SetPrincipalType VALUE Set PrincipalType to VALUE. @@ -131,14 +152,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item PrincipalId +=head2 PrincipalId Returns the current value of PrincipalId. (In the database, PrincipalId is stored as int(11).) -=item SetPrincipalId VALUE +=head2 SetPrincipalId VALUE Set PrincipalId to VALUE. @@ -149,14 +170,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item RightName +=head2 RightName Returns the current value of RightName. (In the database, RightName is stored as varchar(25).) -=item SetRightName VALUE +=head2 SetRightName VALUE Set RightName to VALUE. @@ -167,14 +188,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ObjectType +=head2 ObjectType Returns the current value of ObjectType. (In the database, ObjectType is stored as varchar(25).) -=item SetObjectType VALUE +=head2 SetObjectType VALUE Set ObjectType to VALUE. @@ -185,14 +206,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ObjectId +=head2 ObjectId Returns the current value of ObjectId. (In the database, ObjectId is stored as int(11).) -=item SetObjectId VALUE +=head2 SetObjectId VALUE Set ObjectId to VALUE. @@ -203,14 +224,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item DelegatedBy +=head2 DelegatedBy Returns the current value of DelegatedBy. (In the database, DelegatedBy is stored as int(11).) -=item SetDelegatedBy VALUE +=head2 SetDelegatedBy VALUE Set DelegatedBy to VALUE. @@ -221,14 +242,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item DelegatedFrom +=head2 DelegatedFrom Returns the current value of DelegatedFrom. (In the database, DelegatedFrom is stored as int(11).) -=item SetDelegatedFrom VALUE +=head2 SetDelegatedFrom VALUE Set DelegatedFrom to VALUE. @@ -240,47 +261,30 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, PrincipalType => - {read => 1, write => 1, type => 'varchar(25)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 25, is_blob => 0, is_numeric => 0, type => 'varchar(25)', default => ''}, PrincipalId => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, RightName => - {read => 1, write => 1, type => 'varchar(25)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 25, is_blob => 0, is_numeric => 0, type => 'varchar(25)', default => ''}, ObjectType => - {read => 1, write => 1, type => 'varchar(25)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 25, is_blob => 0, is_numeric => 0, type => 'varchar(25)', default => ''}, ObjectId => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, DelegatedBy => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, DelegatedFrom => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, } }; - - eval "require RT::ACE_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/ACE_Overlay.pm}) { - die $@; - }; - - eval "require RT::ACE_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/ACE_Vendor.pm}) { - die $@; - }; - - eval "require RT::ACE_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/ACE_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -290,7 +294,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/ACL.pm b/rt/lib/RT/ACL.pm index 81f59c6d0..94a0c9109 100755 --- a/rt/lib/RT/ACL.pm +++ b/rt/lib/RT/ACL.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -47,12 +72,9 @@ use strict; package RT::ACL; -use RT::SearchBuilder; +use base 'RT::SearchBuilder'; use RT::ACE; -use vars qw( @ISA ); -@ISA= qw(RT::SearchBuilder); - sub _Init { my $self = shift; @@ -64,7 +86,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::ACE item @@ -74,24 +96,7 @@ sub NewItem { my $self = shift; return(RT::ACE->new($self->CurrentUser)); } - - eval "require RT::ACL_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/ACL_Overlay.pm}) { - die $@; - }; - - eval "require RT::ACL_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/ACL_Vendor.pm}) { - die $@; - }; - - eval "require RT::ACL_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/ACL_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +106,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Action/Autoreply.pm b/rt/lib/RT/Action/Autoreply.pm index 81f7bddfa..e3e792ea7 100755 --- a/rt/lib/RT/Action/Autoreply.pm +++ b/rt/lib/RT/Action/Autoreply.pm @@ -1,34 +1,71 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + package RT::Action::Autoreply; -require RT::Action::SendEmail; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::SendEmail); +use warnings; + +use base qw(RT::Action::SendEmail); + +=head2 Prepare + +Set up the relevant recipients, then call our parent. + +=cut +sub Prepare { + my $self = shift; + $self->SetRecipients(); + $self->SUPER::Prepare(); +} + # {{{ sub SetRecipients =head2 SetRecipients @@ -59,38 +96,37 @@ Set this message\'s return address to the apropriate queue address sub SetReturnAddress { my $self = shift; - my %args = ( is_comment => 0, - @_ - ); - my $replyto; - if ($args{'is_comment'}) { - $replyto = $self->TicketObj->QueueObj->CommentAddress || - $RT::CommentAddress; - } - else { - $replyto = $self->TicketObj->QueueObj->CorrespondAddress || - $RT::CorrespondAddress; - } - - unless ($self->TemplateObj->MIMEObj->head->get('From')) { - my $friendly_name = $self->TicketObj->QueueObj->Description || - $self->TicketObj->QueueObj->Name; - $friendly_name =~ s/"/\\"/g; - $self->SetHeader('From', "\"$friendly_name\" <$replyto>"); - } - - unless ($self->TemplateObj->MIMEObj->head->get('Reply-To')) { - $self->SetHeader('Reply-To', "$replyto"); - } + my $friendly_name; + + if (RT->Config->Get('UseFriendlyFromLine')) { + $friendly_name = $self->TicketObj->QueueObj->Description || + $self->TicketObj->QueueObj->Name; + } + + $self->SUPER::SetReturnAddress( @_, friendly_name => $friendly_name ); } # }}} -eval "require RT::Action::Autoreply_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Autoreply_Vendor.pm}); -eval "require RT::Action::Autoreply_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Autoreply_Local.pm}); +# {{{{ sub SetRTSpecialHeaders + +=head2 SetRTSpecialHeaders + +Set the C<Auto-Generated> header to C<auto-replied>, in accordance +with RFC3834. + +=cut + +sub SetRTSpecialHeaders { + my $self = shift; + $self->SUPER::SetRTSpecialHeaders(@_); + $self->SetHeader( 'Auto-Submitted', 'auto-replied' ); +} + +# }}} + +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Action/Generic.pm b/rt/lib/RT/Action/Generic.pm index 007d299c7..d747813f0 100755 --- a/rt/lib/RT/Action/Generic.pm +++ b/rt/lib/RT/Action/Generic.pm @@ -1,29 +1,54 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + =head1 NAME - RT::Action::Generic - a generic baseclass for RT Actions + RT::Action::Generic - deprecated, see RT::Action =head1 SYNOPSIS @@ -31,165 +56,18 @@ =head1 DESCRIPTION -=head1 METHODS - -=begin testing +This module is provided only for backwards compatibility. -ok (require RT::Action::Generic); +=head1 METHODS -=end testing =cut -package RT::Action::Generic; - use strict; +use warnings; +package RT::Action::Generic; +use base 'RT::Action'; -# {{{ sub new -sub new { - my $proto = shift; - my $class = ref($proto) || $proto; - my $self = {}; - bless ($self, $class); - $self->_Init(@_); - return $self; -} -# }}} - -# {{{ sub new -sub loc { - my $self = shift; - return $self->{'ScripObj'}->loc(@_); -} -# }}} - -# {{{ sub _Init -sub _Init { - my $self = shift; - my %args = ( TransactionObj => undef, - TicketObj => undef, - ScripObj => undef, - TemplateObj => undef, - Argument => undef, - Type => undef, - @_ ); - - - $self->{'Argument'} = $args{'Argument'}; - $self->{'ScripObj'} = $args{'ScripObj'}; - $self->{'TicketObj'} = $args{'TicketObj'}; - $self->{'TransactionObj'} = $args{'TransactionObj'}; - $self->{'TemplateObj'} = $args{'TemplateObj'}; - $self->{'Type'} = $args{'Type'}; -} -# }}} - -# Access Scripwide data - -# {{{ sub Argument -sub Argument { - my $self = shift; - return($self->{'Argument'}); -} -# }}} - -# {{{ sub TicketObj -sub TicketObj { - my $self = shift; - return($self->{'TicketObj'}); -} -# }}} - -# {{{ sub TransactionObj -sub TransactionObj { - my $self = shift; - return($self->{'TransactionObj'}); -} -# }}} - -# {{{ sub TemplateObj -sub TemplateObj { - my $self = shift; - return($self->{'TemplateObj'}); -} -# }}} - -# {{{ sub ScripObj -sub ScripObj { - my $self = shift; - return($self->{'ScripObj'}); -} -# }}} - -# {{{ sub Type -sub Type { - my $self = shift; - return($self->{'Type'}); -} -# }}} - - -# Scrip methods - -#Do what we need to do and send it out. - -# {{{ sub Commit -sub Commit { - my $self = shift; - return(0, $self->loc("Commit Stubbed")); -} -# }}} - - -#What does this type of Action does - -# {{{ sub Describe -sub Describe { - my $self = shift; - return $self->loc("No description for [_1]", ref $self); -} -# }}} - - -#Parse the templates, get things ready to go. - -# {{{ sub Prepare -sub Prepare { - my $self = shift; - return (0, $self->loc("Prepare Stubbed")); -} -# }}} - - -#If this rule applies to this transaction, return true. - -# {{{ sub IsApplicable -sub IsApplicable { - my $self = shift; - return(undef); -} -# }}} - -# {{{ sub DESTROY -sub DESTROY { - my $self = shift; - - # We need to clean up all the references that might maybe get - # oddly circular - $self->{'TemplateObj'} =undef - $self->{'TicketObj'} = undef; - $self->{'TransactionObj'} = undef; - $self->{'ScripObj'} = undef; - - - -} - -# }}} - -eval "require RT::Action::Generic_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Generic_Vendor.pm}); -eval "require RT::Action::Generic_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Generic_Local.pm}); - +RT::Base->_ImportOverlays(); 1; + diff --git a/rt/lib/RT/Action/Notify.pm b/rt/lib/RT/Action/Notify.pm index 1e4e4c073..3f58bf52f 100755 --- a/rt/lib/RT/Action/Notify.pm +++ b/rt/lib/RT/Action/Notify.pm @@ -1,34 +1,73 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + +# package RT::Action::Notify; -require RT::Action::SendEmail; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::SendEmail); +use warnings; -# {{{ sub SetRecipients +use base qw(RT::Action::SendEmail); + +use Email::Address; + +=head2 Prepare + +Set up the relevant recipients, then call our parent. + +=cut + + +sub Prepare { + my $self = shift; + $self->SetRecipients(); + $self->SUPER::Prepare(); +} =head2 SetRecipients @@ -40,93 +79,89 @@ Explicitly B<does not> notify the creator of the transaction by default sub SetRecipients { my $self = shift; - my $arg = $self->Argument; + my $ticket = $self->TicketObj; + my $arg = $self->Argument; $arg =~ s/\bAll\b/Owner,Requestor,AdminCc,Cc/; my ( @To, @PseudoTo, @Cc, @Bcc ); - if ($arg =~ /\bOtherRecipients\b/) { - if ($self->TransactionObj->Attachments->First) { - push (@Cc, $self->TransactionObj->Attachments->First->GetHeader('RT-Send-Cc')); - push (@Bcc, $self->TransactionObj->Attachments->First->GetHeader('RT-Send-Bcc')); + if ( $arg =~ /\bOtherRecipients\b/ ) { + if ( my $attachment = $self->TransactionObj->Attachments->First ) { + push @Cc, map { $_->address } Email::Address->parse( + $attachment->GetHeader('RT-Send-Cc') + ); + push @Bcc, map { $_->address } Email::Address->parse( + $attachment->GetHeader('RT-Send-Bcc') + ); } } if ( $arg =~ /\bRequestor\b/ ) { - push ( @To, $self->TicketObj->Requestors->MemberEmailAddresses ); + push @To, $ticket->Requestors->MemberEmailAddresses; } - - if ( $arg =~ /\bCc\b/ ) { #If we have a To, make the Ccs, Ccs, otherwise, promote them to To if (@To) { - push ( @Cc, $self->TicketObj->Cc->MemberEmailAddresses ); - push ( @Cc, $self->TicketObj->QueueObj->Cc->MemberEmailAddresses ); + push ( @Cc, $ticket->Cc->MemberEmailAddresses ); + push ( @Cc, $ticket->QueueObj->Cc->MemberEmailAddresses ); } else { - push ( @Cc, $self->TicketObj->Cc->MemberEmailAddresses ); - push ( @To, $self->TicketObj->QueueObj->Cc->MemberEmailAddresses ); + push ( @Cc, $ticket->Cc->MemberEmailAddresses ); + push ( @To, $ticket->QueueObj->Cc->MemberEmailAddresses ); } } - if ( ( $arg =~ /\bOwner\b/ ) - && ( $self->TicketObj->OwnerObj->id != $RT::Nobody->id ) ) - { - - # If we're not sending to Ccs or requestors, + if ( $arg =~ /\bOwner\b/ && $ticket->OwnerObj->id != $RT::Nobody->id ) { + # If we're not sending to Ccs or requestors, # then the Owner can be the To. if (@To) { - push ( @Bcc, $self->TicketObj->OwnerObj->EmailAddress ); + push ( @Bcc, $ticket->OwnerObj->EmailAddress ); } else { - push ( @To, $self->TicketObj->OwnerObj->EmailAddress ); + push ( @To, $ticket->OwnerObj->EmailAddress ); } } if ( $arg =~ /\bAdminCc\b/ ) { - push ( @Bcc, $self->TicketObj->AdminCc->MemberEmailAddresses ); - push ( @Bcc, $self->TicketObj->QueueObj->AdminCc->MemberEmailAddresses ); + push ( @Bcc, $ticket->AdminCc->MemberEmailAddresses ); + push ( @Bcc, $ticket->QueueObj->AdminCc->MemberEmailAddresses ); } - if ($RT::UseFriendlyToLine) { + if ( RT->Config->Get('UseFriendlyToLine') ) { unless (@To) { - push ( - @PseudoTo, - sprintf($RT::FriendlyToLineFormat, $arg, $self->TicketObj->id), - ); + push @PseudoTo, + sprintf RT->Config->Get('FriendlyToLineFormat'), $arg, $ticket->id; } } - my $creator = $self->TransactionObj->CreatorObj->EmailAddress(); + my $creatorObj = $self->TransactionObj->CreatorObj; + my $creator = $creatorObj->EmailAddress(); #Strip the sender out of the To, Cc and AdminCc and set the # recipients fields used to build the message by the superclass. # unless a flag is set - if ($RT::NotifyActor) { + my $TransactionCurrentUser = RT::CurrentUser->new; + $TransactionCurrentUser->LoadByName($creatorObj->Name); + if (RT->Config->Get('NotifyActor',$TransactionCurrentUser)) { @{ $self->{'To'} } = @To; @{ $self->{'Cc'} } = @Cc; @{ $self->{'Bcc'} } = @Bcc; } else { - @{ $self->{'To'} } = grep ( !/^$creator$/, @To ); - @{ $self->{'Cc'} } = grep ( !/^$creator$/, @Cc ); - @{ $self->{'Bcc'} } = grep ( !/^$creator$/, @Bcc ); + @{ $self->{'To'} } = grep ( lc $_ ne lc $creator, @To ); + @{ $self->{'Cc'} } = grep ( lc $_ ne lc $creator, @Cc ); + @{ $self->{'Bcc'} } = grep ( lc $_ ne lc $creator, @Bcc ); } @{ $self->{'PseudoTo'} } = @PseudoTo; - return (1); -} -# }}} +} -eval "require RT::Action::Notify_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Notify_Vendor.pm}); -eval "require RT::Action::Notify_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/Notify_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Action/NotifyAsComment.pm b/rt/lib/RT/Action/NotifyAsComment.pm index 210e4ab15..504d139c0 100755 --- a/rt/lib/RT/Action/NotifyAsComment.pm +++ b/rt/lib/RT/Action/NotifyAsComment.pm @@ -1,55 +1,75 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + package RT::Action::NotifyAsComment; -require RT::Action::Notify; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Notify); +use warnings; +use base qw(RT::Action::Notify); =head2 SetReturnAddress -Tell SendEmail that this message should come out as a comment. +Tell SendEmail that this message should come out as a comment. Calls SUPER::SetReturnAddress. =cut sub SetReturnAddress { - my $self = shift; - - # Tell RT::Action::SendEmail that this should come - # from the relevant comment email address. - $self->{'comment'} = 1; - - return($self->SUPER::SetReturnAddress(is_comment => 1)); + my $self = shift; + + # Tell RT::Action::SendEmail that this should come + # from the relevant comment email address. + $self->{'comment'} = 1; + + return $self->SUPER::SetReturnAddress( @_, is_comment => 1 ); } -eval "require RT::Action::NotifyAsComment_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyAsComment_Vendor.pm}); -eval "require RT::Action::NotifyAsComment_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/NotifyAsComment_Local.pm}); +RT::Base->_ImportOverlays(); 1; - diff --git a/rt/lib/RT/Action/ResolveMembers.pm b/rt/lib/RT/Action/ResolveMembers.pm index 02ff3a58c..aff636558 100644 --- a/rt/lib/RT/Action/ResolveMembers.pm +++ b/rt/lib/RT/Action/ResolveMembers.pm @@ -1,35 +1,58 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # This Action will resolve all members of a resolved group ticket package RT::Action::ResolveMembers; -require RT::Action::Generic; +use base 'RT::Action'; require RT::Links; use strict; -use vars qw/@ISA/; -@ISA=qw(RT::Action::Generic); #Do what we need to do and send it out. @@ -79,10 +102,7 @@ sub IsApplicable { } # }}} -eval "require RT::Action::ResolveMembers_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/ResolveMembers_Vendor.pm}); -eval "require RT::Action::ResolveMembers_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/ResolveMembers_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Action/SendEmail.pm b/rt/lib/RT/Action/SendEmail.pm index dac8fc8e7..9e93e4aab 100755 --- a/rt/lib/RT/Action/SendEmail.pm +++ b/rt/lib/RT/Action/SendEmail.pm @@ -1,38 +1,65 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Portions Copyright 2000 Tobias Brox <tobix@cpan.org> package RT::Action::SendEmail; -require RT::Action::Generic; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Action::Generic); +use warnings; -use MIME::Words qw(encode_mimeword); +use base qw(RT::Action); use RT::EmailParser; +use RT::Interface::Email; +use Email::Address; +our @EMAIL_RECIPIENT_HEADERS = qw(To Cc Bcc); + =head1 NAME @@ -42,273 +69,495 @@ RT::Action::AutoReply is a good example subclass. =head1 SYNOPSIS - require RT::Action::SendEmail; - @ISA = qw(RT::Action::SendEmail); - + use base 'RT::Action::SendEmail'; =head1 DESCRIPTION Basically, you create another module RT::Action::YourAction which ISA RT::Action::SendEmail. -If you want to set the recipients of the mail to something other than -the addresses mentioned in the To, Cc, Bcc and headers in -the template, you should subclass RT::Action::SendEmail and override -either the SetRecipients method or the SetTo, SetCc, etc methods (see -the comments for the SetRecipients sub). +=head1 METHODS +=head2 CleanSlate -=begin testing +Cleans class-wide options, like L</SquelchMailTo> or L</AttachTickets>. -ok (require RT::Action::SendEmail); +=cut -=end testing +sub CleanSlate { + my $self = shift; + $self->SquelchMailTo(undef); + $self->AttachTickets(undef); +} +=head2 Commit -=head1 AUTHOR +Sends the prepared message and writes outgoing record into DB if the feature is +activated in the config. -Jesse Vincent <jesse@bestpractical.com> and Tobias Brox <tobix@cpan.org> +=cut -=head1 SEE ALSO +sub Commit { + my $self = shift; -perl(1). + $self->DeferDigestRecipients() if RT->Config->Get('RecordOutgoingEmail'); + my $message = $self->TemplateObj->MIMEObj; + + my $orig_message; + if ( RT->Config->Get('RecordOutgoingEmail') + && RT->Config->Get('GnuPG')->{'Enable'} ) + { + + # it's hacky, but we should know if we're going to crypt things + my $attachment = $self->TransactionObj->Attachments->First; + + my %crypt; + foreach my $argument (qw(Sign Encrypt)) { + if ( $attachment + && defined $attachment->GetHeader("X-RT-$argument") ) + { + $crypt{$argument} = $attachment->GetHeader("X-RT-$argument"); + } else { + $crypt{$argument} = $self->TicketObj->QueueObj->$argument(); + } + } + if ( $crypt{'Sign'} || $crypt{'Encrypt'} ) { + $orig_message = $message->dup; + } + } -=cut + my ($ret) = $self->SendMessage($message); + if ( $ret > 0 && RT->Config->Get('RecordOutgoingEmail') ) { + if ($orig_message) { + $message->attach( + Type => 'application/x-rt-original-message', + Disposition => 'inline', + Data => $orig_message->as_string, + ); + } + $self->RecordOutgoingMailTransaction($message); + $self->RecordDeferredRecipients(); + } -# {{{ Scrip methods (_Init, Commit, Prepare, IsApplicable) -# {{{ sub _Init -# We use _Init from RT::Action -# }}} + return ( abs $ret ); +} -# {{{ sub Commit -#Do what we need to do and send it out. -sub Commit { - my $self = shift; +=head2 Prepare - my $MIMEObj = $self->TemplateObj->MIMEObj; - my $msgid = $MIMEObj->head->get('Message-Id'); - chomp $msgid; - $RT::Logger->info($msgid." #".$self->TicketObj->id."/".$self->TransactionObj->id." - Scrip ". $self->ScripObj->id ." ".$self->ScripObj->Description); - #send the email +Builds an outgoing email we're going to send using scrip's template. - # Weed out any RT addresses. We really don't want to talk to ourselves! - @{$self->{'To'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'To'}}); - @{$self->{'Cc'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'Cc'}}); - @{$self->{'Bcc'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'Bcc'}}); - # If there are no recipients, don't try to send the message. - # If the transaction has content and has the header RT-Squelch-Replies-To +=cut + +sub Prepare { + my $self = shift; - if ( defined $self->TransactionObj->Attachments->First() ) { + my ( $result, $message ) = $self->TemplateObj->Parse( + Argument => $self->Argument, + TicketObj => $self->TicketObj, + TransactionObj => $self->TransactionObj + ); + if ( !$result ) { + return (undef); + } - my $squelch = $self->TransactionObj->Attachments->First->GetHeader( 'RT-Squelch-Replies-To'); + my $MIMEObj = $self->TemplateObj->MIMEObj; - if ($squelch) { - my @blacklist = split ( /,/, $squelch ); + # Header + $self->SetRTSpecialHeaders(); - # Cycle through the people we're sending to and pull out anyone on the - # system blacklist + $self->RemoveInappropriateRecipients(); - foreach my $person_to_yank (@blacklist) { - $person_to_yank =~ s/\s//g; - @{ $self->{'To'} } = - grep ( !/^$person_to_yank$/, @{ $self->{'To'} } ); - @{ $self->{'Cc'} } = - grep ( !/^$person_to_yank$/, @{ $self->{'Cc'} } ); - @{ $self->{'Bcc'} } = - grep ( !/^$person_to_yank$/, @{ $self->{'Bcc'} } ); - } - } + my %seen; + foreach my $type (@EMAIL_RECIPIENT_HEADERS) { + @{ $self->{$type} } + = grep defined && length && !$seen{ lc $_ }++, + @{ $self->{$type} }; } # Go add all the Tos, Ccs and Bccs that we need to to the message to # make it happy, but only if we actually have values in those arrays. - $self->SetHeader( 'To', join ( ',', @{ $self->{'To'} } ) ) - if ( $self->{'To'} && @{ $self->{'To'} } ); - $self->SetHeader( 'Cc', join ( ',', @{ $self->{'Cc'} } ) ) - if ( $self->{'Cc'} && @{ $self->{'Cc'} } ); - $self->SetHeader( 'Bcc', join ( ',', @{ $self->{'Bcc'} } ) ) - if ( $self->{'Cc'} && @{ $self->{'Bcc'} } ); +# TODO: We should be pulling the recipients out of the template and shove them into To, Cc and Bcc + for my $header (@EMAIL_RECIPIENT_HEADERS) { - $self->SetHeader('MIME-Version', '1.0'); + $self->SetHeader( $header, join( ', ', @{ $self->{$header} } ) ) + if (!$MIMEObj->head->get($header) + && $self->{$header} + && @{ $self->{$header} } ); + } + # PseudoTo (fake to headers) shouldn't get matched for message recipients. + # If we don't have any 'To' header (but do have other recipients), drop in + # the pseudo-to header. + $self->SetHeader( 'To', join( ', ', @{ $self->{'PseudoTo'} } ) ) + if $self->{'PseudoTo'} + && @{ $self->{'PseudoTo'} } + && !$MIMEObj->head->get('To') + && ( $MIMEObj->head->get('Cc') or $MIMEObj->head->get('Bcc') ); + + # We should never have to set the MIME-Version header + $self->SetHeader( 'MIME-Version', '1.0' ); + + # fsck.com #5959: Since RT sends 8bit mail, we should say so. + $self->SetHeader( 'Content-Transfer-Encoding', '8bit' ); + + # For security reasons, we only send out textual mails. + foreach my $part ( grep !$_->is_multipart, $MIMEObj->parts_DFS ) { + my $type = $part->mime_type || 'text/plain'; + $type = 'text/plain' unless RT::I18N::IsTextualContentType($type); + $part->head->mime_attr( "Content-Type" => $type ); + # utf-8 here is for _FindOrGuessCharset in I18N.pm + # it's not the final charset/encoding sent + $part->head->mime_attr( "Content-Type.charset" => 'utf-8' ); + } - # try to convert message body from utf-8 to $RT::EmailOutputEncoding - $self->SetHeader( 'Content-Type', 'text/plain; charset="utf-8"' ); + RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, + RT->Config->Get('EmailOutputEncoding'), + 'mime_words_ok', ); - RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding, 'mime_words_ok' ); - $self->SetHeader( 'Content-Type', 'text/plain; charset="' . $RT::EmailOutputEncoding . '"' ); + # Build up a MIME::Entity that looks like the original message. + $self->AddAttachments if ( $MIMEObj->head->get('RT-Attach-Message') + && ( $MIMEObj->head->get('RT-Attach-Message') !~ /^(n|no|0|off|false)$/i ) ); + + $self->AddTickets; + + my $attachment = $self->TransactionObj->Attachments->First; + if ($attachment + && !( + $attachment->GetHeader('X-RT-Encrypt') + || $self->TicketObj->QueueObj->Encrypt + ) + ) + { + $attachment->SetHeader( 'X-RT-Encrypt' => 1 ) + if ( $attachment->GetHeader("X-RT-Incoming-Encryption") || '' ) eq + 'Success'; + } + return $result; +} - # Build up a MIME::Entity that looks like the original message. +=head2 To - my $do_attach = $self->TemplateObj->MIMEObj->head->get('RT-Attach-Message'); +Returns an array of L<Email::Address> objects containing all the To: recipients for this notification - if ($do_attach) { - $self->TemplateObj->MIMEObj->head->delete('RT-Attach-Message'); +=cut - my $attachments = RT::Attachments->new($RT::SystemUser); - $attachments->Limit( FIELD => 'TransactionId', - VALUE => $self->TransactionObj->Id ); - $attachments->OrderBy('id'); +sub To { + my $self = shift; + return ( $self->AddressesFromHeader('To') ); +} - my $transaction_content_obj = $self->TransactionObj->ContentObj; +=head2 Cc - # attach any of this transaction's attachments - while ( my $attach = $attachments->Next ) { +Returns an array of L<Email::Address> objects containing all the Cc: recipients for this notification - # Don't attach anything blank - next unless ( $attach->ContentLength ); +=cut - # We want to make sure that we don't include the attachment that's being sued as the "Content" of this message" - next - if ( $transaction_content_obj - && $transaction_content_obj->Id == $attach->Id - && $transaction_content_obj->ContentType =~ qr{text/plain}i - ); - $MIMEObj->make_multipart('mixed'); - $MIMEObj->attach( Type => $attach->ContentType, - Charset => $attach->OriginalEncoding, - Data => $attach->OriginalContent, - Filename => $self->MIMEEncodeString( $attach->Filename, $RT::EmailOutputEncoding ), - Encoding => '-SUGGEST'); - } +sub Cc { + my $self = shift; + return ( $self->AddressesFromHeader('Cc') ); +} - } +=head2 Bcc +Returns an array of L<Email::Address> objects containing all the Bcc: recipients for this notification - my $retval = $self->SendMessage($MIMEObj); +=cut +sub Bcc { + my $self = shift; + return ( $self->AddressesFromHeader('Bcc') ); - return ($retval); } -# }}} +sub AddressesFromHeader { + my $self = shift; + my $field = shift; + my $header = $self->TemplateObj->MIMEObj->head->get($field); + my @addresses = Email::Address->parse($header); + + return (@addresses); +} -# {{{ sub Prepare +=head2 SendMessage MIMEObj -sub Prepare { - my $self = shift; +sends the message using RT's preferred API. +TODO: Break this out to a separate module - # This actually populates the MIME::Entity fields in the Template Object +=cut - unless ( $self->TemplateObj ) { - $RT::Logger->warning("No template object handed to $self\n"); - } +sub SendMessage { - unless ( $self->TransactionObj ) { - $RT::Logger->warning("No transaction object handed to $self\n"); + # DO NOT SHIFT @_ in this subroutine. It breaks Hook::LexWrap's + # ability to pass @_ to a 'post' routine. + my ( $self, $MIMEObj ) = @_; - } + my $msgid = $MIMEObj->head->get('Message-ID'); + chomp $msgid; + + $self->ScripActionObj->{_Message_ID}++; + + $RT::Logger->info( $msgid . " #" + . $self->TicketObj->id . "/" + . $self->TransactionObj->id + . " - Scrip " + . ($self->ScripObj->id || '#rule'). " " + . ( $self->ScripObj->Description || '' ) ); - unless ( $self->TicketObj ) { - $RT::Logger->warning("No ticket object handed to $self\n"); + my $status = RT::Interface::Email::SendEmail( + Entity => $MIMEObj, + Ticket => $self->TicketObj, + Transaction => $self->TransactionObj, + ); + + + return $status unless ($status > 0 || exists $self->{'Deferred'}); + my $success = $msgid . " sent "; + foreach (@EMAIL_RECIPIENT_HEADERS) { + my $recipients = $MIMEObj->head->get($_); + $success .= " $_: " . $recipients if $recipients; } - my ( $result, $message ) = $self->TemplateObj->Parse( - Argument => $self->Argument, - TicketObj => $self->TicketObj, - TransactionObj => $self->TransactionObj + if( exists $self->{'Deferred'} ) { + for (qw(daily weekly susp)) { + $success .= "\nBatched email $_ for: ". join(", ", keys %{ $self->{'Deferred'}{ $_ } } ) + if exists $self->{'Deferred'}{ $_ }; + } + } + + $success =~ s/\n//g; + + $RT::Logger->info($success); + + return (1); +} + +=head2 AddAttachments + +Takes any attachments to this transaction and attaches them to the message +we're building. + +=cut + +sub AddAttachments { + my $self = shift; + + my $MIMEObj = $self->TemplateObj->MIMEObj; + + $MIMEObj->head->delete('RT-Attach-Message'); + + my $attachments = RT::Attachments->new($RT::SystemUser); + $attachments->Limit( + FIELD => 'TransactionId', + VALUE => $self->TransactionObj->Id ); - if ($result) { - - # Header - $self->SetSubject(); - $self->SetSubjectToken(); - $self->SetRecipients(); - $self->SetReturnAddress(); - $self->SetRTSpecialHeaders(); - if ($RT::EmailOutputEncoding) { - - # l10n related header - $self->SetHeaderAsEncoding( 'Subject', $RT::EmailOutputEncoding ); + + # Don't attach anything blank + $attachments->LimitNotEmpty; + $attachments->OrderBy( FIELD => 'id' ); + + # We want to make sure that we don't include the attachment that's + # being used as the "Content" of this message" unless that attachment's + # content type is not like text/... + my $transaction_content_obj = $self->TransactionObj->ContentObj; + + if ( $transaction_content_obj + && $transaction_content_obj->ContentType =~ m{text/}i ) + { + # If this was part of a multipart/alternative, skip all of the kids + my $parent = $transaction_content_obj->ParentObj; + if ($parent and $parent->Id and $parent->ContentType eq "multipart/alternative") { + $attachments->Limit( + ENTRYAGGREGATOR => 'AND', + FIELD => 'parent', + OPERATOR => '!=', + VALUE => $parent->Id, + ); + } else { + $attachments->Limit( + ENTRYAGGREGATOR => 'AND', + FIELD => 'id', + OPERATOR => '!=', + VALUE => $transaction_content_obj->Id, + ); } } - return $result; + # attach any of this transaction's attachments + my $seen_attachment = 0; + while ( my $attach = $attachments->Next ) { + if ( !$seen_attachment ) { + $MIMEObj->make_multipart( 'mixed', Force => 1 ); + $seen_attachment = 1; + } + $self->AddAttachment($attach); + } +} + +=head2 AddAttachment $attachment + +Takes one attachment object of L<RT::Attachmment> class and attaches it to the message +we're building. + +=cut +sub AddAttachment { + my $self = shift; + my $attach = shift; + my $MIMEObj = shift || $self->TemplateObj->MIMEObj; + + $MIMEObj->attach( + Type => $attach->ContentType, + Charset => $attach->OriginalEncoding, + Data => $attach->OriginalContent, + Filename => $self->MIMEEncodeString( $attach->Filename ), + 'RT-Attachment:' => $self->TicketObj->Id . "/" + . $self->TransactionObj->Id . "/" + . $attach->id, + Encoding => '-SUGGEST', + ); } -# }}} +=head2 AttachTickets [@IDs] -# }}} +Returns or set list of ticket's IDs that should be attached to an outgoing message. -# {{{ SendMessage -=head2 SendMessage MIMEObj +B<Note> this method works as a class method and setup things global, so you have to +clean list by passing undef as argument. -sends the message using RT's preferred API. -TODO: Break this out to a seperate module +=cut + +{ + my $list = []; + + sub AttachTickets { + my $self = shift; + $list = [ grep defined, @_ ] if @_; + return @$list; + } +} + +=head2 AddTickets + +Attaches tickets to the current message, list of tickets' ids get from +L</AttachTickets> method. =cut -sub SendMessage { +sub AddTickets { my $self = shift; - my $MIMEObj = shift; + $self->AddTicket($_) foreach $self->AttachTickets; + return; +} - my $msgid = $MIMEObj->head->get('Message-Id'); +=head2 AddTicket $ID +Attaches a ticket with ID to the message. - #If we don't have any recipients to send to, don't send a message; - unless ( $MIMEObj->head->get('To') - || $MIMEObj->head->get('Cc') - || $MIMEObj->head->get('Bcc') ) { - $RT::Logger->info($msgid. " No recipients found. Not sending.\n"); - return (1); - } +Each ticket is attached as multipart entity and all its messages and attachments +are attached as sub entities in order of creation, but only if transaction type +is Create or Correspond. - # PseudoTo (fake to headers) shouldn't get matched for message recipients. - # If we don't have any 'To' header, drop in the pseudo-to header. +=cut - $self->SetHeader( 'To', join ( ',', @{ $self->{'PseudoTo'} } ) ) - if ( $self->{'PseudoTo'} && ( @{ $self->{'PseudoTo'} } ) - and ( !$MIMEObj->head->get('To') ) ); - if ( $RT::MailCommand eq 'sendmailpipe' ) { - eval { - open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" ); - print MAIL $MIMEObj->as_string; - close(MAIL); - }; - if ($@) { - $RT::Logger->crit($msgid. "Could not send mail. -".$@ ); - } +sub AddTicket { + my $self = shift; + my $tid = shift; + + # XXX: we need a current user here, but who is current user? + my $attachs = RT::Attachments->new($RT::SystemUser); + my $txn_alias = $attachs->TransactionAlias; + $attachs->Limit( ALIAS => $txn_alias, FIELD => 'Type', VALUE => 'Create' ); + $attachs->Limit( + ALIAS => $txn_alias, + FIELD => 'Type', + VALUE => 'Correspond' + ); + $attachs->LimitByTicket($tid); + $attachs->LimitNotEmpty; + $attachs->OrderBy( FIELD => 'Created' ); + + my $ticket_mime = MIME::Entity->build( + Type => 'multipart/mixed', + Top => 0, + Description => "ticket #$tid", + ); + while ( my $attachment = $attachs->Next ) { + $self->AddAttachment( $attachment, $ticket_mime ); } - else { - my @mailer_args = ($RT::MailCommand); - local $ENV{MAILADDRESS}; + if ( $ticket_mime->parts ) { + my $email_mime = $self->TemplateObj->MIMEObj; + $email_mime->make_multipart; + $email_mime->add_part($ticket_mime); + } + return; +} - if ( $RT::MailCommand eq 'sendmail' ) { - push @mailer_args, $RT::SendmailArguments; - } - elsif ( $RT::MailCommand eq 'smtp' ) { - $ENV{MAILADDRESS} = $RT::SMTPFrom || $MIMEObj->head->get('From'); - push @mailer_args, (Server => $RT::SMTPServer); - push @mailer_args, (Debug => $RT::SMTPDebug); - } - else { - push @mailer_args, $RT::MailParams; - } +=head2 RecordOutgoingMailTransaction MIMEObj + +Record a transaction in RT with this outgoing message for future record-keeping purposes + +=cut + +sub RecordOutgoingMailTransaction { + my $self = shift; + my $MIMEObj = shift; - unless ( $MIMEObj->send( @mailer_args ) ) { - $RT::Logger->crit($msgid. "Could not send mail." ); - return (0); + my @parts = $MIMEObj->parts; + my @attachments; + my @keep; + foreach my $part (@parts) { + my $attach = $part->head->get('RT-Attachment'); + if ($attach) { + $RT::Logger->debug( + "We found an attachment. we want to not record it."); + push @attachments, $attach; + } else { + $RT::Logger->debug("We found a part. we want to record it."); + push @keep, $part; } } + $MIMEObj->parts( \@keep ); + foreach my $attachment (@attachments) { + $MIMEObj->head->add( 'RT-Attachment', $attachment ); + } + RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, 'utf-8', 'mime_words_ok' ); - my $success = ($msgid. " sent To: ".$MIMEObj->head->get('To') . " Cc: ".$MIMEObj->head->get('Cc') . " Bcc: ".$MIMEObj->head->get('Bcc')); - $success =~ s/\n//gi; - $RT::Logger->info($success); + my $transaction + = RT::Transaction->new( $self->TransactionObj->CurrentUser ); - return (1); -} +# XXX: TODO -> Record attachments as references to things in the attachments table, maybe. + + my $type; + if ( $self->TransactionObj->Type eq 'Comment' ) { + $type = 'CommentEmailRecord'; + } else { + $type = 'EmailRecord'; + } -# }}} + my $msgid = $MIMEObj->head->get('Message-ID'); + chomp $msgid; -# {{{ Deal with message headers (Set* subs, designed for easy overriding) + my ( $id, $msg ) = $transaction->Create( + Ticket => $self->TicketObj->Id, + Type => $type, + Data => $msgid, + MIMEObj => $MIMEObj, + ActivateScrips => 0 + ); -# {{{ sub SetRTSpecialHeaders + if ($id) { + $self->{'OutgoingMailTransaction'} = $id; + } else { + $RT::Logger->warning( + "Could not record outgoing message transaction: $msg"); + } + return $id; +} =head2 SetRTSpecialHeaders @@ -320,85 +569,272 @@ that don't matter much to anybody else. sub SetRTSpecialHeaders { my $self = shift; - $self->SetReferences(); + $self->SetSubject(); + $self->SetSubjectToken(); + $self->SetHeaderAsEncoding( 'Subject', + RT->Config->Get('EmailOutputEncoding') ) + if ( RT->Config->Get('EmailOutputEncoding') ); + $self->SetReturnAddress(); + $self->SetReferencesHeaders(); + + unless ( $self->TemplateObj->MIMEObj->head->get('Message-ID') ) { + + # Get Message-ID for this txn + my $msgid = ""; + if ( my $msg = $self->TransactionObj->Message->First ) { + $msgid = $msg->GetHeader("RT-Message-ID") + || $msg->GetHeader("Message-ID"); + } - $self->SetMessageID(); + # If there is one, and we can parse it, then base our Message-ID on it + if ( $msgid + and $msgid + =~ s/<(rt-.*?-\d+-\d+)\.(\d+)-\d+-\d+\@\QRT->Config->Get('Organization')\E>$/ + "<$1." . $self->TicketObj->id + . "-" . $self->ScripObj->id + . "-" . $self->ScripActionObj->{_Message_ID} + . "@" . RT->Config->Get('Organization') . ">"/eg + and $2 == $self->TicketObj->id + ) + { + $self->SetHeader( "Message-ID" => $msgid ); + } else { + $self->SetHeader( + 'Message-ID' => RT::Interface::Email::GenMessageId( + Ticket => $self->TicketObj, + Scrip => $self->ScripObj, + ScripAction => $self->ScripActionObj + ), + ); + } + } - $self->SetPrecedence(); + if (my $precedence = RT->Config->Get('DefaultMailPrecedence') + and !$self->TemplateObj->MIMEObj->head->get("Precedence") + ) { + $self->SetHeader( 'Precedence', $precedence ); + } - $self->SetHeader( 'X-RT-Loop-Prevention', $RT::rtname ); + $self->SetHeader( 'X-RT-Loop-Prevention', RT->Config->Get('rtname') ); $self->SetHeader( 'RT-Ticket', - $RT::rtname . " #" . $self->TicketObj->id() ); + RT->Config->Get('rtname') . " #" . $self->TicketObj->id() ); $self->SetHeader( 'Managed-by', - "RT $RT::VERSION (http://www.bestpractical.com/rt/)" ); - - $self->SetHeader( 'RT-Originator', - $self->TransactionObj->CreatorObj->EmailAddress ); - return (); + "RT $RT::VERSION (http://www.bestpractical.com/rt/)" ); + +# XXX, TODO: use /ShowUser/ShowUserEntry(or something like that) when it would be +# refactored into user's method. + if ( my $email = $self->TransactionObj->CreatorObj->EmailAddress + and RT->Config->Get('UseOriginatorHeader') + ) { + $self->SetHeader( 'RT-Originator', $email ); + } } -# {{{ sub SetReferences -=head2 SetReferences - - # This routine will set the References: and In-Reply-To headers, -# autopopulating it with all the correspondence on this ticket so -# far. This should make RT responses threadable. +sub DeferDigestRecipients { + my $self = shift; + $RT::Logger->debug( "Calling SetRecipientDigests for transaction " . $self->TransactionObj . ", id " . $self->TransactionObj->id ); + + # The digest attribute will be an array of notifications that need to + # be sent for this transaction. The array will have the following + # format for its objects. + # $digest_hash -> {daily|weekly|susp} -> address -> {To|Cc|Bcc} + # -> sent -> {true|false} + # The "sent" flag will be used by the cron job to indicate that it has + # run on this transaction. + # In a perfect world we might move this hash construction to the + # extension module itself. + my $digest_hash = {}; + + foreach my $mailfield (@EMAIL_RECIPIENT_HEADERS) { + # If we have a "PseudoTo", the "To" contains it, so we don't need to access it + next if ( ( $self->{'PseudoTo'} && @{ $self->{'PseudoTo'} } ) && ( $mailfield eq 'To' ) ); + $RT::Logger->debug( "Working on mailfield $mailfield; recipients are " . join( ',', @{ $self->{$mailfield} } ) ); + + # Store the 'daily digest' folk in an array. + my ( @send_now, @daily_digest, @weekly_digest, @suspended ); + + # Have to get the list of addresses directly from the MIME header + # at this point. + $RT::Logger->debug( $self->TemplateObj->MIMEObj->head->as_string ); + foreach my $rcpt ( map { $_->address } $self->AddressesFromHeader($mailfield) ) { + next unless $rcpt; + my $user_obj = RT::User->new($RT::SystemUser); + $user_obj->LoadByEmail($rcpt); + if ( ! $user_obj->id ) { + # If there's an email address in here without an associated + # RT user, pass it on through. + $RT::Logger->debug( "User $rcpt is not associated with an RT user object. Send mail."); + push( @send_now, $rcpt ); + next; + } -=cut + my $mailpref = RT->Config->Get( 'EmailFrequency', $user_obj ) || ''; + $RT::Logger->debug( "Got user mail preference '$mailpref' for user $rcpt"); + + if ( $mailpref =~ /daily/i ) { push( @daily_digest, $rcpt ) } + elsif ( $mailpref =~ /weekly/i ) { push( @weekly_digest, $rcpt ) } + elsif ( $mailpref =~ /suspend/i ) { push( @suspended, $rcpt ) } + else { push( @send_now, $rcpt ) } + } + + # Reset the relevant mail field. + $RT::Logger->debug( "Removing deferred recipients from $mailfield: line"); + if (@send_now) { + $self->SetHeader( $mailfield, join( ', ', @send_now ) ); + } else { # No recipients! Remove the header. + $self->TemplateObj->MIMEObj->head->delete($mailfield); + } -sub SetReferences { + # Push the deferred addresses into the appropriate field in + # our attribute hash, with the appropriate mail header. + $RT::Logger->debug( + "Setting deferred recipients for attribute creation"); + $digest_hash->{'daily'}->{$_} = {'header' => $mailfield , _sent => 0} for (@daily_digest); + $digest_hash->{'weekly'}->{$_} ={'header' => $mailfield, _sent => 0} for (@weekly_digest); + $digest_hash->{'susp'}->{$_} = {'header' => $mailfield, _sent =>0 } for (@suspended); + } + + if ( scalar keys %$digest_hash ) { + + # Save the hash so that we can add it as an attribute to the + # outgoing email transaction. + $self->{'Deferred'} = $digest_hash; + } else { + $RT::Logger->debug( "No recipients found for deferred delivery on " + . "transaction #" + . $self->TransactionObj->id ); + } +} + + + +sub RecordDeferredRecipients { my $self = shift; + return unless exists $self->{'Deferred'}; - # TODO: this one is broken. What is this email really a reply to? - # If it's a reply to an incoming message, we'll need to use the - # actual message-id from the appropriate Attachment object. For - # incoming mails, we would like to preserve the In-Reply-To and/or - # References. + my $txn_id = $self->{'OutgoingMailTransaction'}; + return unless $txn_id; - $self->SetHeader( 'In-Reply-To', - "<rt-" . $self->TicketObj->id() . "\@" . $RT::rtname . ">" ); + my $txn_obj = RT::Transaction->new( $self->CurrentUser ); + $txn_obj->Load( $txn_id ); + my( $ret, $msg ) = $txn_obj->AddAttribute( + Name => 'DeferredRecipients', + Content => $self->{'Deferred'} + ); + $RT::Logger->warning( "Unable to add deferred recipients to outgoing transaction: $msg" ) + unless $ret; - # TODO We should always add References headers for all message-ids - # of previous messages related to this ticket. + return ($ret,$msg); } -# }}} +=head2 SquelchMailTo [@ADDRESSES] + +Mark ADDRESSES to be removed from list of the recipients. Returns list of the addresses. +To empty list pass undefined argument. -# {{{ sub SetMessageID +B<Note> that this method can be called as class method and works globaly. Don't forget to +clean this list when blocking is not required anymore, pass undef to do this. -=head2 SetMessageID +=cut + +{ + my $squelch = []; + + sub SquelchMailTo { + my $self = shift; + if (@_) { + $squelch = [ grep defined, @_ ]; + } + return @$squelch; + } +} -Without this one, threading won't work very nice in email agents. -Anyway, I'm not really sure it's that healthy if we need to send -several separate/different emails about the same transaction. +=head2 RemoveInappropriateRecipients + +Remove addresses that are RT addresses or that are on this transaction's blacklist =cut -sub SetMessageID { +sub RemoveInappropriateRecipients { my $self = shift; - # TODO this one might be sort of broken. If we have several scrips +++ - # sending several emails to several different persons, we need to - # pull out different message-ids. I'd suggest message ids like - # "rt-ticket#-transaction#-scrip#-receipient#" - - $self->SetHeader( 'Message-ID', - "<rt-" - . $RT::VERSION ."-" - . $self->TicketObj->id() . "-" - . $self->TransactionObj->id() . "." - . rand(20) . "\@" - . $RT::Organization . ">" ) - unless $self->TemplateObj->MIMEObj->head->get('Message-ID'); -} + my @blacklist = (); -# }}} + # If there are no recipients, don't try to send the message. + # If the transaction has content and has the header RT-Squelch-Replies-To + + my $msgid = $self->TemplateObj->MIMEObj->head->get('Message-Id'); + if ( my $attachment = $self->TransactionObj->Attachments->First ) { + + if ( $attachment->GetHeader('RT-DetectedAutoGenerated') ) { + + # What do we want to do with this? It's probably (?) a bounce + # caused by one of the watcher addresses being broken. + # Default ("true") is to redistribute, for historical reasons. + + if ( !RT->Config->Get('RedistributeAutoGeneratedMessages') ) { + + # Don't send to any watchers. + @{ $self->{$_} } = () for (@EMAIL_RECIPIENT_HEADERS); + $RT::Logger->info( $msgid + . " The incoming message was autogenerated. " + . "Not redistributing this message based on site configuration." + ); + } elsif ( RT->Config->Get('RedistributeAutoGeneratedMessages') eq + 'privileged' ) + { + + # Only send to "privileged" watchers. + foreach my $type (@EMAIL_RECIPIENT_HEADERS) { + foreach my $addr ( @{ $self->{$type} } ) { + my $user = RT::User->new($RT::SystemUser); + $user->LoadByEmail($addr); + push @blacklist, $addr if ( !$user->Privileged ); + } + } + $RT::Logger->info( $msgid + . " The incoming message was autogenerated. " + . "Not redistributing this message to unprivileged users based on site configuration." + ); + } + } + + if ( my $squelch = $attachment->GetHeader('RT-Squelch-Replies-To') ) { + push @blacklist, split( /,/, $squelch ); + } + } + +# Let's grab the SquelchMailTo attribue and push those entries into the @blacklist + push @blacklist, map $_->Content, $self->TicketObj->SquelchMailTo; + push @blacklist, $self->SquelchMailTo; + + # Cycle through the people we're sending to and pull out anyone on the + # system blacklist -# }}} + # Trim leading and trailing spaces. + @blacklist = map { RT::User->CanonicalizeEmailAddress( $_->address ) } Email::Address->parse(join(', ', grep {defined} @blacklist)); -# {{{ sub SetReturnAddress + foreach my $type (@EMAIL_RECIPIENT_HEADERS) { + my @addrs; + foreach my $addr ( @{ $self->{$type} } ) { + + # Weed out any RT addresses. We really don't want to talk to ourselves! + # If we get a reply back, that means it's not an RT address + if ( !RT::EmailParser->CullRTAddresses($addr) ) { + $RT::Logger->info( $msgid . "$addr appears to point to this RT instance. Skipping" ); + next; + } + if ( grep /^\Q$addr\E$/, @blacklist ) { + $RT::Logger->info( $msgid . "$addr was blacklisted for outbound mail on this transaction. Skipping"); + next; + } + push @addrs, $addr; + } + @{ $self->{$type} } = @addrs; + } +} =head2 SetReturnAddress is_comment => BOOLEAN @@ -409,8 +845,11 @@ Calculate and set From and Reply-To headers based on the is_comment flag. sub SetReturnAddress { my $self = shift; - my %args = ( is_comment => 0, - @_ ); + my %args = ( + is_comment => 0, + friendly_name => undef, + @_ + ); # From and Reply-To # $args{is_comment} should be set if the comment address is to be used. @@ -418,29 +857,37 @@ sub SetReturnAddress { if ( $args{'is_comment'} ) { $replyto = $self->TicketObj->QueueObj->CommentAddress - || $RT::CommentAddress; - } - else { + || RT->Config->Get('CommentAddress'); + } else { $replyto = $self->TicketObj->QueueObj->CorrespondAddress - || $RT::CorrespondAddress; + || RT->Config->Get('CorrespondAddress'); } unless ( $self->TemplateObj->MIMEObj->head->get('From') ) { - if ($RT::UseFriendlyFromLine) { - my $friendly_name = $self->TransactionObj->CreatorObj->RealName; - if ( $friendly_name =~ /^"(.*)"$/ ) { # a quoted string - $friendly_name = $1; - } - - $friendly_name =~ s/"/\\"/g; - $self->SetHeader( 'From', - sprintf($RT::FriendlyFromLineFormat, - $self->MIMEEncodeString( $friendly_name, $RT::EmailOutputEncoding ), $replyto), - ); - } - else { - $self->SetHeader( 'From', $replyto ); - } + if ( RT->Config->Get('UseFriendlyFromLine') ) { + my $friendly_name = $args{friendly_name}; + + unless ( $friendly_name ) { + $friendly_name = $self->TransactionObj->CreatorObj->FriendlyName; + if ( $friendly_name =~ /^"(.*)"$/ ) { # a quoted string + $friendly_name = $1; + } + } + + $friendly_name =~ s/"/\\"/g; + $self->SetHeader( + 'From', + sprintf( + RT->Config->Get('FriendlyFromLineFormat'), + $self->MIMEEncodeString( + $friendly_name, RT->Config->Get('EmailOutputEncoding') + ), + $replyto + ), + ); + } else { + $self->SetHeader( 'From', $replyto ); + } } unless ( $self->TemplateObj->MIMEObj->head->get('Reply-To') ) { @@ -449,10 +896,6 @@ sub SetReturnAddress { } -# }}} - -# {{{ sub SetHeader - =head2 SetHeader FIELD, VALUE Set the FIELD of the current MIME object into VALUE. @@ -466,163 +909,157 @@ sub SetHeader { chomp $val; chomp $field; - $self->TemplateObj->MIMEObj->head->fold_length( $field, 10000 ); - $self->TemplateObj->MIMEObj->head->replace( $field, $val ); - return $self->TemplateObj->MIMEObj->head->get($field); + my $head = $self->TemplateObj->MIMEObj->head; + $head->fold_length( $field, 10000 ); + $head->replace( $field, $val ); + return $head->get($field); } -# }}} - -# {{{ sub SetRecipients - -=head2 SetRecipients +=head2 SetSubject -Dummy method to be overriden by subclasses which want to set the recipients. +This routine sets the subject. it does not add the rt tag. That gets done elsewhere +If subject is already defined via template, it uses that. otherwise, it tries to get +the transaction's subject. -=cut +=cut -sub SetRecipients { +sub SetSubject { my $self = shift; - return (); -} + my $subject; -# }}} + if ( $self->TemplateObj->MIMEObj->head->get('Subject') ) { + return (); + } -# {{{ sub SetTo + # don't use Transaction->Attachments because it caches + # and anything which later calls ->Attachments will be hurt + # by our RowsPerPage() call. caching is hard. + my $message = RT::Attachments->new( $self->CurrentUser ); + $message->Limit( FIELD => 'TransactionId', VALUE => $self->TransactionObj->id); + $message->OrderBy( FIELD => 'id', ORDER => 'ASC' ); + $message->RowsPerPage(1); + + if ( $self->{'Subject'} ) { + $subject = $self->{'Subject'}; + } elsif ( my $first = $message->First ) { + my $tmp = $first->GetHeader('Subject'); + $subject = defined $tmp ? $tmp : $self->TicketObj->Subject; + } else { + $subject = $self->TicketObj->Subject; + } + $subject = '' unless defined $subject; + chomp $subject; -=head2 SetTo + $subject =~ s/(\r\n|\n|\s)/ /g; -Takes a string that is the addresses you want to send mail to + $self->SetHeader( 'Subject', $subject ); -=cut - -sub SetTo { - my $self = shift; - my $addresses = shift; - return $self->SetHeader( 'To', $addresses ); } -# }}} - -# {{{ sub SetCc - -=head2 SetCc +=head2 SetSubjectToken -Takes a string that is the addresses you want to Cc +This routine fixes the RT tag in the subject. It's unlikely that you want to overwrite this. =cut -sub SetCc { - my $self = shift; - my $addresses = shift; +sub SetSubjectToken { + my $self = shift; - return $self->SetHeader( 'Cc', $addresses ); + my $head = $self->TemplateObj->MIMEObj->head; + $head->replace( + Subject => RT::Interface::Email::AddSubjectTag( + Encode::decode_utf8( $head->get('Subject') ), + $self->TicketObj, + ), + ); } -# }}} - -# {{{ sub SetBcc - -=head2 SetBcc +=head2 SetReferencesHeaders -Takes a string that is the addresses you want to Bcc +Set References and In-Reply-To headers for this message. =cut -sub SetBcc { - my $self = shift; - my $addresses = shift; - - return $self->SetHeader( 'Bcc', $addresses ); -} - -# }}} - -# {{{ sub SetPrecedence - -sub SetPrecedence { +sub SetReferencesHeaders { my $self = shift; - - unless ( $self->TemplateObj->MIMEObj->head->get("Precedence") ) { - $self->SetHeader( 'Precedence', "bulk" ); + my ( @in_reply_to, @references, @msgid ); + + if ( my $top = $self->TransactionObj->Message->First ) { + @in_reply_to = split( /\s+/m, $top->GetHeader('In-Reply-To') || '' ); + @references = split( /\s+/m, $top->GetHeader('References') || '' ); + @msgid = split( /\s+/m, $top->GetHeader('Message-ID') || '' ); + } else { + return (undef); } -} -# }}} + # There are two main cases -- this transaction was created with + # the RT Web UI, and hence we want to *not* append its Message-ID + # to the References and In-Reply-To. OR it came from an outside + # source, and we should treat it as per the RFC + my $org = RT->Config->Get('Organization'); + if ( "@msgid" =~ /<(rt-.*?-\d+-\d+)\.(\d+)-0-0\@\Q$org\E>/ ) { + + # Make all references which are internal be to version which we + # have sent out + + for ( @references, @in_reply_to ) { + s/<(rt-.*?-\d+-\d+)\.(\d+-0-0)\@\Q$org\E>$/ + "<$1." . $self->TicketObj->id . + "-" . $self->ScripObj->id . + "-" . $self->ScripActionObj->{_Message_ID} . + "@" . $org . ">"/eg + } -# {{{ sub SetSubject + # In reply to whatever the internal message was in reply to + $self->SetHeader( 'In-Reply-To', join( " ", (@in_reply_to) ) ); -=head2 SetSubject + # Default the references to whatever we're in reply to + @references = @in_reply_to unless @references; -This routine sets the subject. it does not add the rt tag. that gets done elsewhere -If $self->{'Subject'} is already defined, it uses that. otherwise, it tries to get -the transaction's subject. + # References are unchanged from internal + } else { -=cut + # In reply to that message + $self->SetHeader( 'In-Reply-To', join( " ", (@msgid) ) ); -sub SetSubject { - my $self = shift; - my $subject; - - unless ( $self->TemplateObj->MIMEObj->head->get('Subject') ) { - my $message = $self->TransactionObj->Attachments; - my $ticket = $self->TicketObj->Id; + # Default the references to whatever we're in reply to + @references = @in_reply_to unless @references; - if ( $self->{'Subject'} ) { - $subject = $self->{'Subject'}; - } - elsif ( ( $message->First() ) - && ( $message->First->Headers ) ) { - my $header = $message->First->Headers(); - $header =~ s/\n\s+/ /g; - if ( $header =~ /^Subject: (.*?)$/m ) { - $subject = $1; - } - else { - $subject = $self->TicketObj->Subject(); - } + # Push that message onto the end of the references + push @references, @msgid; + } - } - else { - $subject = $self->TicketObj->Subject(); - } + # Push pseudo-ref to the front + my $pseudo_ref = $self->PseudoReference; + @references = ( $pseudo_ref, grep { $_ ne $pseudo_ref } @references ); - $subject =~ s/(\r\n|\n|\s)/ /gi; + # If there are more than 10 references headers, remove all but the + # first four and the last six (Gotta keep this from growing + # forever) + splice( @references, 4, -6 ) if ( $#references >= 10 ); - chomp $subject; - $self->SetHeader( 'Subject', $subject ); + # Add on the references + $self->SetHeader( 'References', join( " ", @references ) ); + $self->TemplateObj->MIMEObj->head->fold_length( 'References', 80 ); - } - return ($subject); } -# }}} - -# {{{ sub SetSubjectToken +=head2 PseudoReference -=head2 SetSubjectToken - -This routine fixes the RT tag in the subject. It's unlikely that you want to overwrite this. +Returns a fake Message-ID: header for the ticket to allow a base level of threading =cut -sub SetSubjectToken { +sub PseudoReference { + my $self = shift; - my $tag = "[$RT::rtname #" . $self->TicketObj->id . "]"; - my $sub = $self->TemplateObj->MIMEObj->head->get('Subject'); - unless ( $sub =~ /\Q$tag\E/ ) { - $sub =~ s/(\r\n|\n|\s)/ /gi; - chomp $sub; - $self->TemplateObj->MIMEObj->head->replace( 'Subject', "$tag $sub" ); - } + my $pseudo_ref + = '<RT-Ticket-' + . $self->TicketObj->id . '@' + . RT->Config->Get('Organization') . '>'; + return $pseudo_ref; } -# }}} - -# }}} - -# {{{ - =head2 SetHeaderAsEncoding($field_name, $charset_encoding) This routine converts the field into specified charset encoding. @@ -633,53 +1070,34 @@ sub SetHeaderAsEncoding { my $self = shift; my ( $field, $enc ) = ( shift, shift ); - if ($field eq 'From' and $RT::SMTPFrom) { - $self->TemplateObj->MIMEObj->head->replace( $field, $RT::SMTPFrom ); - return; - } - - my $value = $self->TemplateObj->MIMEObj->head->get($field); - - # don't bother if it's us-ascii + my $head = $self->TemplateObj->MIMEObj->head; - # See RT::I18N, 'NOTES: Why Encode::_utf8_off before Encode::from_to' - - $value = $self->MIMEEncodeString($value, $enc); - - $self->TemplateObj->MIMEObj->head->replace( $field, $value ); + if ( lc($field) eq 'from' and RT->Config->Get('SMTPFrom') ) { + $head->replace( $field, RT->Config->Get('SMTPFrom') ); + return; + } + my $value = $head->get( $field ); + $value = $self->MIMEEncodeString( $value, $enc ); + $head->replace( $field, $value ); -} -# }}} +} -# {{{ MIMENcodeString +=head2 MIMEEncodeString -=head2 MIMEEncodeString STRING ENCODING +Takes a perl string and optional encoding pass it over +L<RT::Interface::Email/EncodeToMIME>. -Takes a string and a possible encoding and returns the string wrapped in MIME goo. +Basicly encode a string using B encoding according to RFC2047. =cut sub MIMEEncodeString { - my $self = shift; - my $value = shift; - my $enc = shift; - - chomp $value; - return ($value) unless $value =~ /[^\x20-\x7e]/; - - $value =~ s/\s*$//; - Encode::_utf8_off($value); - my $res = Encode::from_to( $value, "utf-8", $enc ); - $value = encode_mimeword( $value, 'B', $enc ); + my $self = shift; + return RT::Interface::Email::EncodeToMIME( String => $_[0], Charset => $_[1] ); } -# }}} - -eval "require RT::Action::SendEmail_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/SendEmail_Vendor.pm}); -eval "require RT::Action::SendEmail_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Action/SendEmail_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Attachment.pm b/rt/lib/RT/Attachment.pm index 2ed520162..e9a3dc6e6 100755 --- a/rt/lib/RT/Attachment.pm +++ b/rt/lib/RT/Attachment.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -110,7 +135,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -119,14 +144,14 @@ Returns the current value of id. =cut -=item TransactionId +=head2 TransactionId Returns the current value of TransactionId. (In the database, TransactionId is stored as int(11).) -=item SetTransactionId VALUE +=head2 SetTransactionId VALUE Set TransactionId to VALUE. @@ -137,14 +162,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Parent +=head2 Parent Returns the current value of Parent. (In the database, Parent is stored as int(11).) -=item SetParent VALUE +=head2 SetParent VALUE Set Parent to VALUE. @@ -155,14 +180,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item MessageId +=head2 MessageId Returns the current value of MessageId. (In the database, MessageId is stored as varchar(160).) -=item SetMessageId VALUE +=head2 SetMessageId VALUE Set MessageId to VALUE. @@ -173,14 +198,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Subject +=head2 Subject Returns the current value of Subject. (In the database, Subject is stored as varchar(255).) -=item SetSubject VALUE +=head2 SetSubject VALUE Set Subject to VALUE. @@ -191,14 +216,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Filename +=head2 Filename Returns the current value of Filename. (In the database, Filename is stored as varchar(255).) -=item SetFilename VALUE +=head2 SetFilename VALUE Set Filename to VALUE. @@ -209,14 +234,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ContentType +=head2 ContentType Returns the current value of ContentType. (In the database, ContentType is stored as varchar(80).) -=item SetContentType VALUE +=head2 SetContentType VALUE Set ContentType to VALUE. @@ -227,14 +252,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ContentEncoding +=head2 ContentEncoding Returns the current value of ContentEncoding. (In the database, ContentEncoding is stored as varchar(80).) -=item SetContentEncoding VALUE +=head2 SetContentEncoding VALUE Set ContentEncoding to VALUE. @@ -245,14 +270,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Content +=head2 Content Returns the current value of Content. (In the database, Content is stored as longtext.) -=item SetContent VALUE +=head2 SetContent VALUE Set Content to VALUE. @@ -263,14 +288,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Headers +=head2 Headers Returns the current value of Headers. (In the database, Headers is stored as longtext.) -=item SetHeaders VALUE +=head2 SetHeaders VALUE Set Headers to VALUE. @@ -281,7 +306,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -290,7 +315,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -300,55 +325,38 @@ Returns the current value of Created. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, TransactionId => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Parent => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, MessageId => - {read => 1, write => 1, type => 'varchar(160)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 160, is_blob => 0, is_numeric => 0, type => 'varchar(160)', default => ''}, Subject => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, Filename => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, ContentType => - {read => 1, write => 1, type => 'varchar(80)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 80, is_blob => 0, is_numeric => 0, type => 'varchar(80)', default => ''}, ContentEncoding => - {read => 1, write => 1, type => 'varchar(80)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 80, is_blob => 0, is_numeric => 0, type => 'varchar(80)', default => ''}, Content => - {read => 1, write => 1, type => 'longtext', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'longtext', default => ''}, Headers => - {read => 1, write => 1, type => 'longtext', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'longtext', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::Attachment_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Attachment_Overlay.pm}) { - die $@; - }; - - eval "require RT::Attachment_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Attachment_Vendor.pm}) { - die $@; - }; - - eval "require RT::Attachment_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Attachment_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -358,7 +366,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Attachments.pm b/rt/lib/RT/Attachments.pm index 177cdd094..40f25e435 100755 --- a/rt/lib/RT/Attachments.pm +++ b/rt/lib/RT/Attachments.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Attachment item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Attachment->new($self->CurrentUser)); } - - eval "require RT::Attachments_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Attachments_Overlay.pm}) { - die $@; - }; - - eval "require RT::Attachments_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Attachments_Vendor.pm}) { - die $@; - }; - - eval "require RT::Attachments_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Attachments_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Condition/AnyTransaction.pm b/rt/lib/RT/Condition/AnyTransaction.pm index 4519fcf5a..755879479 100644 --- a/rt/lib/RT/Condition/AnyTransaction.pm +++ b/rt/lib/RT/Condition/AnyTransaction.pm @@ -1,34 +1,55 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK - +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} package RT::Condition::AnyTransaction; -require RT::Condition::Generic; +use base 'RT::Condition'; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Condition::Generic); =head2 IsApplicable @@ -42,10 +63,7 @@ sub IsApplicable { return(1); } -eval "require RT::Condition::AnyTransaction_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Condition/AnyTransaction_Vendor.pm}); -eval "require RT::Condition::AnyTransaction_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Condition/AnyTransaction_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Condition/Generic.pm b/rt/lib/RT/Condition/Generic.pm index bd269315e..a3bfa7585 100755 --- a/rt/lib/RT/Condition/Generic.pm +++ b/rt/lib/RT/Condition/Generic.pm @@ -1,211 +1,74 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + =head1 NAME - RT::Condition::Generic - ; + RT::Condition::Generic - deprecated, see RT::Condition =head1 SYNOPSIS - use RT::Condition::Generic; - my $foo = new RT::Condition::IsApplicable( - TransactionObj => $tr, - TicketObj => $ti, - ScripObj => $scr, - Argument => $arg, - Type => $type); - - if ($foo->IsApplicable) { - # do something - } - + use RT::Condition::Generic; =head1 DESCRIPTION +This module is provided only for backwards compatibility. =head1 METHODS -=begin testing - -ok (require RT::Condition::Generic); - -=end testing - - =cut -package RT::Condition::Generic; - -use RT::Base; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Base); - -# {{{ sub new -sub new { - my $proto = shift; - my $class = ref($proto) || $proto; - my $self = {}; - bless ($self, $class); - $self->_Init(@_); - return $self; -} -# }}} - -# {{{ sub _Init -sub _Init { - my $self = shift; - my %args = ( TransactionObj => undef, - TicketObj => undef, - ScripObj => undef, - TemplateObj => undef, - Argument => undef, - ApplicableTransTypes => undef, - @_ ); - - $self->{'Argument'} = $args{'Argument'}; - $self->{'ScripObj'} = $args{'ScripObj'}; - $self->{'TicketObj'} = $args{'TicketObj'}; - $self->{'TransactionObj'} = $args{'TransactionObj'}; - $self->{'ApplicableTransTypes'} = $args{'ApplicableTransTypes'}; -} -# }}} - -# Access Scripwide data - -# {{{ sub Argument - -=head2 Argument - -Return the optional argument associated with this ScripCondition - -=cut - -sub Argument { - my $self = shift; - return($self->{'Argument'}); -} -# }}} - -# {{{ sub TicketObj - -=head2 TicketObj - -Return the ticket object we're talking about - -=cut - -sub TicketObj { - my $self = shift; - return($self->{'TicketObj'}); -} -# }}} - -# {{{ sub ScripObj - -=head2 ScripObj - -Return the Scrip object we're talking about - -=cut - -sub ScripObj { - my $self = shift; - return($self->{'ScripObj'}); -} -# }}} -# {{{ sub TransactionObj - -=head2 TransactionObj - -Return the transaction object we're talking about - -=cut - -sub TransactionObj { - my $self = shift; - return($self->{'TransactionObj'}); -} -# }}} - -# {{{ sub Type - -=head2 Type - - - -=cut - -sub ApplicableTransTypes { - my $self = shift; - return($self->{'ApplicableTransTypes'}); -} -# }}} - - -# Scrip methods - - -#What does this type of Action does - -# {{{ sub Describe -sub Describe { - my $self = shift; - return ($self->loc("No description for [_1]", ref $self)); -} -# }}} - - -#Parse the templates, get things ready to go. - -#If this rule applies to this transaction, return true. - -# {{{ sub IsApplicable -sub IsApplicable { - my $self = shift; - return(undef); -} -# }}} - -# {{{ sub DESTROY -sub DESTROY { - my $self = shift; - - # We need to clean up all the references that might maybe get - # oddly circular - $self->{'TemplateObj'} =undef - $self->{'TicketObj'} = undef; - $self->{'TransactionObj'} = undef; - $self->{'ScripObj'} = undef; - -} - -# }}} +use warnings; +package RT::Condition::Generic; +use base 'RT::Condition'; -eval "require RT::Condition::Generic_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Condition/Generic_Vendor.pm}); -eval "require RT::Condition::Generic_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Condition/Generic_Local.pm}); +RT::Base->_ImportOverlays(); 1; + diff --git a/rt/lib/RT/Condition/StatusChange.pm b/rt/lib/RT/Condition/StatusChange.pm index 8afabcda0..b20a5ac25 100644 --- a/rt/lib/RT/Condition/StatusChange.pm +++ b/rt/lib/RT/Condition/StatusChange.pm @@ -1,35 +1,54 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK - - +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} package RT::Condition::StatusChange; -require RT::Condition::Generic; - +use base 'RT::Condition'; use strict; -use vars qw/@ISA/; -@ISA = qw(RT::Condition::Generic); =head2 IsApplicable @@ -50,10 +69,7 @@ sub IsApplicable { } } -eval "require RT::Condition::StatusChange_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Condition/StatusChange_Vendor.pm}); -eval "require RT::Condition::StatusChange_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Condition/StatusChange_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/CurrentUser.pm b/rt/lib/RT/CurrentUser.pm index 4ca2f9891..85b95f864 100755 --- a/rt/lib/RT/CurrentUser.pm +++ b/rt/lib/RT/CurrentUser.pm @@ -1,194 +1,183 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + =head1 NAME RT::CurrentUser - an RT object representing the current user =head1 SYNOPSIS - use RT::CurrentUser + use RT::CurrentUser; + + # laod + my $current_user = new RT::CurrentUser; + $current_user->Load(...); + # or + my $current_user = RT::CurrentUser->new( $user_obj ); + # or + my $current_user = RT::CurrentUser->new( $address || $name || $id ); + + # manipulation + $current_user->UserObj->SetName('new_name'); =head1 DESCRIPTION +B<Read-only> subclass of L<RT::User> class. Used to define the current +user. You should pass an instance of this class to constructors of +many RT classes, then the instance used to check ACLs and localize +strings. =head1 METHODS +See also L<RT::User> for a list of methods this class has. -=begin testing - -ok (require RT::CurrentUser); +=head2 new -=end testing +Returns new CurrentUser object. Unlike all other classes of RT it takes +either subclass of C<RT::User> class object or scalar value that is +passed to Load method. =cut package RT::CurrentUser; -use RT::Record; use RT::I18N; use strict; -use vars qw/@ISA/; -@ISA= qw(RT::Record); +use warnings; -# {{{ sub _Init +use base qw/RT::User/; #The basic idea here is that $self->CurrentUser is always supposed # to be a CurrentUser object. but that's hard to do when we're trying to load # the CurrentUser object -sub _Init { - my $self = shift; - my $Name = shift; - - $self->{'table'} = "Users"; +sub _Init { + my $self = shift; + my $User = shift; + + $self->{'table'} = "Users"; + + if ( defined $User ) { + + if ( UNIVERSAL::isa( $User, 'RT::User' ) ) { + $self->LoadById( $User->id ); + } + elsif ( ref $User ) { + $RT::Logger->crit( + "RT::CurrentUser->new() called with a bogus argument: $User"); + } + else { + $self->Load( $User ); + } + } - if (defined($Name)) { - $self->Load($Name); - } - - $self->CurrentUser($self); + $self->_BuildTableAttributes; } -# }}} -# {{{ sub Create +=head2 Create, Delete and Set* + +As stated above it's a subclass of L<RT::User>, but this class is read-only +and calls to these methods are illegal. Return 'permission denied' message +and log an error. + +=cut sub Create { my $self = shift; + $RT::Logger->error('RT::CurrentUser is read-only, RT::User for manipulation'); return (0, $self->loc('Permission Denied')); } -# }}} - -# {{{ sub Delete - sub Delete { my $self = shift; + $RT::Logger->error('RT::CurrentUser is read-only, RT::User for manipulation'); return (0, $self->loc('Permission Denied')); } -# }}} - -# {{{ sub UserObj - -=head2 UserObj - - Returns the RT::User object associated with this CurrentUser object. - -=cut - -sub UserObj { - my $self = shift; - - unless ($self->{'UserObj'}) { - use RT::User; - $self->{'UserObj'} = RT::User->new($self); - unless ($self->{'UserObj'}->Load($self->Id)) { - $RT::Logger->err($self->loc("Couldn't load [_1] from the users database.\n", $self->Id)); - } - - } - return ($self->{'UserObj'}); -} -# }}} - -# {{{ sub PrincipalObj - -=head2 PrincipalObj - - Returns this user's principal object. this is just a helper routine for - $self->UserObj->PrincipalObj - -=cut - -sub PrincipalObj { +sub _Set { my $self = shift; - return($self->UserObj->PrincipalObj); + $RT::Logger->error('RT::CurrentUser is read-only, RT::User for manipulation'); + return (0, $self->loc('Permission Denied')); } +=head2 UserObj -# }}} - - -# {{{ sub PrincipalId - -=head2 PrincipalId - - Returns this user's principal Id. this is just a helper routine for - $self->UserObj->PrincipalId +Returns the L<RT::User> object associated with this CurrentUser object. =cut -sub PrincipalId { +sub UserObj { my $self = shift; - return($self->UserObj->PrincipalId); -} - -# }}} - - -# {{{ sub _Accessible -sub _Accessible { - my $self = shift; - my %Cols = ( - Name => 'read', - Gecos => 'read', - RealName => 'read', - Password => 'neither', - EmailAddress => 'read', - Privileged => 'read', - IsAdministrator => 'read' - ); - return($self->SUPER::_Accessible(@_, %Cols)); + my $user = RT::User->new( $self ); + unless ( $user->LoadById( $self->Id ) ) { + $RT::Logger->error( + $self->loc("Couldn't load [_1] from the users database.\n", $self->Id) + ); + } + return $user; } -# }}} -# {{{ sub LoadByEmail - -=head2 LoadByEmail - -Loads a User into this CurrentUser object. -Takes the email address of the user to load. - -=cut - -sub LoadByEmail { - my $self = shift; - my $identifier = shift; - - $identifier = RT::User::CanonicalizeEmailAddress(undef, $identifier); - - $self->LoadByCol("EmailAddress",$identifier); - +sub _CoreAccessible { + { + Name => { 'read' => 1 }, + Gecos => { 'read' => 1 }, + RealName => { 'read' => 1 }, + Lang => { 'read' => 1 }, + Password => { 'read' => 0, 'write' => 0 }, + EmailAddress => { 'read' => 1, 'write' => 0 } + }; + } -# }}} - -# {{{ sub LoadByGecos =head2 LoadByGecos @@ -199,155 +188,62 @@ Takes a unix username as its only argument. sub LoadByGecos { my $self = shift; - my $identifier = shift; - - $self->LoadByCol("Gecos",$identifier); - + return $self->LoadByCol( "Gecos", shift ); } -# }}} - -# {{{ sub LoadByName =head2 LoadByName Loads a User into this CurrentUser object. Takes a Name. -=cut - -sub LoadByName { - my $self = shift; - my $identifier = shift; - $self->LoadByCol("Name",$identifier); - -} -# }}} - -# {{{ sub Load - -=head2 Load - -Loads a User into this CurrentUser object. -Takes either an integer (users id column reference) or a Name -The latter is deprecated. Instead, you should use LoadByName. -Formerly, this routine also took email addresses. - -=cut - -sub Load { - my $self = shift; - my $identifier = shift; - - #if it's an int, load by id. otherwise, load by name. - if ($identifier !~ /\D/) { - $self->SUPER::LoadById($identifier); - } - else { - # This is a bit dangerous, we might get false authen if somebody - # uses ambigous userids or real names: - $self->LoadByCol("Name",$identifier); - } -} - -# }}} - -# {{{ sub IsPassword - -=head2 IsPassword - -Takes a password as a string. Passes it off to IsPassword in this -user's UserObj. If it is the user's password and the user isn't -disabled, returns 1. - -Otherwise, returns undef. - -=cut - -sub IsPassword { - my $self = shift; - my $value = shift; - - return ($self->UserObj->IsPassword($value)); -} - -# }}} - -# {{{ sub Privileged - -=head2 Privileged - -Returns true if the current user can be granted rights and be -a member of groups. =cut -sub Privileged { +sub LoadByName { my $self = shift; - return ($self->UserObj->Privileged()); + return $self->LoadByCol( "Name", shift ); } -# }}} - - -# {{{ sub HasRight - -=head2 HasRight - -calls $self->UserObj->HasRight with the arguments passed in - -=cut - -sub HasRight { - my $self = shift; - return ($self->UserObj->HasRight(@_)); -} - -# }}} - -# {{{ Localization - =head2 LanguageHandle Returns this current user's langauge handle. Should take a language specification. but currently doesn't -=begin testing - -ok (my $cu = RT::CurrentUser->new('root')); -ok (my $lh = $cu->LanguageHandle); -ok ($lh != undef); -ok ($lh->isa('Locale::Maketext')); -ok ($cu->loc('TEST_STRING') eq "Concrete Mixer", "Localized TEST_STRING into English"); -ok ($lh = $cu->LanguageHandle('fr')); -ok ($cu->loc('Before') eq "Avant", "Localized TEST_STRING into Frenc"); - -=end testing - =cut sub LanguageHandle { my $self = shift; - if ((!defined $self->{'LangHandle'}) || - (!UNIVERSAL::can($self->{'LangHandle'}, 'maketext')) || - (@_)) { + if ( !defined $self->{'LangHandle'} + || !UNIVERSAL::can( $self->{'LangHandle'}, 'maketext' ) + || @_ ) + { + if ( my $lang = $self->Lang ) { + push @_, $lang; + } + elsif ( $self->id && ($self->id == ($RT::SystemUser->id||0) || $self->id == ($RT::Nobody->id||0)) ) { + # don't use ENV magic for system users + push @_, 'en'; + } + $self->{'LangHandle'} = RT::I18N->get_handle(@_); } + # Fall back to english. - unless ($self->{'LangHandle'}) { - die "We couldn't get a dictionary. Nye mogu naidti slovar. No puedo encontrar dictionario."; + unless ( $self->{'LangHandle'} ) { + die "We couldn't get a dictionary. Ne mogu naidti slovar. No puedo encontrar dictionario."; } - return ($self->{'LangHandle'}); + return $self->{'LangHandle'}; } sub loc { my $self = shift; - return '' if $_[0] eq ''; + return '' if !defined $_[0] || $_[0] eq ''; my $handle = $self->LanguageHandle; if (@_ == 1) { - # pre-scan the lexicon hashes to return _AUTO keys verbatim, - # to keep locstrings containing '[' and '~' from tripping over Maketext - return $_[0] unless grep { exists $_->{$_[0]} } @{ $handle->_lex_refs }; + # pre-scan the lexicon hashes to return _AUTO keys verbatim, + # to keep locstrings containing '[' and '~' from tripping over Maketext + return $_[0] unless grep exists $_->{$_[0]}, @{ $handle->_lex_refs }; } return $handle->maketext(@_); @@ -355,20 +251,66 @@ sub loc { sub loc_fuzzy { my $self = shift; - return '' if $_[0] eq ''; + return '' if !defined $_[0] || $_[0] eq ''; # XXX: work around perl's deficiency when matching utf8 data return $_[0] if Encode::is_utf8($_[0]); - my $result = $self->LanguageHandle->maketext_fuzzy(@_); - return($result); + return $self->LanguageHandle->maketext_fuzzy( @_ ); +} + +=head2 CurrentUser + +Return the current currentuser object + +=cut + +sub CurrentUser { + my $self = shift; + return($self); + +} + +=head2 Authenticate + +Takes $password, $created and $nonce, and returns a boolean value +representing whether the authentication succeeded. + +If both $nonce and $created are specified, validate $password against: + + encode_base64(sha1( + $nonce . + $created . + sha1_hex( "$username:$realm:$server_pass" ) + )) + +where $server_pass is the md5_hex(password) digest stored in the +database, $created is in ISO time format, and $nonce is a random +string no longer than 32 bytes. + +=cut + +sub Authenticate { + my ($self, $password, $created, $nonce, $realm) = @_; + + require Digest::MD5; + require Digest::SHA1; + require MIME::Base64; + + my $username = $self->UserObj->Name or return; + my $server_pass = $self->UserObj->__Value('Password') or return; + my $auth_digest = MIME::Base64::encode_base64(Digest::SHA1::sha1( + $nonce . + $created . + Digest::MD5::md5_hex("$username:$realm:$server_pass") + )); + + chomp($password); + chomp($auth_digest); + + return ($password eq $auth_digest); } -# }}} -eval "require RT::CurrentUser_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Vendor.pm}); -eval "require RT::CurrentUser_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Local.pm}); +RT::Base->_ImportOverlays(); 1; - diff --git a/rt/lib/RT/Group.pm b/rt/lib/RT/Group.pm index 4dcef3f07..7af79ce42 100755 --- a/rt/lib/RT/Group.pm +++ b/rt/lib/RT/Group.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -69,7 +94,7 @@ Create takes a hash of values and creates a row in the database: varchar(255) 'Description'. varchar(64) 'Domain'. varchar(64) 'Type'. - varchar(64) 'Instance'. + int(11) 'Instance'. =cut @@ -98,7 +123,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -107,14 +132,14 @@ Returns the current value of id. =cut -=item Name +=head2 Name Returns the current value of Name. (In the database, Name is stored as varchar(200).) -=item SetName VALUE +=head2 SetName VALUE Set Name to VALUE. @@ -125,14 +150,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Description +=head2 Description Returns the current value of Description. (In the database, Description is stored as varchar(255).) -=item SetDescription VALUE +=head2 SetDescription VALUE Set Description to VALUE. @@ -143,14 +168,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Domain +=head2 Domain Returns the current value of Domain. (In the database, Domain is stored as varchar(64).) -=item SetDomain VALUE +=head2 SetDomain VALUE Set Domain to VALUE. @@ -161,14 +186,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Type +=head2 Type Returns the current value of Type. (In the database, Type is stored as varchar(64).) -=item SetType VALUE +=head2 SetType VALUE Set Type to VALUE. @@ -179,62 +204,45 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Instance +=head2 Instance Returns the current value of Instance. -(In the database, Instance is stored as varchar(64).) +(In the database, Instance is stored as int(11).) -=item SetInstance VALUE +=head2 SetInstance VALUE Set Instance to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -(In the database, Instance will be stored as a varchar(64).) +(In the database, Instance will be stored as a int(11).) =cut -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Name => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Description => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, Domain => - {read => 1, write => 1, type => 'varchar(64)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 64, is_blob => 0, is_numeric => 0, type => 'varchar(64)', default => ''}, Type => - {read => 1, write => 1, type => 'varchar(64)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 64, is_blob => 0, is_numeric => 0, type => 'varchar(64)', default => ''}, Instance => - {read => 1, write => 1, type => 'varchar(64)', default => ''}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, } }; - - eval "require RT::Group_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Group_Overlay.pm}) { - die $@; - }; - - eval "require RT::Group_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Group_Vendor.pm}) { - die $@; - }; - - eval "require RT::Group_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Group_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -244,7 +252,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/GroupMember.pm b/rt/lib/RT/GroupMember.pm index 8de1a73fe..ae0160c9f 100755 --- a/rt/lib/RT/GroupMember.pm +++ b/rt/lib/RT/GroupMember.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -89,7 +114,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -98,14 +123,14 @@ Returns the current value of id. =cut -=item GroupId +=head2 GroupId Returns the current value of GroupId. (In the database, GroupId is stored as int(11).) -=item SetGroupId VALUE +=head2 SetGroupId VALUE Set GroupId to VALUE. @@ -116,14 +141,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item MemberId +=head2 MemberId Returns the current value of MemberId. (In the database, MemberId is stored as int(11).) -=item SetMemberId VALUE +=head2 SetMemberId VALUE Set MemberId to VALUE. @@ -135,37 +160,20 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, GroupId => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, MemberId => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, } }; - - eval "require RT::GroupMember_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/GroupMember_Overlay.pm}) { - die $@; - }; - - eval "require RT::GroupMember_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/GroupMember_Vendor.pm}) { - die $@; - }; - - eval "require RT::GroupMember_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/GroupMember_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -175,7 +183,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/GroupMembers.pm b/rt/lib/RT/GroupMembers.pm index 31cb9536f..5d821ad59 100755 --- a/rt/lib/RT/GroupMembers.pm +++ b/rt/lib/RT/GroupMembers.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::GroupMember item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::GroupMember->new($self->CurrentUser)); } - - eval "require RT::GroupMembers_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/GroupMembers_Overlay.pm}) { - die $@; - }; - - eval "require RT::GroupMembers_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/GroupMembers_Vendor.pm}) { - die $@; - }; - - eval "require RT::GroupMembers_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/GroupMembers_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Groups.pm b/rt/lib/RT/Groups.pm index 29f12a5a0..2ec2f7979 100755 --- a/rt/lib/RT/Groups.pm +++ b/rt/lib/RT/Groups.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Group item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Group->new($self->CurrentUser)); } - - eval "require RT::Groups_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Groups_Overlay.pm}) { - die $@; - }; - - eval "require RT::Groups_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Groups_Vendor.pm}) { - die $@; - }; - - eval "require RT::Groups_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Groups_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Handle.pm b/rt/lib/RT/Handle.pm index 5cdb65e5b..38905de83 100644 --- a/rt/lib/RT/Handle.pm +++ b/rt/lib/RT/Handle.pm @@ -1,101 +1,1087 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + =head1 NAME - RT::Handle - RT's database handle +RT::Handle - RT's database handle =head1 SYNOPSIS - use RT::Handle; + use RT; + BEGIN { RT::LoadConfig() }; + use RT::Handle; =head1 DESCRIPTION -=begin testing - -ok(require RT::Handle); - -=end testing - -=head1 METHODS +C<RT::Handle> is RT specific wrapper over one of L<DBIx::SearchBuilder::Handle> +classes. As RT works with different types of DBs we subclass repsective handler +from L<DBIx::SerachBuilder>. Type of the DB is defined by C<DatabasseType> RT's +config option. You B<must> load this module only when the configs have been +loaded. =cut package RT::Handle; use strict; +use warnings; use vars qw/@ISA/; -eval "use DBIx::SearchBuilder::Handle::$RT::DatabaseType; -\@ISA= qw(DBIx::SearchBuilder::Handle::$RT::DatabaseType);"; -#TODO check for errors here. +=head1 METHODS + +=head2 FinalizeDatabaseType + +Sets RT::Handle's superclass to the correct subclass of +L<DBIx::SearchBuilder::Handle>, using the C<DatabaseType> configuration. + +=cut + +sub FinalizeDatabaseType { + eval { + use base "DBIx::SearchBuilder::Handle::". RT->Config->Get('DatabaseType'); + }; + + if ($@) { + die "Unable to load DBIx::SearchBuilder database handle for '". RT->Config->Get('DatabaseType') ."'.\n". + "Perhaps you've picked an invalid database type or spelled it incorrectly.\n". + $@; + } +} =head2 Connect -Connects to RT's database handle. -Takes nothing. Calls SUPER::Connect with the needed args +Connects to RT's database using credentials and options from the RT config. +Takes nothing. =cut sub Connect { -my $self=shift; + my $self = shift; + + my $db_type = RT->Config->Get('DatabaseType'); + if ( $db_type eq 'Oracle' ) { + $ENV{'NLS_LANG'} = "AMERICAN_AMERICA.AL32UTF8"; + $ENV{'NLS_NCHAR'} = "AL32UTF8"; + } + + $self->SUPER::Connect( + User => RT->Config->Get('DatabaseUser'), + Password => RT->Config->Get('DatabasePassword'), + ); + + if ( $db_type eq 'mysql' ) { + my $version = $self->DatabaseVersion; + ($version) = $version =~ /^(\d+\.\d+)/; + $self->dbh->do("SET NAMES 'utf8'") if $version >= 4.1; + } + -# Unless the database port is a positive integer, we really don't want to pass it. + if ( $db_type eq 'Pg' ) { + my $version = $self->DatabaseVersion; + ($version) = $version =~ /^(\d+\.\d+)/; + $self->dbh->do("SET bytea_output = 'escape'") if $version >= 9.0; + } -$self->SUPER::Connect( - User => $RT::DatabaseUser, - Password => $RT::DatabasePassword, - ); - + + + $self->dbh->{'LongReadLen'} = RT->Config->Get('MaxAttachmentSize'); } -=item BuildDSN +=head2 BuildDSN -Build the DSN for the RT database. doesn't take any parameters, draws all that -from the config file. +Build the DSN for the RT database. Doesn't take any parameters, draws all that +from the config. =cut +require File::Spec; sub BuildDSN { my $self = shift; -$RT::DatabasePort = undef unless (defined $RT::DatabasePort && $RT::DatabasePort =~ /^(\d+)$/); -$RT::DatabaseHost = undef unless (defined $RT::DatabaseHost && $RT::DatabaseHost ne ''); + # Unless the database port is a positive integer, we really don't want to pass it. + my $db_port = RT->Config->Get('DatabasePort'); + $db_port = undef unless (defined $db_port && $db_port =~ /^(\d+)$/); + my $db_host = RT->Config->Get('DatabaseHost'); + $db_host = undef unless $db_host; + my $db_name = RT->Config->Get('DatabaseName'); + my $db_type = RT->Config->Get('DatabaseType'); + $db_name = File::Spec->catfile($RT::VarPath, $db_name) + if $db_type eq 'SQLite' && !File::Spec->file_name_is_absolute($db_name); + + my %args = ( + Host => $db_host, + Database => $db_name, + Port => $db_port, + Driver => $db_type, + RequireSSL => RT->Config->Get('DatabaseRequireSSL'), + DisconnectHandleOnDestroy => 1, + ); + if ( $db_type eq 'Oracle' && $db_host ) { + $args{'SID'} = delete $args{'Database'}; + } + $self->SUPER::BuildDSN( %args ); +} + +=head2 DSN + +Returns the DSN for this handle. In order to get correct value you must +build DSN first, see L</BuildDSN>. + +This is method can be called as class method, in this case creates +temporary handle object, L</BuildDSN builds DSN> and returns it. + +=cut + +sub DSN { + my $self = shift; + return $self->SUPER::DSN if ref $self; + + my $handle = $self->new; + $handle->BuildDSN; + return $handle->DSN; +} + +=head2 SystemDSN + +Returns a DSN suitable for database creates and drops +and user creates and drops. + +Gets RT's DSN first (see L<DSN>) and then change it according +to requirements of a database system RT's using. + +=cut + +sub SystemDSN { + my $self = shift; - $self->SUPER::BuildDSN(Host => $RT::DatabaseHost, - Database => $RT::DatabaseName, - Port => $RT::DatabasePort, - Driver => $RT::DatabaseType, - RequireSSL => $RT::DatabaseRequireSSL, - DisconnectHandleOnDestroy => 1 - ); - + my $db_name = RT->Config->Get('DatabaseName'); + my $db_type = RT->Config->Get('DatabaseType'); + my $dsn = $self->DSN; + if ( $db_type eq 'mysql' ) { + # with mysql, you want to connect sans database to funge things + $dsn =~ s/dbname=\Q$db_name//; + } + elsif ( $db_type eq 'Pg' ) { + # with postgres, you want to connect to template1 database + $dsn =~ s/dbname=\Q$db_name/dbname=template1/; + } + elsif ( $db_type eq 'Informix' ) { + # with Informix, you want to connect sans database: + $dsn =~ s/Informix:\Q$db_name/Informix:/; + } + return $dsn; } -eval "require RT::Handle_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Handle_Vendor.pm}); -eval "require RT::Handle_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Handle_Local.pm}); +=head2 Database compatibility and integrity checks + + + +=cut + +sub CheckIntegrity { + my $self = shift; + + my $dsn = $self->DSN; + my $user = RT->Config->Get('DatabaseUser'); + my $pass = RT->Config->Get('DatabasePassword'); + + my $dbh = DBI->connect( + $dsn, $user, $pass, + { RaiseError => 0, PrintError => 0 }, + ); + unless ( $dbh ) { + return (0, 'no connection', "Failed to connect to $dsn as user '$user': ". $DBI::errstr); + } + + RT::ConnectToDatabase(); + RT::InitLogging(); + + require RT::CurrentUser; + my $test_user = new RT::CurrentUser; + $test_user->Load('RT_System'); + unless ( $test_user->id ) { + return (0, 'no system user', "Couldn't find RT_System user in the DB '$dsn'"); + } + + $test_user = new RT::CurrentUser; + $test_user->Load('Nobody'); + unless ( $test_user->id ) { + return (0, 'no nobody user', "Couldn't find Nobody user in the DB '$dsn'"); + } + + return $dbh; +} + +sub CheckCompatibility { + my $self = shift; + my $dbh = shift; + my $state = shift || 'post'; + + my $db_type = RT->Config->Get('DatabaseType'); + if ( $db_type eq "mysql" ) { + # Check which version we're running + my $version = ($dbh->selectrow_array("show variables like 'version'"))[1]; + return (0, "couldn't get version of the mysql server") + unless $version; + + ($version) = $version =~ /^(\d+\.\d+)/; + return (0, "RT is unsupported on MySQL versions before 4.0.x, it's $version") + if $version < 4; + + # MySQL must have InnoDB support + my $innodb = ($dbh->selectrow_array("show variables like 'have_innodb'"))[1]; + if ( lc $innodb eq "no" ) { + return (0, "RT requires that MySQL be compiled with InnoDB table support.\n". + "See http://dev.mysql.com/doc/mysql/en/InnoDB.html"); + } elsif ( lc $innodb eq "disabled" ) { + return (0, "RT requires that MySQL InnoDB table support be enabled.\n". + "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n"); + } + + if ( $state eq 'post' ) { + my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Tickets")->[1]; + unless ( $create_table =~ /(?:ENGINE|TYPE)\s*=\s*InnoDB/i ) { + return (0, "RT requires that all its tables be of InnoDB type. Upgrade RT tables."); + } + } + if ( $version >= 4.1 && $state eq 'post' ) { + my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1]; + unless ( $create_table =~ /\bContent\b[^,]*BLOB/i ) { + return (0, "RT since version 3.8 has new schema for MySQL versions after 4.1.0\n" + ."Follow instructions in the UPGRADING.mysql file."); + } + } + } + return (1) +} + +=head2 Database maintanance + +=head3 CreateDatabase $DBH + +Creates a new database. This method can be used as class method. + +Takes DBI handle. Many database systems require special handle to +allow you to create a new database, so you have to use L<SystemDSN> +method during connection. + +Fetches type and name of the DB from the config. + +=cut + +sub CreateDatabase { + my $self = shift; + my $dbh = shift or return (0, "No DBI handle provided"); + my $db_type = RT->Config->Get('DatabaseType'); + my $db_name = RT->Config->Get('DatabaseName'); + + my $status; + if ( $db_type eq 'SQLite' ) { + return (1, 'Skipped as SQLite doesn\'t need any action'); + } + elsif ( $db_type eq 'Oracle' ) { + my $db_user = RT->Config->Get('DatabaseUser'); + my $db_pass = RT->Config->Get('DatabasePassword'); + $status = $dbh->do( + "CREATE USER $db_user IDENTIFIED BY $db_pass" + ." default tablespace USERS" + ." temporary tablespace TEMP" + ." quota unlimited on USERS" + ); + unless ( $status ) { + return $status, "Couldn't create user $db_user identified by $db_pass." + ."\nError: ". $dbh->errstr; + } + $status = $dbh->do( "GRANT connect, resource TO $db_user" ); + unless ( $status ) { + return $status, "Couldn't grant connect and resource to $db_user." + ."\nError: ". $dbh->errstr; + } + return (1, "Created user $db_user. All RT's objects should be in his schema."); + } + elsif ( $db_type eq 'Pg' ) { + # XXX: as we get external DBH we don't know if RaiseError or PrintError + # are enabled, so we have to setup it here and restore them back + $status = $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE' TEMPLATE template0") + || $dbh->do("CREATE DATABASE $db_name TEMPLATE template0"); + } + elsif ( $db_type eq 'Informix' ) { + local $ENV{'DB_LOCALE'} = 'en_us.utf8'; + $status = $dbh->do("CREATE DATABASE $db_name WITH BUFFERED LOG"); + } + else { + $status = $dbh->do("CREATE DATABASE $db_name"); + } + return ($status, $DBI::errstr); +} + +=head3 DropDatabase $DBH [Force => 0] + +Drops RT's database. This method can be used as class method. + +Takes DBI handle as first argument. Many database systems require +special handle to allow you to create a new database, so you have +to use L<SystemDSN> method during connection. + +Fetches type and name of the DB from the config. + +=cut + +sub DropDatabase { + my $self = shift; + my $dbh = shift or return (0, "No DBI handle provided"); + + my $db_type = RT->Config->Get('DatabaseType'); + my $db_name = RT->Config->Get('DatabaseName'); + + if ( $db_type eq 'Oracle' || $db_type eq 'Informix' ) { + my $db_user = RT->Config->Get('DatabaseUser'); + my $status = $dbh->do( "DROP USER $db_user CASCADE" ); + unless ( $status ) { + return 0, "Couldn't drop user $db_user." + ."\nError: ". $dbh->errstr; + } + return (1, "Successfully dropped user '$db_user' with his schema."); + } + elsif ( $db_type eq 'SQLite' ) { + my $path = $db_name; + $path = "$RT::VarPath/$path" unless substr($path, 0, 1) eq '/'; + unlink $path or return (0, "Couldn't remove '$path': $!"); + return (1); + } else { + $dbh->do("DROP DATABASE ". $db_name) + or return (0, $DBI::errstr); + } + return (1); +} + +=head2 InsertACL + +=cut + +sub InsertACL { + my $self = shift; + my $dbh = shift; + my $base_path = shift || $RT::EtcPath; + + my $db_type = RT->Config->Get('DatabaseType'); + return (1) if $db_type eq 'SQLite'; + + $dbh = $self->dbh if !$dbh && ref $self; + return (0, "No DBI handle provided") unless $dbh; + + return (0, "'$base_path' doesn't exist") unless -e $base_path; + + my $path; + if ( -d $base_path ) { + $path = File::Spec->catfile( $base_path, "acl.$db_type"); + $path = $self->GetVersionFile($dbh, $path); + + $path = File::Spec->catfile( $base_path, "acl") + unless $path && -e $path; + return (0, "Couldn't find ACLs for $db_type") + unless -e $path; + } else { + $path = $base_path; + } + + local *acl; + do $path || return (0, "Couldn't load ACLs: " . $@); + my @acl = acl($dbh); + foreach my $statement (@acl) { + my $sth = $dbh->prepare($statement) + or return (0, "Couldn't prepare SQL query:\n $statement\n\nERROR: ". $dbh->errstr); + unless ( $sth->execute ) { + return (0, "Couldn't run SQL query:\n $statement\n\nERROR: ". $sth->errstr); + } + } + return (1); +} + +=head2 InsertSchema + +=cut + +sub InsertSchema { + my $self = shift; + my $dbh = shift; + my $base_path = (shift || $RT::EtcPath); + + $dbh = $self->dbh if !$dbh && ref $self; + return (0, "No DBI handle provided") unless $dbh; + + my $db_type = RT->Config->Get('DatabaseType'); + + my $file; + if ( -d $base_path ) { + $file = $base_path . "/schema." . $db_type; + } else { + $file = $base_path; + } + + $file = $self->GetVersionFile( $dbh, $file ); + unless ( $file ) { + return (0, "Couldn't find schema file(s) '$file*'"); + } + unless ( -f $file && -r $file ) { + return (0, "File '$file' doesn't exist or couldn't be read"); + } + + my (@schema); + + open( my $fh_schema, '<', $file ) or die $!; + + my $has_local = 0; + open( my $fh_schema_local, "<", $self->GetVersionFile( $dbh, $RT::LocalEtcPath . "/schema." . $db_type )) + and $has_local = 1; + + my $statement = ""; + foreach my $line ( <$fh_schema>, ($_ = ';;'), $has_local? <$fh_schema_local>: () ) { + $line =~ s/\#.*//g; + $line =~ s/--.*//g; + $statement .= $line; + if ( $line =~ /;(\s*)$/ ) { + $statement =~ s/;(\s*)$//g; + push @schema, $statement; + $statement = ""; + } + } + close $fh_schema; close $fh_schema_local; + + if ( $db_type eq 'Oracle' ) { + my $db_user = RT->Config->Get('DatabaseUser'); + my $status = $dbh->do( "ALTER SESSION SET CURRENT_SCHEMA=$db_user" ); + unless ( $status ) { + return $status, "Couldn't set current schema to $db_user." + ."\nError: ". $dbh->errstr; + } + } + + local $SIG{__WARN__} = sub {}; + my $is_local = 0; + $dbh->begin_work or return (0, "Couldn't begin transaction: ". $dbh->errstr); + foreach my $statement (@schema) { + if ( $statement =~ /^\s*;$/ ) { + $is_local = 1; next; + } + + my $sth = $dbh->prepare($statement) + or return (0, "Couldn't prepare SQL query:\n$statement\n\nERROR: ". $dbh->errstr); + unless ( $sth->execute or $is_local ) { + return (0, "Couldn't run SQL query:\n$statement\n\nERROR: ". $sth->errstr); + } + } + $dbh->commit or return (0, "Couldn't commit transaction: ". $dbh->errstr); + return (1); +} + +=head1 GetVersionFile + +Takes base name of the file as argument, scans for <base name>-<version> named +files and returns file name with closest version to the version of the RT DB. + +=cut + +sub GetVersionFile { + my $self = shift; + my $dbh = shift; + my $base_name = shift; + + my $db_version = ref $self + ? $self->DatabaseVersion + : do { + my $tmp = RT::Handle->new; + $tmp->dbh($dbh); + $tmp->DatabaseVersion; + }; + + require File::Glob; + my @files = File::Glob::bsd_glob("$base_name*"); + return '' unless @files; + + my %version = map { $_ =~ /\.\w+-([-\w\.]+)$/; ($1||0) => $_ } @files; + my $version; + foreach ( reverse sort cmp_version keys %version ) { + if ( cmp_version( $db_version, $_ ) >= 0 ) { + $version = $_; + last; + } + } + + return defined $version? $version{ $version } : undef; +} + +sub cmp_version($$) { + my ($a, $b) = (@_); + $b =~ s/HEAD$/9999/; + my @a = split /[^0-9]+/, $a; + my @b = split /[^0-9]+/, $b; + for ( my $i = 0; $i < @a; $i++ ) { + return 1 unless defined $b[$i]; + return $a[$i] <=> $b[$i] if $a[$i] <=> $b[$i]; + } + return 0 if @a == @b; + return -1; +} + + +=head2 InsertInitialData + +Inserts system objects into RT's DB, like system user or 'nobody', +internal groups and other records required. However, this method +doesn't insert any real users like 'root' and you have to use +InsertData or another way to do that. + +Takes no arguments. Returns status and message tuple. + +It's safe to call this method even if those objects already exist. + +=cut + +sub InsertInitialData { + my $self = shift; + + my @warns; + + # create RT_System user and grant him rights + { + require RT::CurrentUser; + + my $test_user = RT::User->new( new RT::CurrentUser ); + $test_user->Load('RT_System'); + if ( $test_user->id ) { + push @warns, "Found system user in the DB."; + } + else { + my $user = RT::User->new( new RT::CurrentUser ); + my ( $val, $msg ) = $user->_BootstrapCreate( + Name => 'RT_System', + RealName => 'The RT System itself', + Comments => 'Do not delete or modify this user. ' + . 'It is integral to RT\'s internal database structures', + Creator => '1', + LastUpdatedBy => '1', + ); + return ($val, $msg) unless $val; + } + DBIx::SearchBuilder::Record::Cachable->FlushCache; + } + + # init RT::SystemUser and RT::System objects + RT::InitSystemObjects(); + unless ( $RT::SystemUser->id ) { + return (0, "Couldn't load system user"); + } + + # grant SuperUser right to system user + { + my $test_ace = RT::ACE->new( $RT::SystemUser ); + $test_ace->LoadByCols( + PrincipalId => ACLEquivGroupId( $RT::SystemUser->Id ), + PrincipalType => 'Group', + RightName => 'SuperUser', + ObjectType => 'RT::System', + ObjectId => 1, + ); + if ( $test_ace->id ) { + push @warns, "System user has global SuperUser right."; + } else { + my $ace = RT::ACE->new( $RT::SystemUser ); + my ( $val, $msg ) = $ace->_BootstrapCreate( + PrincipalId => ACLEquivGroupId( $RT::SystemUser->Id ), + PrincipalType => 'Group', + RightName => 'SuperUser', + ObjectType => 'RT::System', + ObjectId => 1, + ); + return ($val, $msg) unless $val; + } + DBIx::SearchBuilder::Record::Cachable->FlushCache; + } + + # system groups + # $self->loc('Everyone'); # For the string extractor to get a string to localize + # $self->loc('Privileged'); # For the string extractor to get a string to localize + # $self->loc('Unprivileged'); # For the string extractor to get a string to localize + foreach my $name (qw(Everyone Privileged Unprivileged)) { + my $group = RT::Group->new( $RT::SystemUser ); + $group->LoadSystemInternalGroup( $name ); + if ( $group->id ) { + push @warns, "System group '$name' already exists."; + next; + } + + $group = RT::Group->new( $RT::SystemUser ); + my ( $val, $msg ) = $group->_Create( + Type => $name, + Domain => 'SystemInternal', + Description => 'Pseudogroup for internal use', # loc + Name => '', + Instance => '', + ); + return ($val, $msg) unless $val; + } + + # nobody + { + my $user = RT::User->new( $RT::SystemUser ); + $user->Load('Nobody'); + if ( $user->id ) { + push @warns, "Found 'Nobody' user in the DB."; + } + else { + my ( $val, $msg ) = $user->Create( + Name => 'Nobody', + RealName => 'Nobody in particular', + Comments => 'Do not delete or modify this user. It is integral ' + .'to RT\'s internal data structures', + Privileged => 0, + ); + return ($val, $msg) unless $val; + } + + if ( $user->HasRight( Right => 'OwnTicket', Object => $RT::System ) ) { + push @warns, "User 'Nobody' has global OwnTicket right."; + } else { + my ( $val, $msg ) = $user->PrincipalObj->GrantRight( + Right => 'OwnTicket', + Object => $RT::System, + ); + return ($val, $msg) unless $val; + } + } + + # rerun to get init Nobody as well + RT::InitSystemObjects(); + + # system role groups + foreach my $name (qw(Owner Requestor Cc AdminCc)) { + my $group = RT::Group->new( $RT::SystemUser ); + $group->LoadSystemRoleGroup( $name ); + if ( $group->id ) { + push @warns, "System role '$name' already exists."; + next; + } + + $group = RT::Group->new( $RT::SystemUser ); + my ( $val, $msg ) = $group->_Create( + Type => $name, + Domain => 'RT::System-Role', + Description => 'SystemRolegroup for internal use', # loc + Name => '', + Instance => '', + ); + return ($val, $msg) unless $val; + } + + push @warns, "You appear to have a functional RT database." + if @warns; + + return (1, join "\n", @warns); +} + +=head2 InsertData + +Load some sort of data into the database, takes path to a file. + +=cut + +sub InsertData { + my $self = shift; + my $datafile = shift; + + # Slurp in stuff to insert from the datafile. Possible things to go in here:- + our (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions, + @Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final); + local (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions, + @Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final); + + local $@; + $RT::Logger->debug("Going to load '$datafile' data file"); + eval { require $datafile } + or return (0, "Couldn't load data from '$datafile' for import:\n\nERROR:". $@); + + if ( @Initial ) { + $RT::Logger->debug("Running initial actions..."); + foreach ( @Initial ) { + local $@; + eval { $_->(); 1 } or return (0, "One of initial functions failed: $@"); + } + $RT::Logger->debug("Done."); + } + if ( @Groups ) { + $RT::Logger->debug("Creating groups..."); + foreach my $item (@Groups) { + my $new_entry = RT::Group->new( $RT::SystemUser ); + my $member_of = delete $item->{'MemberOf'}; + my ( $return, $msg ) = $new_entry->_Create(%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + next; + } else { + $RT::Logger->debug($return ."."); + } + if ( $member_of ) { + $member_of = [ $member_of ] unless ref $member_of eq 'ARRAY'; + foreach( @$member_of ) { + my $parent = RT::Group->new($RT::SystemUser); + if ( ref $_ eq 'HASH' ) { + $parent->LoadByCols( %$_ ); + } + elsif ( !ref $_ ) { + $parent->LoadUserDefinedGroup( $_ ); + } + else { + $RT::Logger->error( + "(Error: wrong format of MemberOf field." + ." Should be name of user defined group or" + ." hash reference with 'column => value' pairs." + ." Use array reference to add to multiple groups)" + ); + next; + } + unless ( $parent->Id ) { + $RT::Logger->error("(Error: couldn't load group to add member)"); + next; + } + my ( $return, $msg ) = $parent->AddMember( $new_entry->Id ); + unless ( $return ) { + $RT::Logger->error( $msg ); + } else { + $RT::Logger->debug( $return ."." ); + } + } + } + } + $RT::Logger->debug("done."); + } + if ( @Users ) { + $RT::Logger->debug("Creating users..."); + foreach my $item (@Users) { + my $new_entry = new RT::User( $RT::SystemUser ); + my ( $return, $msg ) = $new_entry->Create(%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + } else { + $RT::Logger->debug( $return ."." ); + } + } + $RT::Logger->debug("done."); + } + if ( @Queues ) { + $RT::Logger->debug("Creating queues..."); + for my $item (@Queues) { + my $new_entry = new RT::Queue($RT::SystemUser); + my ( $return, $msg ) = $new_entry->Create(%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + } else { + $RT::Logger->debug( $return ."." ); + } + } + $RT::Logger->debug("done."); + } + if ( @CustomFields ) { + $RT::Logger->debug("Creating custom fields..."); + for my $item ( @CustomFields ) { + my $new_entry = new RT::CustomField( $RT::SystemUser ); + my $values = delete $item->{'Values'}; + + my @queues; + # if ref then it's list of queues, so we do things ourself + if ( exists $item->{'Queue'} && ref $item->{'Queue'} ) { + $item->{'LookupType'} ||= 'RT::Queue-RT::Ticket'; + @queues = @{ delete $item->{'Queue'} }; + } + + my ( $return, $msg ) = $new_entry->Create(%$item); + unless( $return ) { + $RT::Logger->error( $msg ); + next; + } + + if ( $item->{'BasedOn'} ) { + my $basedon = RT::CustomField->new($RT::SystemUser); + my ($ok, $msg ) = $basedon->LoadByCols( Name => $item->{'BasedOn'}, + LookupType => $new_entry->LookupType ); + if ($ok) { + ($ok, $msg) = $new_entry->SetBasedOn( $basedon ); + if ($ok) { + $RT::Logger->debug("Added BasedOn $item->{BasedOn}: $msg"); + } else { + $RT::Logger->error("Failed to add basedOn $item->{BasedOn}: $msg"); + } + } else { + $RT::Logger->error("Unable to load $item->{BasedOn} as a $item->{LookupType} CF. Skipping BasedOn"); + } + } + + foreach my $value ( @{$values} ) { + my ( $return, $msg ) = $new_entry->AddValue(%$value); + $RT::Logger->error( $msg ) unless $return; + } + + # apply by default + if ( !@queues && !exists $item->{'Queue'} && $item->{LookupType} ) { + my $ocf = RT::ObjectCustomField->new($RT::SystemUser); + $ocf->Create( CustomField => $new_entry->Id ); + } + + for my $q (@queues) { + my $q_obj = RT::Queue->new($RT::SystemUser); + $q_obj->Load($q); + unless ( $q_obj->Id ) { + $RT::Logger->error("Could not find queue ". $q ); + next; + } + my $OCF = RT::ObjectCustomField->new($RT::SystemUser); + ( $return, $msg ) = $OCF->Create( + CustomField => $new_entry->Id, + ObjectId => $q_obj->Id, + ); + $RT::Logger->error( $msg ) unless $return and $OCF->Id; + } + } + + $RT::Logger->debug("done."); + } + if ( @ACL ) { + $RT::Logger->debug("Creating ACL..."); + for my $item (@ACL) { + + my ($princ, $object); + + # Global rights or Queue rights? + if ( $item->{'CF'} ) { + $object = RT::CustomField->new( $RT::SystemUser ); + my @columns = ( Name => $item->{'CF'} ); + push @columns, Queue => $item->{'Queue'} if $item->{'Queue'} and not ref $item->{'Queue'}; + $object->LoadByName( @columns ); + } elsif ( $item->{'Queue'} ) { + $object = RT::Queue->new($RT::SystemUser); + $object->Load( $item->{'Queue'} ); + } else { + $object = $RT::System; + } + + $RT::Logger->error("Couldn't load object") and next unless $object and $object->Id; + + # Group rights or user rights? + if ( $item->{'GroupDomain'} ) { + $princ = RT::Group->new($RT::SystemUser); + if ( $item->{'GroupDomain'} eq 'UserDefined' ) { + $princ->LoadUserDefinedGroup( $item->{'GroupId'} ); + } elsif ( $item->{'GroupDomain'} eq 'SystemInternal' ) { + $princ->LoadSystemInternalGroup( $item->{'GroupType'} ); + } elsif ( $item->{'GroupDomain'} eq 'RT::System-Role' ) { + $princ->LoadSystemRoleGroup( $item->{'GroupType'} ); + } elsif ( $item->{'GroupDomain'} eq 'RT::Queue-Role' && + $item->{'Queue'} ) + { + $princ->LoadQueueRoleGroup( Type => $item->{'GroupType'}, + Queue => $object->id); + } else { + $princ->Load( $item->{'GroupId'} ); + } + } else { + $princ = RT::User->new($RT::SystemUser); + $princ->Load( $item->{'UserId'} ); + } + + # Grant it + my ( $return, $msg ) = $princ->PrincipalObj->GrantRight( + Right => $item->{'Right'}, + Object => $object + ); + unless ( $return ) { + $RT::Logger->error( $msg ); + } + else { + $RT::Logger->debug( $return ."." ); + } + } + $RT::Logger->debug("done."); + } + + if ( @ScripActions ) { + $RT::Logger->debug("Creating ScripActions..."); + + for my $item (@ScripActions) { + my $new_entry = RT::ScripAction->new($RT::SystemUser); + my ( $return, $msg ) = $new_entry->Create(%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + } + else { + $RT::Logger->debug( $return ."." ); + } + } + + $RT::Logger->debug("done."); + } + + if ( @ScripConditions ) { + $RT::Logger->debug("Creating ScripConditions..."); + + for my $item (@ScripConditions) { + my $new_entry = RT::ScripCondition->new($RT::SystemUser); + my ( $return, $msg ) = $new_entry->Create(%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + } + else { + $RT::Logger->debug( $return ."." ); + } + } + + $RT::Logger->debug("done."); + } + + if ( @Templates ) { + $RT::Logger->debug("Creating templates..."); + + for my $item (@Templates) { + my $new_entry = new RT::Template($RT::SystemUser); + my ( $return, $msg ) = $new_entry->Create(%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + } + else { + $RT::Logger->debug( $return ."." ); + } + } + $RT::Logger->debug("done."); + } + if ( @Scrips ) { + $RT::Logger->debug("Creating scrips..."); + + for my $item (@Scrips) { + my $new_entry = new RT::Scrip($RT::SystemUser); + + my @queues = ref $item->{'Queue'} eq 'ARRAY'? @{ $item->{'Queue'} }: $item->{'Queue'} || 0; + push @queues, 0 unless @queues; # add global queue at least + + foreach my $q ( @queues ) { + my ( $return, $msg ) = $new_entry->Create( %$item, Queue => $q ); + unless ( $return ) { + $RT::Logger->error( $msg ); + } + else { + $RT::Logger->debug( $return ."." ); + } + } + } + $RT::Logger->debug("done."); + } + if ( @Attributes ) { + $RT::Logger->debug("Creating predefined searches..."); + my $sys = RT::System->new($RT::SystemUser); + + for my $item (@Attributes) { + my $obj = delete $item->{Object}; # XXX: make this something loadable + $obj ||= $sys; + my ( $return, $msg ) = $obj->AddAttribute (%$item); + unless ( $return ) { + $RT::Logger->error( $msg ); + } + else { + $RT::Logger->debug( $return ."." ); + } + } + $RT::Logger->debug("done."); + } + if ( @Final ) { + $RT::Logger->debug("Running final actions..."); + for ( @Final ) { + local $@; + eval { $_->(); }; + $RT::Logger->error( "Failed to run one of final actions: $@" ) + if $@; + } + $RT::Logger->debug("done."); + } + + my $db_type = RT->Config->Get('DatabaseType'); + $RT::Handle->Disconnect() unless $db_type eq 'SQLite'; + + $RT::Logger->debug("Done setting up database content."); + +# TODO is it ok to return 1 here? If so, the previous codes in this sub +# should return (0, $msg) if error happens instead of just warning. +# anyway, we need to return something here to tell if everything is ok + return( 1, 'Done inserting data' ); +} + +=head2 ACLEquivGroupId + +Given a userid, return that user's acl equivalence group + +=cut + +sub ACLEquivGroupId { + my $id = shift; + + my $cu = $RT::SystemUser; + unless ( $cu ) { + require RT::CurrentUser; + $cu = new RT::CurrentUser; + $cu->LoadByName('RT_System'); + warn "Couldn't load RT_System user" unless $cu->id; + } + + my $equiv_group = RT::Group->new( $cu ); + $equiv_group->LoadACLEquivalenceGroup( $id ); + return $equiv_group->Id; +} + +__PACKAGE__->FinalizeDatabaseType; + +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Interface/CLI.pm b/rt/lib/RT/Interface/CLI.pm index ec0e877b4..5e1999816 100644 --- a/rt/lib/RT/Interface/CLI.pm +++ b/rt/lib/RT/Interface/CLI.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + use strict; use RT; @@ -29,14 +54,12 @@ package RT::Interface::CLI; BEGIN { - use Exporter (); - use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + use base 'Exporter'; + use vars qw ($VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS); # set the version for version checking - $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker - - @ISA = qw(Exporter); - + $VERSION = do { my @r = (q$Revision: 1.1.1.10 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker + # your exported package globals go here, # as well as any optionally exported functions @EXPORT_OK = qw(&CleanEnv @@ -76,11 +99,6 @@ BEGIN { =head1 METHODS -=begin testing - -ok(require RT::Interface::CLI); - -=end testing =cut @@ -182,9 +200,9 @@ sub GetMessageContent { #Load the sourcefile, if it's been handed to us if ($source) { - open (SOURCE, "<$source"); - @lines = (<SOURCE>); - close (SOURCE); + open( SOURCE, '<', $source ) or die $!; + @lines = (<SOURCE>) or die $!; + close (SOURCE) or die $!; } elsif ($args{'Content'}) { @lines = split('\n',$args{'Content'}); @@ -196,21 +214,21 @@ sub GetMessageContent { for (@lines) { print $fh $_; } - close ($fh); + close ($fh) or die $!; #Edit the file if we need to if ($edit) { unless ($ENV{'EDITOR'}) { - $RT::Logger->crit('No $EDITOR variable defined'. "\n"); + $RT::Logger->crit('No $EDITOR variable defined'); return undef; } system ($ENV{'EDITOR'}, $filename); } - open (READ, "<$filename"); + open( READ, '<', $filename ) or die $!; my @newlines = (<READ>); - close (READ); + close (READ) or die $!; unlink ($filename) unless (debug()); return(\@newlines); @@ -225,7 +243,7 @@ sub debug { my $val = shift; my ($debug); if ($val) { - $RT::Logger->debug($val."\n"); + $RT::Logger->debug($val); if ($debug) { print STDERR "$val\n"; } @@ -238,9 +256,6 @@ sub debug { # }}} -eval "require RT::Interface::CLI_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/CLI_Vendor.pm}); -eval "require RT::Interface::CLI_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/CLI_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Interface/Email.pm b/rt/lib/RT/Interface/Email.pm index 7eec0502f..401e970e8 100755 --- a/rt/lib/RT/Interface/Email.pm +++ b/rt/lib/RT/Interface/Email.pm @@ -1,63 +1,91 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + package RT::Interface::Email; use strict; -use Mail::Address; +use warnings; + +use Email::Address; use MIME::Entity; use RT::EmailParser; - +use File::Temp; +use UNIVERSAL::require; +use Mail::Mailer (); BEGIN { - use Exporter (); - use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); - + use base 'Exporter'; + use vars qw ( @EXPORT_OK); + # set the version for version checking - $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker - - @ISA = qw(Exporter); - + our $VERSION = 2.0; + # your exported package globals go here, # as well as any optionally exported functions - @EXPORT_OK = qw( - &CreateUser - &GetMessageContent - &CheckForLoops - &CheckForSuspiciousSender - &CheckForAutoGenerated - &MailError - &ParseCcAddressesFromHead - &ParseSenderAddressFromHead - &ParseErrorsToAddressFromHead - &ParseAddressFromHeader - &Gateway); + @EXPORT_OK = qw( + &CreateUser + &GetMessageContent + &CheckForLoops + &CheckForSuspiciousSender + &CheckForAutoGenerated + &CheckForBounce + &MailError + &ParseCcAddressesFromHead + &ParseSenderAddressFromHead + &ParseErrorsToAddressFromHead + &ParseAddressFromHeader + &Gateway); } =head1 NAME - RT::Interface::CLI - helper functions for creating a commandline RT interface + RT::Interface::Email - helper functions for parsing email sent to RT =head1 SYNOPSIS @@ -69,425 +97,1627 @@ BEGIN { =head1 DESCRIPTION -=begin testing - -ok(require RT::Interface::Email); - -=end testing =head1 METHODS -=cut +=head2 CheckForLoops HEAD +Takes a HEAD object of L<MIME::Head> class and returns true if the +message's been sent by this RT instance. Uses "X-RT-Loop-Prevention" +field of the head for test. -# {{{ sub CheckForLoops +=cut -sub CheckForLoops { +sub CheckForLoops { my $head = shift; - - #If this instance of RT sent it our, we don't want to take it in + + # If this instance of RT sent it our, we don't want to take it in my $RTLoop = $head->get("X-RT-Loop-Prevention") || ""; - chomp ($RTLoop); #remove that newline - if ($RTLoop eq "$RT::rtname") { - return (1); + chomp ($RTLoop); # remove that newline + if ( $RTLoop eq RT->Config->Get('rtname') ) { + return 1; } - + # TODO: We might not trap the case where RT instance A sends a mail # to RT instance B which sends a mail to ... - return (undef); + return undef; } -# }}} +=head2 CheckForSuspiciousSender HEAD + +Takes a HEAD object of L<MIME::Head> class and returns true if sender +is suspicious. Suspicious means mailer daemon. -# {{{ sub CheckForSuspiciousSender +See also L</ParseSenderAddressFromHead>. + +=cut sub CheckForSuspiciousSender { my $head = shift; #if it's from a postmaster or mailer daemon, it's likely a bounce. - + #TODO: better algorithms needed here - there is no standards for #bounces, so it's very difficult to separate them from anything #else. At the other hand, the Return-To address is only ment to be #used as an error channel, we might want to put up a separate #Return-To address which is treated differently. - + #TODO: search through the whole email and find the right Ticket ID. - my ($From, $junk) = ParseSenderAddressFromHead($head); - - if (($From =~ /^mailer-daemon/i) or - ($From =~ /^postmaster/i)){ - return (1); - + my ( $From, $junk ) = ParseSenderAddressFromHead($head); + + if ( ( $From =~ /^mailer-daemon\@/i ) + or ( $From =~ /^postmaster\@/i ) + or ( $From eq "" )) + { + return (1); + } - - return (undef); + return undef; } -# }}} +=head2 CheckForAutoGenerated HEAD + +Takes a HEAD object of L<MIME::Head> class and returns true if message +is autogenerated. Checks 'Precedence' and 'X-FC-Machinegenerated' +fields of the head in tests. + +=cut -# {{{ sub CheckForAutoGenerated sub CheckForAutoGenerated { my $head = shift; - - my $Precedence = $head->get("Precedence") || "" ; - if ($Precedence =~ /^(bulk|junk)/i) { - return (1); + + my $Precedence = $head->get("Precedence") || ""; + if ( $Precedence =~ /^(bulk|junk)/i ) { + return (1); } - else { - return (0); + + # Per RFC3834, any Auto-Submitted header which is not "no" means + # it is auto-generated. + my $AutoSubmitted = $head->get("Auto-Submitted") || ""; + if ( length $AutoSubmitted and $AutoSubmitted ne "no" ) { + return (1); + } + + # First Class mailer uses this as a clue. + my $FCJunk = $head->get("X-FC-Machinegenerated") || ""; + if ( $FCJunk =~ /^true/i ) { + return (1); } + + return (0); } -# }}} +sub CheckForBounce { + my $head = shift; + + my $ReturnPath = $head->get("Return-path") || ""; + return ( $ReturnPath =~ /<>/ ); +} + + +=head2 MailError PARAM HASH + +Sends an error message. Takes a param hash: + +=over 4 + +=item From - sender's address, by default is 'CorrespondAddress'; + +=item To - recipient, by default is 'OwnerEmail'; + +=item Bcc - optional Bcc recipients; + +=item Subject - subject of the message, default is 'There has been an error'; + +=item Explanation - main content of the error, default value is 'Unexplained error'; + +=item MIMEObj - optional MIME entity that's attached to the error mail, as well we +add 'In-Reply-To' field to the error that points to this message. + +=item Attach - optional text that attached to the error as 'message/rfc822' part. + +=item LogLevel - log level under which we should write explanation message into the +log, by default we log it as critical. + +=back + +=cut -# {{{ sub MailError sub MailError { - my %args = (To => $RT::OwnerEmail, - Bcc => undef, - From => $RT::CorrespondAddress, - Subject => 'There has been an error', - Explanation => 'Unexplained error', - MIMEObj => undef, - LogLevel => 'crit', - @_); - - - $RT::Logger->log(level => $args{'LogLevel'}, - message => $args{'Explanation'} - ); - my $entity = MIME::Entity->build( Type =>"multipart/mixed", - From => $args{'From'}, - Bcc => $args{'Bcc'}, - To => $args{'To'}, - Subject => $args{'Subject'}, - 'X-RT-Loop-Prevention' => $RT::rtname, - ); - - $entity->attach( Data => $args{'Explanation'}."\n"); - - my $mimeobj = $args{'MIMEObj'}; - if ($mimeobj) { - $mimeobj->sync_headers(); - $entity->add_part($mimeobj); + my %args = ( + To => RT->Config->Get('OwnerEmail'), + Bcc => undef, + From => RT->Config->Get('CorrespondAddress'), + Subject => 'There has been an error', + Explanation => 'Unexplained error', + MIMEObj => undef, + Attach => undef, + LogLevel => 'crit', + @_ + ); + + $RT::Logger->log( + level => $args{'LogLevel'}, + message => $args{'Explanation'} + ) if $args{'LogLevel'}; + + # the colons are necessary to make ->build include non-standard headers + my %entity_args = ( + Type => "multipart/mixed", + From => $args{'From'}, + Bcc => $args{'Bcc'}, + To => $args{'To'}, + Subject => $args{'Subject'}, + 'X-RT-Loop-Prevention:' => RT->Config->Get('rtname'), + ); + + # only set precedence if the sysadmin wants us to + if (defined(RT->Config->Get('DefaultErrorMailPrecedence'))) { + $entity_args{'Precedence:'} = RT->Config->Get('DefaultErrorMailPrecedence'); } + + my $entity = MIME::Entity->build(%entity_args); + SetInReplyTo( Message => $entity, InReplyTo => $args{'MIMEObj'} ); + + $entity->attach( Data => $args{'Explanation'} . "\n" ); + + if ( $args{'MIMEObj'} ) { + $args{'MIMEObj'}->sync_headers; + $entity->add_part( $args{'MIMEObj'} ); + } + + if ( $args{'Attach'} ) { + $entity->attach( Data => $args{'Attach'}, Type => 'message/rfc822' ); + + } + + SendEmail( Entity => $entity, Bounce => 1 ); +} + + +=head2 SendEmail Entity => undef, [ Bounce => 0, Ticket => undef, Transaction => undef ] + +Sends an email (passed as a L<MIME::Entity> object C<ENTITY>) using +RT's outgoing mail configuration. If C<BOUNCE> is passed, and is a +true value, the message will be marked as an autogenerated error, if +possible. Sets Date field of the head to now if it's not set. + +If the C<X-RT-Squelch> header is set to any true value, the mail will +not be sent. One use is to let extensions easily cancel outgoing mail. + +Ticket and Transaction arguments are optional. If Transaction is +specified and Ticket is not then ticket of the transaction is +used, but only if the transaction belongs to a ticket. + +Returns 1 on success, 0 on error or -1 if message has no recipients +and hasn't been sent. + +=head3 Signing and Encrypting + +This function as well signs and/or encrypts the message according to +headers of a transaction's attachment or properties of a ticket's queue. +To get full access to the configuration Ticket and/or Transaction +arguments must be provided, but you can force behaviour using Sign +and/or Encrypt arguments. + +The following precedence of arguments are used to figure out if +the message should be encrypted and/or signed: + +* if Sign or Encrypt argument is defined then its value is used + +* else if Transaction's first attachment has X-RT-Sign or X-RT-Encrypt +header field then it's value is used + +* else properties of a queue of the Ticket are used. + +=cut + +sub SendEmail { + my (%args) = ( + Entity => undef, + Bounce => 0, + Ticket => undef, + Transaction => undef, + @_, + ); + + my $TicketObj = $args{'Ticket'}; + my $TransactionObj = $args{'Transaction'}; + + foreach my $arg( qw(Entity Bounce) ) { + next unless defined $args{ lc $arg }; + + $RT::Logger->warning("'". lc($arg) ."' argument is deprecated, use '$arg' instead"); + $args{ $arg } = delete $args{ lc $arg }; + } + + unless ( $args{'Entity'} ) { + $RT::Logger->crit( "Could not send mail without 'Entity' object" ); + return 0; + } + + my $msgid = $args{'Entity'}->head->get('Message-ID') || ''; + chomp $msgid; - if ($RT::MailCommand eq 'sendmailpipe') { - open (MAIL, "|$RT::SendmailPath $RT::SendmailArguments") || return(0); - print MAIL $entity->as_string; - close(MAIL); + # If we don't have any recipients to send to, don't send a message; + unless ( $args{'Entity'}->head->get('To') + || $args{'Entity'}->head->get('Cc') + || $args{'Entity'}->head->get('Bcc') ) + { + $RT::Logger->info( $msgid . " No recipients found. Not sending." ); + return -1; + } + + if ($args{'Entity'}->head->get('X-RT-Squelch')) { + $RT::Logger->info( $msgid . " Squelch header found. Not sending." ); + return -1; + } + + if ( $TransactionObj && !$TicketObj + && $TransactionObj->ObjectType eq 'RT::Ticket' ) + { + $TicketObj = $TransactionObj->Object; + } + + if ( RT->Config->Get('GnuPG')->{'Enable'} ) { + my %crypt; + + my $attachment; + $attachment = $TransactionObj->Attachments->First + if $TransactionObj; + + foreach my $argument ( qw(Sign Encrypt) ) { + next if defined $args{ $argument }; + + if ( $attachment && defined $attachment->GetHeader("X-RT-$argument") ) { + $crypt{$argument} = $attachment->GetHeader("X-RT-$argument"); + } elsif ( $TicketObj ) { + $crypt{$argument} = $TicketObj->QueueObj->$argument(); + } + } + + my $res = SignEncrypt( %args, %crypt ); + return $res unless $res > 0; + } + + unless ( $args{'Entity'}->head->get('Date') ) { + require RT::Date; + my $date = RT::Date->new( $RT::SystemUser ); + $date->SetToNow; + $args{'Entity'}->head->set( 'Date', $date->RFC2822( Timezone => 'server' ) ); + } + + my $mail_command = RT->Config->Get('MailCommand'); + + if ($mail_command eq 'testfile' and not $Mail::Mailer::testfile::config{outfile}) { + $Mail::Mailer::testfile::config{outfile} = File::Temp->new; + $RT::Logger->info("Storing outgoing emails in $Mail::Mailer::testfile::config{outfile}"); + } + + # if it is a sub routine, we just return it; + return $mail_command->($args{'Entity'}) if UNIVERSAL::isa( $mail_command, 'CODE' ); + + if ( $mail_command eq 'sendmailpipe' ) { + my $path = RT->Config->Get('SendmailPath'); + my $args = RT->Config->Get('SendmailArguments'); + + # SetOutgoingMailFrom + if ( RT->Config->Get('SetOutgoingMailFrom') ) { + my $OutgoingMailAddress; + + if ($TicketObj) { + my $QueueName = $TicketObj->QueueObj->Name; + my $QueueAddressOverride = RT->Config->Get('OverrideOutgoingMailFrom')->{$QueueName}; + + if ($QueueAddressOverride) { + $OutgoingMailAddress = $QueueAddressOverride; + } else { + $OutgoingMailAddress = $TicketObj->QueueObj->CorrespondAddress; + } + } + + $OutgoingMailAddress ||= RT->Config->Get('OverrideOutgoingMailFrom')->{'Default'}; + + $args .= " -f $OutgoingMailAddress" + if $OutgoingMailAddress; + } + + # Set Bounce Arguments + $args .= ' '. RT->Config->Get('SendmailBounceArguments') if $args{'Bounce'}; + + # VERP + if ( $TransactionObj and + my $prefix = RT->Config->Get('VERPPrefix') and + my $domain = RT->Config->Get('VERPDomain') ) + { + my $from = $TransactionObj->CreatorObj->EmailAddress; + $from =~ s/@/=/g; + $from =~ s/\s//g; + $args .= " -f $prefix$from\@$domain"; + } + + eval { + # don't ignore CHLD signal to get proper exit code + local $SIG{'CHLD'} = 'DEFAULT'; + + open( my $mail, '|-', "$path $args >/dev/null" ) + or die "couldn't execute program: $!"; + + # if something wrong with $mail->print we will get PIPE signal, handle it + local $SIG{'PIPE'} = sub { die "program unexpectedly closed pipe" }; + $args{'Entity'}->print($mail); + + unless ( close $mail ) { + die "close pipe failed: $!" if $!; # system error + # sendmail exit statuses mostly errors with data not software + # TODO: status parsing: core dump, exit on signal or EX_* + my $msg = "$msgid: `$path $args` exitted with code ". ($?>>8); + $msg = ", interrupted by signal ". ($?&127) if $?&127; + $RT::Logger->error( $msg ); + die $msg; + } + }; + if ( $@ ) { + $RT::Logger->crit( "$msgid: Could not send mail with command `$path $args`: " . $@ ); + if ( $TicketObj ) { + _RecordSendEmailFailure( $TicketObj ); + } + return 0; + } + } + elsif ( $mail_command eq 'smtp' ) { + require Net::SMTP; + my $smtp = do { local $@; eval { Net::SMTP->new( + Host => RT->Config->Get('SMTPServer'), + Debug => RT->Config->Get('SMTPDebug'), + ) } }; + unless ( $smtp ) { + $RT::Logger->crit( "Could not connect to SMTP server."); + if ($TicketObj) { + _RecordSendEmailFailure( $TicketObj ); + } + return 0; + } + + # duplicate head as we want drop Bcc field + my $head = $args{'Entity'}->head->dup; + my @recipients = map $_->address, map + Email::Address->parse($head->get($_)), qw(To Cc Bcc); + $head->delete('Bcc'); + + my $sender = RT->Config->Get('SMTPFrom') + || $args{'Entity'}->head->get('From'); + chomp $sender; + + my $status = $smtp->mail( $sender ) + && $smtp->recipient( @recipients ); + + if ( $status ) { + $smtp->data; + my $fh = $smtp->tied_fh; + $head->print( $fh ); + print $fh "\n"; + $args{'Entity'}->print_body( $fh ); + $smtp->dataend; + } + $smtp->quit; + + unless ( $status ) { + $RT::Logger->crit( "$msgid: Could not send mail via SMTP." ); + if ( $TicketObj ) { + _RecordSendEmailFailure( $TicketObj ); + } + return 0; + } } else { - $entity->send($RT::MailCommand, $RT::MailParams); + local ($ENV{'MAILADDRESS'}, $ENV{'PERL_MAILERS'}); + + my @mailer_args = ($mail_command); + if ( $mail_command eq 'sendmail' ) { + $ENV{'PERL_MAILERS'} = RT->Config->Get('SendmailPath'); + push @mailer_args, split(/\s+/, RT->Config->Get('SendmailArguments')); + } + else { + push @mailer_args, RT->Config->Get('MailParams'); + } + + unless ( $args{'Entity'}->send( @mailer_args ) ) { + $RT::Logger->crit( "$msgid: Could not send mail." ); + if ( $TicketObj ) { + _RecordSendEmailFailure( $TicketObj ); + } + return 0; + } + } + return 1; +} + +=head2 PrepareEmailUsingTemplate Template => '', Arguments => {} + +Loads a template. Parses it using arguments if it's not empty. +Returns a tuple (L<RT::Template> object, error message). + +Note that even if a template object is returned MIMEObj method +may return undef for empty templates. + +=cut + +sub PrepareEmailUsingTemplate { + my %args = ( + Template => '', + Arguments => {}, + @_ + ); + + my $template = RT::Template->new( $RT::SystemUser ); + $template->LoadGlobalTemplate( $args{'Template'} ); + unless ( $template->id ) { + return (undef, "Couldn't load template '". $args{'Template'} ."'"); + } + return $template if $template->IsEmpty; + + my ($status, $msg) = $template->Parse( %{ $args{'Arguments'} } ); + return (undef, $msg) unless $status; + + return $template; +} + +=head2 SendEmailUsingTemplate Template => '', Arguments => {}, From => CorrespondAddress, To => '', Cc => '', Bcc => '' + +Sends email using a template, takes name of template, arguments for it and recipients. + +=cut + +sub SendEmailUsingTemplate { + my %args = ( + Template => '', + Arguments => {}, + To => undef, + Cc => undef, + Bcc => undef, + From => RT->Config->Get('CorrespondAddress'), + InReplyTo => undef, + @_ + ); + + my ($template, $msg) = PrepareEmailUsingTemplate( %args ); + return (0, $msg) unless $template; + + my $mail = $template->MIMEObj; + unless ( $mail ) { + $RT::Logger->info("Message is not sent as template #". $template->id ." is empty"); + return -1; + } + + $mail->head->set( $_ => Encode::encode_utf8( $args{ $_ } ) ) + foreach grep defined $args{$_}, qw(To Cc Bcc From); + + SetInReplyTo( Message => $mail, InReplyTo => $args{'InReplyTo'} ); + + return SendEmail( Entity => $mail ); +} + +=head2 ForwardTransaction TRANSACTION, To => '', Cc => '', Bcc => '' + +Forwards transaction with all attachments as 'message/rfc822'. + +=cut + +sub ForwardTransaction { + my $txn = shift; + my %args = ( To => '', Cc => '', Bcc => '', @_ ); + + my $entity = $txn->ContentAsMIME; + + return SendForward( %args, Entity => $entity, Transaction => $txn ); +} + +=head2 ForwardTicket TICKET, To => '', Cc => '', Bcc => '' + +Forwards a ticket's Create and Correspond Transactions and their Attachments as 'message/rfc822'. + +=cut + +sub ForwardTicket { + my $ticket = shift; + my %args = ( To => '', Cc => '', Bcc => '', @_ ); + + my $txns = $ticket->Transactions; + $txns->Limit( + FIELD => 'Type', + VALUE => $_, + ) for qw(Create Correspond); + + my $entity = MIME::Entity->build( + Type => 'multipart/mixed', + ); + $entity->add_part( $_ ) foreach + map $_->ContentAsMIME, + @{ $txns->ItemsArrayRef }; + + return SendForward( %args, Entity => $entity, Ticket => $ticket, Template => 'Forward Ticket' ); +} + +=head2 SendForward Entity => undef, Ticket => undef, Transaction => undef, Template => undef, To => '', Cc => '', Bcc => '' + +Forwards an Entity representing Ticket or Transaction as 'message/rfc822'. Entity is wrapped into Template. + +=cut + +sub SendForward { + my (%args) = ( + Entity => undef, + Ticket => undef, + Transaction => undef, + Template => 'Forward', + To => '', Cc => '', Bcc => '', + @_ + ); + + my $txn = $args{'Transaction'}; + my $ticket = $args{'Ticket'}; + $ticket ||= $txn->Object if $txn; + + my $entity = $args{'Entity'}; + unless ( $entity ) { + require Carp; + $RT::Logger->error(Carp::longmess("No entity provided")); + return (0, $ticket->loc("Couldn't send email")); } + + my ($template, $msg) = PrepareEmailUsingTemplate( + Template => $args{'Template'}, + Arguments => { + Ticket => $ticket, + Transaction => $txn, + }, + ); + + my $mail; + if ( $template ) { + $mail = $template->MIMEObj; + } else { + $RT::Logger->warning($msg); + } + unless ( $mail ) { + $RT::Logger->warning("Couldn't generate email using template '$args{Template}'"); + + my $description; + unless ( $args{'Transaction'} ) { + $description = 'This is forward of ticket #'. $ticket->id; + } else { + $description = 'This is forward of transaction #' + . $txn->id ." of a ticket #". $txn->ObjectId; + } + $mail = MIME::Entity->build( + Type => 'text/plain', + Data => $description, + ); + } + + $mail->head->set( $_ => EncodeToMIME( String => $args{$_} ) ) + foreach grep defined $args{$_}, qw(To Cc Bcc); + + $mail->attach( + Type => 'message/rfc822', + Disposition => 'attachment', + Description => 'forwarded message', + Data => $entity->as_string, + ); + + my $from; + my $subject = ''; + $subject = $txn->Subject if $txn; + $subject ||= $ticket->Subject if $ticket; + if ( RT->Config->Get('ForwardFromUser') ) { + $from = ($txn || $ticket)->CurrentUser->UserObj->EmailAddress; + } else { + # XXX: what if want to forward txn of other object than ticket? + $subject = AddSubjectTag( $subject, $ticket ); + $from = $ticket->QueueObj->CorrespondAddress + || RT->Config->Get('CorrespondAddress'); + } + $mail->head->set( Subject => EncodeToMIME( String => "Fwd: $subject" ) ); + $mail->head->set( From => EncodeToMIME( String => $from ) ); + + my $status = RT->Config->Get('ForwardFromUser') + # never sign if we forward from User + ? SendEmail( %args, Entity => $mail, Sign => 0 ) + : SendEmail( %args, Entity => $mail ); + return (0, $ticket->loc("Couldn't send email")) unless $status; + return (1, $ticket->loc("Send email successfully")); } -# }}} +=head2 SignEncrypt Entity => undef, Sign => 0, Encrypt => 0 + +Signs and encrypts message using L<RT::Crypt::GnuPG>, but as well +handle errors with users' keys. + +If a recipient has no key or has other problems with it, then the +unction sends a error to him using 'Error: public key' template. +Also, notifies RT's owner using template 'Error to RT owner: public key' +to inform that there are problems with users' keys. Then we filter +all bad recipients and retry. -# {{{ Create User +Returns 1 on success, 0 on error and -1 if all recipients are bad and +had been filtered out. + +=cut + +sub SignEncrypt { + my %args = ( + Entity => undef, + Sign => 0, + Encrypt => 0, + @_ + ); + return 1 unless $args{'Sign'} || $args{'Encrypt'}; + + my $msgid = $args{'Entity'}->head->get('Message-ID') || ''; + chomp $msgid; + + $RT::Logger->debug("$msgid Signing message") if $args{'Sign'}; + $RT::Logger->debug("$msgid Encrypting message") if $args{'Encrypt'}; + + require RT::Crypt::GnuPG; + my %res = RT::Crypt::GnuPG::SignEncrypt( %args ); + return 1 unless $res{'exit_code'}; + + my @status = RT::Crypt::GnuPG::ParseStatus( $res{'status'} ); + + my @bad_recipients; + foreach my $line ( @status ) { + # if the passphrase fails, either you have a bad passphrase + # or gpg-agent has died. That should get caught in Create and + # Update, but at least throw an error here + if (($line->{'Operation'}||'') eq 'PassphraseCheck' + && $line->{'Status'} =~ /^(?:BAD|MISSING)$/ ) { + $RT::Logger->error( "$line->{'Status'} PASSPHRASE: $line->{'Message'}" ); + return 0; + } + next unless ($line->{'Operation'}||'') eq 'RecipientsCheck'; + next if $line->{'Status'} eq 'DONE'; + $RT::Logger->error( $line->{'Message'} ); + push @bad_recipients, $line; + } + return 0 unless @bad_recipients; + + $_->{'AddressObj'} = (Email::Address->parse( $_->{'Recipient'} ))[0] + foreach @bad_recipients; + + foreach my $recipient ( @bad_recipients ) { + my $status = SendEmailUsingTemplate( + To => $recipient->{'AddressObj'}->address, + Template => 'Error: public key', + Arguments => { + %$recipient, + TicketObj => $args{'Ticket'}, + TransactionObj => $args{'Transaction'}, + }, + ); + unless ( $status ) { + $RT::Logger->error("Couldn't send 'Error: public key'"); + } + } + + my $status = SendEmailUsingTemplate( + To => RT->Config->Get('OwnerEmail'), + Template => 'Error to RT owner: public key', + Arguments => { + BadRecipients => \@bad_recipients, + TicketObj => $args{'Ticket'}, + TransactionObj => $args{'Transaction'}, + }, + ); + unless ( $status ) { + $RT::Logger->error("Couldn't send 'Error to RT owner: public key'"); + } + + DeleteRecipientsFromHead( + $args{'Entity'}->head, + map $_->{'AddressObj'}->address, @bad_recipients + ); + + unless ( $args{'Entity'}->head->get('To') + || $args{'Entity'}->head->get('Cc') + || $args{'Entity'}->head->get('Bcc') ) + { + $RT::Logger->debug("$msgid No recipients that have public key, not sending"); + return -1; + } + + # redo without broken recipients + %res = RT::Crypt::GnuPG::SignEncrypt( %args ); + return 0 if $res{'exit_code'}; + + return 1; +} + +use MIME::Words (); + +=head2 EncodeToMIME + +Takes a hash with a String and a Charset. Returns the string encoded +according to RFC2047, using B (base64 based) encoding. + +String must be a perl string, octets are returned. + +If Charset is not provided then $EmailOutputEncoding config option +is used, or "latin-1" if that is not set. + +=cut + +sub EncodeToMIME { + my %args = ( + String => undef, + Charset => undef, + @_ + ); + my $value = $args{'String'}; + return $value unless $value; # 0 is perfect ascii + my $charset = $args{'Charset'} || RT->Config->Get('EmailOutputEncoding'); + my $encoding = 'B'; + + # using RFC2047 notation, sec 2. + # encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" + + # An 'encoded-word' may not be more than 75 characters long + # + # MIME encoding increases 4/3*(number of bytes), and always in multiples + # of 4. Thus we have to find the best available value of bytes available + # for each chunk. + # + # First we get the integer max which max*4/3 would fit on space. + # Then we find the greater multiple of 3 lower or equal than $max. + my $max = int( + ( ( 75 - length( '=?' . $charset . '?' . $encoding . '?' . '?=' ) ) + * 3 + ) / 4 + ); + $max = int( $max / 3 ) * 3; + + chomp $value; + + if ( $max <= 0 ) { + + # gives an error... + $RT::Logger->crit("Can't encode! Charset or encoding too big."); + return ($value); + } + + return ($value) unless $value =~ /[^\x20-\x7e]/; + + $value =~ s/\s+$//; + + # we need perl string to split thing char by char + Encode::_utf8_on($value) unless Encode::is_utf8($value); + + my ( $tmp, @chunks ) = ( '', () ); + while ( length $value ) { + my $char = substr( $value, 0, 1, '' ); + my $octets = Encode::encode( $charset, $char ); + if ( length($tmp) + length($octets) > $max ) { + push @chunks, $tmp; + $tmp = ''; + } + $tmp .= $octets; + } + push @chunks, $tmp if length $tmp; + + # encode an join chuncks + $value = join "\n ", + map MIME::Words::encode_mimeword( $_, $encoding, $charset ), + @chunks; + return ($value); +} sub CreateUser { - my ($Username, $Address, $Name, $ErrorsTo, $entity) = @_; - my $NewUser = RT::User->new($RT::SystemUser); - - # This data is tainted by some Very Broken mailers. - # (Sometimes they send raw ISO 8859-1 data here. fear that. - require Encode; - $Username = Encode::encode(utf8 => $Username, Encode::FB_PERLQQ()) if defined $Username; - $Name = Encode::encode(utf8 => $Name, Encode::FB_PERLQQ()) if defined $Name; - - my ($Val, $Message) = - $NewUser->Create(Name => ($Username || $Address), - EmailAddress => $Address, - RealName => $Name, - Password => undef, - Privileged => 0, - Comments => 'Autocreated on ticket submission' - ); - + my ( $Username, $Address, $Name, $ErrorsTo, $entity ) = @_; + + my $NewUser = RT::User->new( $RT::SystemUser ); + + my ( $Val, $Message ) = $NewUser->Create( + Name => ( $Username || $Address ), + EmailAddress => $Address, + RealName => $Name, + Password => undef, + Privileged => 0, + Comments => 'Autocreated on ticket submission', + ); + unless ($Val) { - + # Deal with the race condition of two account creations at once - # if ($Username) { $NewUser->LoadByName($Username); } - - unless ($NewUser->Id) { + + unless ( $NewUser->Id ) { $NewUser->LoadByEmail($Address); } - - unless ($NewUser->Id) { - MailError( To => $ErrorsTo, - Subject => "User could not be created", - Explanation => "User creation failed in mailgateway: $Message", - MIMEObj => $entity, - LogLevel => 'crit' - ); + + unless ( $NewUser->Id ) { + MailError( + To => $ErrorsTo, + Subject => "User could not be created", + Explanation => + "User creation failed in mailgateway: $Message", + MIMEObj => $entity, + LogLevel => 'crit', + ); } } #Load the new user object - my $CurrentUser = RT::CurrentUser->new(); - $CurrentUser->LoadByEmail($Address); + my $CurrentUser = new RT::CurrentUser; + $CurrentUser->LoadByEmail( $Address ); - unless ($CurrentUser->id) { - $RT::Logger->warning("Couldn't load user '$Address'.". "giving up"); - MailError( To => $ErrorsTo, - Subject => "User could not be loaded", - Explanation => "User '$Address' could not be loaded in the mail gateway", - MIMEObj => $entity, - LogLevel => 'crit' - ); + unless ( $CurrentUser->id ) { + $RT::Logger->warning( + "Couldn't load user '$Address'." . "giving up" ); + MailError( + To => $ErrorsTo, + Subject => "User could not be loaded", + Explanation => + "User '$Address' could not be loaded in the mail gateway", + MIMEObj => $entity, + LogLevel => 'crit' + ); } return $CurrentUser; } -# }}} -# {{{ ParseCcAddressesFromHead -=head2 ParseCcAddressesFromHead HASHREF -Takes a hashref object containing QueueObj, Head and CurrentUser objects. -Returns a list of all email addresses in the To and Cc -headers b<except> the current Queue\'s email addresses, the CurrentUser\'s + +=head2 ParseCcAddressesFromHead HASH + +Takes a hash containing QueueObj, Head and CurrentUser objects. +Returns a list of all email addresses in the To and Cc +headers b<except> the current Queue\'s email addresses, the CurrentUser\'s email address and anything that the configuration sub RT::IsRTAddress matches. =cut - + sub ParseCcAddressesFromHead { - my %args = ( Head => undef, - QueueObj => undef, - CurrentUser => undef, - @_ ); - - my (@Addresses); - - my @ToObjs = Mail::Address->parse($args{'Head'}->get('To')); - my @CcObjs = Mail::Address->parse($args{'Head'}->get('Cc')); - - foreach my $AddrObj (@ToObjs, @CcObjs) { - my $Address = $AddrObj->address; - $Address = $args{'CurrentUser'}->UserObj->CanonicalizeEmailAddress($Address); - next if ($args{'CurrentUser'}->EmailAddress =~ /^$Address$/i); - next if ($args{'QueueObj'}->CorrespondAddress =~ /^$Address$/i); - next if ($args{'QueueObj'}->CommentAddress =~ /^$Address$/i); - next if (RT::EmailParser::IsRTAddress(undef, $Address)); - - push (@Addresses, $Address); - } - return (@Addresses); + my %args = ( + Head => undef, + QueueObj => undef, + CurrentUser => undef, + @_ + ); + + my $current_address = lc $args{'CurrentUser'}->EmailAddress; + my $user = $args{'CurrentUser'}->UserObj; + + return + grep $_ ne $current_address && !RT::EmailParser->IsRTAddress( $_ ), + map lc $user->CanonicalizeEmailAddress( $_->address ), + map Email::Address->parse( $args{'Head'}->get( $_ ) ), + qw(To Cc); } -# }}} -# {{{ ParseSenderAdddressFromHead +=head2 ParseSenderAddressFromHead HEAD -=head2 ParseSenderAddressFromHead - -Takes a MIME::Header object. Returns a tuple: (user@host, friendly name) +Takes a MIME::Header object. Returns a tuple: (user@host, friendly name) of the From (evaluated in order of Reply-To:, From:, Sender) =cut sub ParseSenderAddressFromHead { my $head = shift; + #Figure out who's sending this message. - my $From = $head->get('Reply-To') || - $head->get('From') || - $head->get('Sender'); - return (ParseAddressFromHeader($From)); -} -# }}} + foreach my $header ('Reply-To', 'From', 'Sender') { + my $addr_line = $head->get($header) || next; + my ($addr, $name) = ParseAddressFromHeader( $addr_line ); + # only return if the address is not empty + return ($addr, $name) if $addr; + } -# {{{ ParseErrorsToAdddressFromHead + return (undef, undef); +} -=head2 ParseErrorsToAddressFromHead +=head2 ParseErrorsToAddressFromHead HEAD Takes a MIME::Header object. Return a single value : user@host -of the From (evaluated in order of Errors-To:,Reply-To:, From:, Sender) +of the From (evaluated in order of Return-path:,Errors-To:,Reply-To:, +From:, Sender) =cut sub ParseErrorsToAddressFromHead { my $head = shift; + #Figure out who's sending this message. - foreach my $header ('Errors-To' , 'Reply-To', 'From', 'Sender' ) { - # If there's a header of that name - my $headerobj = $head->get($header); - if ($headerobj) { - my ($addr, $name ) = ParseAddressFromHeader($headerobj); - # If it's got actual useful content... - return ($addr) if ($addr); - } + foreach my $header ( 'Errors-To', 'Reply-To', 'From', 'Sender' ) { + + # If there's a header of that name + my $headerobj = $head->get($header); + if ($headerobj) { + my ( $addr, $name ) = ParseAddressFromHeader($headerobj); + + # If it's got actual useful content... + return ($addr) if ($addr); + } } } -# }}} -# {{{ ParseAddressFromHeader + =head2 ParseAddressFromHeader ADDRESS -Takes an address from $head->get('Line') and returns a tuple: user@host, friendly name +Takes an address from C<$head->get('Line')> and returns a tuple: user@host, friendly name =cut - -sub ParseAddressFromHeader{ +sub ParseAddressFromHeader { my $Addr = shift; - - my @Addresses = Mail::Address->parse($Addr); - - my $AddrObj = $Addresses[0]; - unless (ref($AddrObj)) { - return(undef,undef); + # Some broken mailers send: ""Vincent, Jesse"" <jesse@fsck.com>. Hate + $Addr =~ s/\"\"(.*?)\"\"/\"$1\"/g; + my @Addresses = RT::EmailParser->ParseEmailAddress($Addr); + + my ($AddrObj) = grep ref $_, @Addresses; + unless ( $AddrObj ) { + return ( undef, undef ); } - - my $Name = ($AddrObj->phrase || $AddrObj->comment || $AddrObj->address); - + + my $Name = ( $AddrObj->name || $AddrObj->phrase || $AddrObj->comment || $AddrObj->address ); + #Lets take the from and load a user object. my $Address = $AddrObj->address; - return ($Address, $Name); + return ( $Address, $Name ); +} + +=head2 DeleteRecipientsFromHead HEAD RECIPIENTS + +Gets a head object and list of addresses. +Deletes addresses from To, Cc or Bcc fields. + +=cut + +sub DeleteRecipientsFromHead { + my $head = shift; + my %skip = map { lc $_ => 1 } @_; + + foreach my $field ( qw(To Cc Bcc) ) { + $head->set( $field => + join ', ', map $_->format, grep !$skip{ lc $_->address }, + Email::Address->parse( $head->get( $field ) ) + ); + } +} + +sub GenMessageId { + my %args = ( + Ticket => undef, + Scrip => undef, + ScripAction => undef, + @_ + ); + my $org = RT->Config->Get('Organization'); + my $ticket_id = ( ref $args{'Ticket'}? $args{'Ticket'}->id : $args{'Ticket'} ) || 0; + my $scrip_id = ( ref $args{'Scrip'}? $args{'Scrip'}->id : $args{'Scrip'} ) || 0; + my $sent = ( ref $args{'ScripAction'}? $args{'ScripAction'}->{'_Message_ID'} : 0 ) || 0; + + return "<rt-". $RT::VERSION ."-". $$ ."-". CORE::time() ."-". int(rand(2000)) .'.' + . $ticket_id ."-". $scrip_id ."-". $sent ."@". $org .">" ; } -# }}} +sub SetInReplyTo { + my %args = ( + Message => undef, + InReplyTo => undef, + Ticket => undef, + @_ + ); + return unless $args{'Message'} && $args{'InReplyTo'}; + + my $get_header = sub { + my @res; + if ( $args{'InReplyTo'}->isa('MIME::Entity') ) { + @res = $args{'InReplyTo'}->head->get( shift ); + } else { + @res = $args{'InReplyTo'}->GetHeader( shift ) || ''; + } + return grep length, map { split /\s+/m, $_ } grep defined, @res; + }; + + my @id = $get_header->('Message-ID'); + #XXX: custom header should begin with X- otherwise is violation of the standard + my @rtid = $get_header->('RT-Message-ID'); + my @references = $get_header->('References'); + unless ( @references ) { + @references = $get_header->('In-Reply-To'); + } + push @references, @id, @rtid; + if ( $args{'Ticket'} ) { + my $pseudo_ref = '<RT-Ticket-'. $args{'Ticket'}->id .'@'. RT->Config->Get('Organization') .'>'; + push @references, $pseudo_ref unless grep $_ eq $pseudo_ref, @references; + } + @references = splice @references, 4, -6 + if @references > 10; + + my $mail = $args{'Message'}; + $mail->head->set( 'In-Reply-To' => join ' ', @rtid? (@rtid) : (@id) ) if @id || @rtid; + $mail->head->set( 'References' => join ' ', @references ); +} +sub ParseTicketId { + my $Subject = shift; + + my $rtname = RT->Config->Get('rtname'); + my $test_name = RT->Config->Get('EmailSubjectTagRegex') || qr/\Q$rtname\E/i; + + my $id; + if ( $Subject =~ s/\[$test_name\s+\#(\d+)\s*\]//i ) { + $id = $1; + } else { + foreach my $tag ( RT->System->SubjectTag ) { + next unless $Subject =~ s/\[\Q$tag\E\s+\#(\d+)\s*\]//i; + $id = $1; + last; + } + } + return undef unless $id; + + $RT::Logger->debug("Found a ticket ID. It's $id"); + return $id; +} + +sub AddSubjectTag { + my $subject = shift; + my $ticket = shift; + unless ( ref $ticket ) { + my $tmp = RT::Ticket->new( $RT::SystemUser ); + $tmp->Load( $ticket ); + $ticket = $tmp; + } + my $id = $ticket->id; + my $queue_tag = $ticket->QueueObj->SubjectTag; + + my $tag_re = RT->Config->Get('EmailSubjectTagRegex'); + unless ( $tag_re ) { + my $tag = $queue_tag || RT->Config->Get('rtname'); + $tag_re = qr/\Q$tag\E/; + } elsif ( $queue_tag ) { + $tag_re = qr/$tag_re|\Q$queue_tag\E/; + } + return $subject if $subject =~ /\[$tag_re\s+#$id\]/; + + $subject =~ s/(\r\n|\n|\s)/ /gi; + chomp $subject; + return "[". ($queue_tag || RT->Config->Get('rtname')) ." #$id] $subject"; +} + + +=head2 Gateway ARGSREF + + +Takes parameters: + + action + queue + message -=head2 Gateway This performs all the "guts" of the mail rt-mailgate program, and is designed to be called from the web interface with a message, user object, and so on. +Can also take an optional 'ticket' parameter; this ticket id overrides +any ticket id found in the subject. + +Returns: + + An array of: + + (status code, message, optional ticket object) + + status code is a numeric value. + + for temporary failures, the status code should be -75 + + for permanent failures which are handled by RT, the status code + should be 0 + + for succces, the status code should be 1 + + + =cut +sub _LoadPlugins { + my @mail_plugins = @_; + + my @res; + foreach my $plugin (@mail_plugins) { + if ( ref($plugin) eq "CODE" ) { + push @res, $plugin; + } elsif ( !ref $plugin ) { + my $Class = $plugin; + $Class = "RT::Interface::Email::" . $Class + unless $Class =~ /^RT::Interface::Email::/; + $Class->require or + do { $RT::Logger->error("Couldn't load $Class: $@"); next }; + + no strict 'refs'; + unless ( defined *{ $Class . "::GetCurrentUser" }{CODE} ) { + $RT::Logger->crit( "No GetCurrentUser code found in $Class module"); + next; + } + push @res, $Class; + } else { + $RT::Logger->crit( "$plugin - is not class name or code reference"); + } + } + return @res; +} + sub Gateway { - my %args = ( message => undef, - queue => 1, - action => 'correspond', - ticket => undef, - @_ ); + my $argsref = shift; + my %args = ( + action => 'correspond', + queue => '1', + ticket => undef, + message => undef, + %$argsref + ); - # Validate the action - unless ( $args{'action'} =~ /^(comment|correspond|action)$/ ) { + my $SystemTicket; + my $Right; - # Can't safely loc this. What object do we loc around? - return ( 0, "Invalid 'action' parameter", undef ); + # Validate the action + my ( $status, @actions ) = IsCorrectAction( $args{'action'} ); + unless ($status) { + return ( + -75, + "Invalid 'action' parameter " + . $actions[0] + . " for queue " + . $args{'queue'}, + undef + ); } my $parser = RT::EmailParser->new(); - $parser->ParseMIMEEntityFromScalar( $args{'message'} ); + $parser->SmartParseMIMEEntityFromScalar( + Message => $args{'message'}, + Decode => 0, + Exact => 1, + ); my $Message = $parser->Entity(); - my $head = $Message->head; + unless ($Message) { + MailError( + Subject => "RT Bounce: Unparseable message", + Explanation => "RT couldn't process the message below", + Attach => $args{'message'} + ); + + return ( 0, + "Failed to parse this message. Something is likely badly wrong with the message" + ); + } + + my @mail_plugins = grep $_, RT->Config->Get('MailPlugins'); + push @mail_plugins, "Auth::MailFrom" unless @mail_plugins; + @mail_plugins = _LoadPlugins( @mail_plugins ); + + my %skip_plugin; + foreach my $class( grep !ref, @mail_plugins ) { + # check if we should apply filter before decoding + my $check_cb = do { + no strict 'refs'; + *{ $class . "::ApplyBeforeDecode" }{CODE}; + }; + next unless defined $check_cb; + next unless $check_cb->( + Message => $Message, + RawMessageRef => \$args{'message'}, + ); - my ( $CurrentUser, $AuthStat, $status, $error ); + $skip_plugin{ $class }++; - my $ErrorsTo = ParseErrorsToAddressFromHead($head); + my $Code = do { + no strict 'refs'; + *{ $class . "::GetCurrentUser" }{CODE}; + }; + my ($status, $msg) = $Code->( + Message => $Message, + RawMessageRef => \$args{'message'}, + ); + next if $status > 0; + + if ( $status == -2 ) { + return (1, $msg, undef); + } elsif ( $status == -1 ) { + return (0, $msg, undef); + } + } + @mail_plugins = grep !$skip_plugin{"$_"}, @mail_plugins; + $parser->_DecodeBodies; + $parser->_PostProcessNewEntity; - my $MessageId = $head->get('Message-Id') - || "<no-message-id-" . time . rand(2000) . "\@.$RT::Organization>"; + my $head = $Message->head; + my $ErrorsTo = ParseErrorsToAddressFromHead( $head ); + + my $MessageId = $head->get('Message-ID') + || "<no-message-id-". time . rand(2000) .'@'. RT->Config->Get('Organization') .'>'; #Pull apart the subject line my $Subject = $head->get('Subject') || ''; chomp $Subject; + + # {{{ Lets check for mail loops of various sorts. + my ($should_store_machine_generated_message, $IsALoop, $result); + ( $should_store_machine_generated_message, $ErrorsTo, $result, $IsALoop ) = + _HandleMachineGeneratedMail( + Message => $Message, + ErrorsTo => $ErrorsTo, + Subject => $Subject, + MessageId => $MessageId + ); + + # Do not pass loop messages to MailPlugins, to make sure the loop + # is broken, unless $RT::StoreLoops is set. + if ($IsALoop && !$should_store_machine_generated_message) { + return ( 0, $result, undef ); + } + # }}} + $args{'ticket'} ||= ParseTicketId( $Subject ); - $args{'ticket'} ||= $parser->ParseTicketId($Subject); - - my $SystemTicket; - if ($args{'ticket'} ) { - $SystemTicket = RT::Ticket->new($RT::SystemUser); - $SystemTicket->Load($args{'ticket'}); + $SystemTicket = RT::Ticket->new( $RT::SystemUser ); + $SystemTicket->Load( $args{'ticket'} ) if ( $args{'ticket'} ) ; + if ( $SystemTicket->id ) { + $Right = 'ReplyToTicket'; + } else { + $Right = 'CreateTicket'; } #Set up a queue object - my $SystemQueueObj = RT::Queue->new($RT::SystemUser); + my $SystemQueueObj = RT::Queue->new( $RT::SystemUser ); $SystemQueueObj->Load( $args{'queue'} ); - # We can safely have no queue of we have a known-good ticket - unless ( $args{'ticket'} || $SystemQueueObj->id ) { + unless ( $SystemTicket->id || $SystemQueueObj->id ) { + return ( -75, "RT couldn't find the queue: " . $args{'queue'}, undef ); + } + + my ($AuthStat, $CurrentUser, $error) = GetAuthenticationLevel( + MailPlugins => \@mail_plugins, + Actions => \@actions, + Message => $Message, + RawMessageRef => \$args{message}, + SystemTicket => $SystemTicket, + SystemQueue => $SystemQueueObj, + ); + + # {{{ If authentication fails and no new user was created, get out. + if ( !$CurrentUser || !$CurrentUser->id || $AuthStat == -1 ) { + + # If the plugins refused to create one, they lose. + unless ( $AuthStat == -1 ) { + _NoAuthorizedUserFound( + Right => $Right, + Message => $Message, + Requestor => $ErrorsTo, + Queue => $args{'queue'} + ); + + } + return ( 0, "Could not load a valid user", undef ); + } + + # If we got a user, but they don't have the right to say things + if ( $AuthStat == 0 ) { MailError( - To => $RT::OwnerEmail, - Subject => "RT Bounce: $Subject", - Explanation => "RT couldn't find the queue: " . $args{'queue'}, - MIMEObj => $Message ); - return ( 0, "RT couldn't find the queue: " . $args{'queue'}, undef ); + To => $ErrorsTo, + Subject => "Permission Denied", + Explanation => + "You do not have permission to communicate with RT", + MIMEObj => $Message + ); + return ( + 0, + "$ErrorsTo tried to submit a message to " + . $args{'Queue'} + . " without permission.", + undef + ); + } + + + unless ($should_store_machine_generated_message) { + return ( 0, $result, undef ); } + # if plugin's updated SystemTicket then update arguments + $args{'ticket'} = $SystemTicket->Id if $SystemTicket && $SystemTicket->Id; + + my $Ticket = RT::Ticket->new($CurrentUser); + + if ( !$args{'ticket'} && grep /^(comment|correspond)$/, @actions ) + { + + my @Cc; + my @Requestors = ( $CurrentUser->id ); + + if (RT->Config->Get('ParseNewMessageForTicketCcs')) { + @Cc = ParseCcAddressesFromHead( + Head => $head, + CurrentUser => $CurrentUser, + QueueObj => $SystemQueueObj + ); + } + + my ( $id, $Transaction, $ErrStr ) = $Ticket->Create( + Queue => $SystemQueueObj->Id, + Subject => $Subject, + Requestor => \@Requestors, + Cc => \@Cc, + MIMEObj => $Message + ); + if ( $id == 0 ) { + MailError( + To => $ErrorsTo, + Subject => "Ticket creation failed: $Subject", + Explanation => $ErrStr, + MIMEObj => $Message + ); + return ( 0, "Ticket creation failed: $ErrStr", $Ticket ); + } + + # strip comments&corresponds from the actions we don't need + # to record them if we've created the ticket just now + @actions = grep !/^(comment|correspond)$/, @actions; + $args{'ticket'} = $id; + + } elsif ( $args{'ticket'} ) { + + $Ticket->Load( $args{'ticket'} ); + unless ( $Ticket->Id ) { + my $error = "Could not find a ticket with id " . $args{'ticket'}; + MailError( + To => $ErrorsTo, + Subject => "Message not recorded: $Subject", + Explanation => $error, + MIMEObj => $Message + ); + + return ( 0, $error ); + } + $args{'ticket'} = $Ticket->id; + } else { + return ( 1, "Success", $Ticket ); + } + + # }}} + + my $unsafe_actions = RT->Config->Get('UnsafeEmailCommands'); + foreach my $action (@actions) { + + # If the action is comment, add a comment. + if ( $action =~ /^(?:comment|correspond)$/i ) { + my $method = ucfirst lc $action; + my ( $status, $msg ) = $Ticket->$method( MIMEObj => $Message ); + unless ($status) { + + #Warn the sender that we couldn't actually submit the comment. + MailError( + To => $ErrorsTo, + Subject => "Message not recorded: $Subject", + Explanation => $msg, + MIMEObj => $Message + ); + return ( 0, "Message not recorded: $msg", $Ticket ); + } + } elsif ($unsafe_actions) { + my ( $status, $msg ) = _RunUnsafeAction( + Action => $action, + ErrorsTo => $ErrorsTo, + Message => $Message, + Ticket => $Ticket, + CurrentUser => $CurrentUser, + ); + return ($status, $msg, $Ticket) unless $status == 1; + } + } + return ( 1, "Success", $Ticket ); +} + +=head2 GetAuthenticationLevel + # Authentication Level - # -1 - Get out. this user has been explicitly declined + # -1 - Get out. this user has been explicitly declined # 0 - User may not do anything (Not used at the moment) # 1 - Normal user # 2 - User is allowed to specify status updates etc. a la enhanced-mailgate - push @RT::MailPlugins, "Auth::MailFrom" unless @RT::MailPlugins; - # Since this needs loading, no matter what +=cut - for (@RT::MailPlugins) { - my $Code; - my $NewAuthStat; +sub GetAuthenticationLevel { + my %args = ( + MailPlugins => [], + Actions => [], + Message => undef, + RawMessageRef => undef, + SystemTicket => undef, + SystemQueue => undef, + @_, + ); + + my ( $CurrentUser, $AuthStat, $error ); + + # Initalize AuthStat so comparisons work correctly + $AuthStat = -9999999; + + # if plugin returns AuthStat -2 we skip action + # NOTE: this is experimental API and it would be changed + my %skip_action = (); + + # Since this needs loading, no matter what + foreach (@{ $args{MailPlugins} }) { + my ($Code, $NewAuthStat); if ( ref($_) eq "CODE" ) { $Code = $_; - } - else { - $_ = "RT::Interface::Email::$_" unless /^RT::Interface::Email::/; - eval "require $_;"; - if ($@) { - die ("Couldn't load module $_: $@"); - next; - } + } else { no strict 'refs'; - if ( !defined( $Code = *{ $_ . "::GetCurrentUser" }{CODE} ) ) { - die ("No GetCurrentUser code found in $_ module"); - next; - } + $Code = *{ $_ . "::GetCurrentUser" }{CODE}; } - ( $CurrentUser, $NewAuthStat ) = $Code->( Message => $Message, - CurrentUser => $CurrentUser, - AuthLevel => $AuthStat, - Action => $args{'action'}, - Ticket => $SystemTicket, - Queue => $SystemQueueObj ); + foreach my $action (@{ $args{Actions} }) { + ( $CurrentUser, $NewAuthStat ) = $Code->( + Message => $args{Message}, + RawMessageRef => $args{RawMessageRef}, + CurrentUser => $CurrentUser, + AuthLevel => $AuthStat, + Action => $action, + Ticket => $args{SystemTicket}, + Queue => $args{SystemQueue}, + ); + +# You get the highest level of authentication you were assigned, unless you get the magic -1 +# If a module returns a "-1" then we discard the ticket, so. + $AuthStat = $NewAuthStat + if ( $NewAuthStat > $AuthStat or $NewAuthStat == -1 or $NewAuthStat == -2 ); + + last if $AuthStat == -1; + $skip_action{$action}++ if $AuthStat == -2; + } + + # strip actions we should skip + @{$args{Actions}} = grep !$skip_action{$_}, @{$args{Actions}} + if $AuthStat == -2; + last unless @{$args{Actions}}; - # You get the highest level of authentication you were assigned. last if $AuthStat == -1; - $AuthStat = $NewAuthStat if $NewAuthStat > $AuthStat; } - # {{{ If authentication fails and no new user was created, get out. - if ( !$CurrentUser or !$CurrentUser->Id or $AuthStat == -1 ) { + return $AuthStat if !wantarray; - # If the plugins refused to create one, they lose. - MailError( - Subject => "Could not load a valid user", - Explanation => <<EOT, + return ($AuthStat, $CurrentUser, $error); +} + +sub _RunUnsafeAction { + my %args = ( + Action => undef, + ErrorsTo => undef, + Message => undef, + Ticket => undef, + CurrentUser => undef, + @_ + ); + + if ( $args{'Action'} =~ /^take$/i ) { + my ( $status, $msg ) = $args{'Ticket'}->SetOwner( $args{'CurrentUser'}->id ); + unless ($status) { + MailError( + To => $args{'ErrorsTo'}, + Subject => "Ticket not taken", + Explanation => $msg, + MIMEObj => $args{'Message'} + ); + return ( 0, "Ticket not taken" ); + } + } elsif ( $args{'Action'} =~ /^resolve$/i ) { + my ( $status, $msg ) = $args{'Ticket'}->SetStatus('resolved'); + unless ($status) { + + #Warn the sender that we couldn't actually submit the comment. + MailError( + To => $args{'ErrorsTo'}, + Subject => "Ticket not resolved", + Explanation => $msg, + MIMEObj => $args{'Message'} + ); + return ( 0, "Ticket not resolved" ); + } + } else { + return ( 0, "Not supported unsafe action $args{'Action'}", $args{'Ticket'} ); + } + return ( 1, "Success" ); +} + +=head2 _NoAuthorizedUserFound + +Emails the RT Owner and the requestor when the auth plugins return "No auth user found" + +=cut + +sub _NoAuthorizedUserFound { + my %args = ( + Right => undef, + Message => undef, + Requestor => undef, + Queue => undef, + @_ + ); + + # Notify the RT Admin of the failure. + MailError( + To => RT->Config->Get('OwnerEmail'), + Subject => "Could not load a valid user", + Explanation => <<EOT, RT could not load a valid user, and RT's configuration does not allow -for the creation of a new user for your email. +for the creation of a new user for this email (@{[$args{Requestor}]}). -Your RT administrator needs to grant 'Everyone' the right 'CreateTicket' -for this queue. +You might need to grant 'Everyone' the right '@{[$args{Right}]}' for the +queue @{[$args{'Queue'}]}. EOT - MIMEObj => $Message, - LogLevel => 'error' ) - unless $AuthStat == -1; - return ( 0, "Could not load a valid user", undef ); + MIMEObj => $args{'Message'}, + LogLevel => 'error' + ); + + # Also notify the requestor that his request has been dropped. + if ($args{'Requestor'} ne RT->Config->Get('OwnerEmail')) { + MailError( + To => $args{'Requestor'}, + Subject => "Could not load a valid user", + Explanation => <<EOT, +RT could not load a valid user, and RT's configuration does not allow +for the creation of a new user for your email. + +EOT + MIMEObj => $args{'Message'}, + LogLevel => 'error' + ); } +} - # }}} +=head2 _HandleMachineGeneratedMail + +Takes named params: + Message + ErrorsTo + Subject + +Checks the message to see if it's a bounce, if it looks like a loop, if it's autogenerated, etc. +Returns a triple of ("Should we continue (boolean)", "New value for $ErrorsTo", "Status message", +"This message appears to be a loop (boolean)" ); + +=cut + +sub _HandleMachineGeneratedMail { + my %args = ( Message => undef, ErrorsTo => undef, Subject => undef, MessageId => undef, @_ ); + my $head = $args{'Message'}->head; + my $ErrorsTo = $args{'ErrorsTo'}; + + my $IsBounce = CheckForBounce($head); - # {{{ Lets check for mail loops of various sorts. my $IsAutoGenerated = CheckForAutoGenerated($head); my $IsSuspiciousSender = CheckForSuspiciousSender($head); @@ -496,153 +1726,89 @@ EOT my $SquelchReplies = 0; + my $owner_mail = RT->Config->Get('OwnerEmail'); + #If the message is autogenerated, we need to know, so we can not # send mail to the sender - if ( $IsSuspiciousSender || $IsAutoGenerated || $IsALoop ) { + if ( $IsBounce || $IsSuspiciousSender || $IsAutoGenerated || $IsALoop ) { $SquelchReplies = 1; - $ErrorsTo = $RT::OwnerEmail; + $ErrorsTo = $owner_mail; } - # }}} - - # {{{ Drop it if it's disallowed - if ( $AuthStat == 0 ) { - MailError( - To => $ErrorsTo, - Subject => "Permission Denied", - Explanation => "You do not have permission to communicate with RT", - MIMEObj => $Message ); - } - - # }}} - # {{{ Warn someone if it's a loop - # Warn someone if it's a loop, before we drop it on the ground if ($IsALoop) { - $RT::Logger->crit("RT Recieved mail ($MessageId) from itself."); + $RT::Logger->crit("RT Received mail (".$args{MessageId}.") from itself."); #Should we mail it to RTOwner? - if ($RT::LoopsToRTOwner) { - MailError( To => $RT::OwnerEmail, - Subject => "RT Bounce: $Subject", - Explanation => "RT thinks this message may be a bounce", - MIMEObj => $Message ); - - #Do we actually want to store it? - return ( 0, "Message Bounced", undef ) unless ($RT::StoreLoops); + if ( RT->Config->Get('LoopsToRTOwner') ) { + MailError( + To => $owner_mail, + Subject => "RT Bounce: ".$args{'Subject'}, + Explanation => "RT thinks this message may be a bounce", + MIMEObj => $args{Message} + ); } - } - # }}} + #Do we actually want to store it? + return ( 0, $ErrorsTo, "Message Bounced", $IsALoop ) + unless RT->Config->Get('StoreLoops'); + } - # {{{ Squelch replies if necessary + # Squelch replies if necessary # Don't let the user stuff the RT-Squelch-Replies-To header. if ( $head->get('RT-Squelch-Replies-To') ) { - $head->add( 'RT-Relocated-Squelch-Replies-To', - $head->get('RT-Squelch-Replies-To') ); + $head->add( + 'RT-Relocated-Squelch-Replies-To', + $head->get('RT-Squelch-Replies-To') + ); $head->delete('RT-Squelch-Replies-To'); } if ($SquelchReplies) { - ## TODO: This is a hack. It should be some other way to - ## indicate that the transaction should be "silent". + # Squelch replies to the sender, and also leave a clue to + # allow us to squelch ALL outbound messages. This way we + # can punt the logic of "what to do when we get a bounce" + # to the scrip. We might want to notify nobody. Or just + # the RT Owner. Or maybe all Privileged watchers. my ( $Sender, $junk ) = ParseSenderAddressFromHead($head); - $head->add( 'RT-Squelch-Replies-To', $Sender ); + $head->add( 'RT-Squelch-Replies-To', $Sender ); + $head->add( 'RT-DetectedAutoGenerated', 'true' ); } + return ( 1, $ErrorsTo, "Handled machine detection", $IsALoop ); +} - # }}} - - my $Ticket = RT::Ticket->new($CurrentUser); - - # {{{ If we don't have a ticket Id, we're creating a new ticket - if ( !$args{'ticket'} ) { - - # {{{ Create a new ticket +=head2 IsCorrectAction - my @Cc; - my @Requestors = ( $CurrentUser->id ); +Returns a list of valid actions we've found for this message - if ($RT::ParseNewMessageForTicketCcs) { - @Cc = ParseCcAddressesFromHead( Head => $head, - CurrentUser => $CurrentUser, - QueueObj => $SystemQueueObj ); - } - - my ( $id, $Transaction, $ErrStr ) = $Ticket->Create( - Queue => $SystemQueueObj->Id, - Subject => $Subject, - Requestor => \@Requestors, - Cc => \@Cc, - MIMEObj => $Message ); - if ( $id == 0 ) { - MailError( To => $ErrorsTo, - Subject => "Ticket creation failed", - Explanation => $ErrStr, - MIMEObj => $Message ); - $RT::Logger->error("Create failed: $id / $Transaction / $ErrStr "); - return ( 0, "Ticket creation failed", $Ticket ); - } +=cut - # }}} +sub IsCorrectAction { + my $action = shift; + my @actions = grep $_, split /-/, $action; + return ( 0, '(no value)' ) unless @actions; + foreach ( @actions ) { + return ( 0, $_ ) unless /^(?:comment|correspond|take|resolve)$/; } + return ( 1, @actions ); +} - # }}} - - # If the action is comment, add a comment. - elsif ( $args{'action'} =~ /^(comment|correspond)$/i ) { - $Ticket->Load($args{'ticket'}); - unless ( $Ticket->Id ) { - my $message = "Could not find a ticket with id ".$args{'ticket'}; - MailError( To => $ErrorsTo, - Subject => "Message not recorded", - Explanation => $message, - MIMEObj => $Message ); - - return ( 0, $message); - } - - my ( $status, $msg ); - if ( $args{'action'} =~ /^correspond$/ ) { - ( $status, $msg ) = $Ticket->Correspond( MIMEObj => $Message ); - } - else { - ( $status, $msg ) = $Ticket->Comment( MIMEObj => $Message ); - } - unless ($status) { - - #Warn the sender that we couldn't actually submit the comment. - MailError( To => $ErrorsTo, - Subject => "Message not recorded", - Explanation => $msg, - MIMEObj => $Message ); - return ( 0, "Message not recorded", $Ticket ); - } +sub _RecordSendEmailFailure { + my $ticket = shift; + if ($ticket) { + $ticket->_RecordNote( + NoteType => 'SystemError', + Content => "Sending the previous mail has failed. Please contact your admin, they can find more details in the logs.", + ); + return 1; } - else { - - #Return mail to the sender with an error - MailError( To => $ErrorsTo, - Subject => "RT Configuration error", - Explanation => "'" - . $args{'action'} - . "' not a recognized action." - . " Your RT administrator has misconfigured " - . "the mail aliases which invoke RT", - MIMEObj => $Message ); - $RT::Logger->crit( $args{'action'} . " type unknown for $MessageId" ); - return ( 0, "Configuration error: " . $args{'action'} . " not a recognized action", $Ticket ); - + $RT::Logger->error( "Can't record send email failure as ticket is missing" ); + return; } - - -return ( 1, "Success", $Ticket ); } -eval "require RT::Interface::Email_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Email_Vendor.pm}); -eval "require RT::Interface::Email_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Email_Local.pm}); +RT::Base->_ImportOverlays(); 1; diff --git a/rt/lib/RT/Link.pm b/rt/lib/RT/Link.pm index 962c378a8..1aff5ef64 100644 --- a/rt/lib/RT/Link.pm +++ b/rt/lib/RT/Link.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -98,7 +123,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -107,14 +132,14 @@ Returns the current value of id. =cut -=item Base +=head2 Base Returns the current value of Base. (In the database, Base is stored as varchar(240).) -=item SetBase VALUE +=head2 SetBase VALUE Set Base to VALUE. @@ -125,14 +150,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Target +=head2 Target Returns the current value of Target. (In the database, Target is stored as varchar(240).) -=item SetTarget VALUE +=head2 SetTarget VALUE Set Target to VALUE. @@ -143,14 +168,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Type +=head2 Type Returns the current value of Type. (In the database, Type is stored as varchar(20).) -=item SetType VALUE +=head2 SetType VALUE Set Type to VALUE. @@ -161,14 +186,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item LocalTarget +=head2 LocalTarget Returns the current value of LocalTarget. (In the database, LocalTarget is stored as int(11).) -=item SetLocalTarget VALUE +=head2 SetLocalTarget VALUE Set LocalTarget to VALUE. @@ -179,14 +204,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item LocalBase +=head2 LocalBase Returns the current value of LocalBase. (In the database, LocalBase is stored as int(11).) -=item SetLocalBase VALUE +=head2 SetLocalBase VALUE Set LocalBase to VALUE. @@ -197,7 +222,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -206,7 +231,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -215,7 +240,7 @@ Returns the current value of LastUpdated. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -224,7 +249,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -234,51 +259,34 @@ Returns the current value of Created. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Base => - {read => 1, write => 1, type => 'varchar(240)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 240, is_blob => 0, is_numeric => 0, type => 'varchar(240)', default => ''}, Target => - {read => 1, write => 1, type => 'varchar(240)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 240, is_blob => 0, is_numeric => 0, type => 'varchar(240)', default => ''}, Type => - {read => 1, write => 1, type => 'varchar(20)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 20, is_blob => 0, is_numeric => 0, type => 'varchar(20)', default => ''}, LocalTarget => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LocalBase => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::Link_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Link_Overlay.pm}) { - die $@; - }; - - eval "require RT::Link_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Link_Vendor.pm}) { - die $@; - }; - - eval "require RT::Link_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Link_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -288,7 +296,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Links.pm b/rt/lib/RT/Links.pm index 7a1773af9..d8b602587 100644 --- a/rt/lib/RT/Links.pm +++ b/rt/lib/RT/Links.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Link item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Link->new($self->CurrentUser)); } - - eval "require RT::Links_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Links_Overlay.pm}) { - die $@; - }; - - eval "require RT::Links_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Links_Vendor.pm}) { - die $@; - }; - - eval "require RT::Links_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Links_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Queue.pm b/rt/lib/RT/Queue.pm index b362c9f0d..c0a0229cd 100755 --- a/rt/lib/RT/Queue.pm +++ b/rt/lib/RT/Queue.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -107,7 +132,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -116,14 +141,14 @@ Returns the current value of id. =cut -=item Name +=head2 Name Returns the current value of Name. (In the database, Name is stored as varchar(200).) -=item SetName VALUE +=head2 SetName VALUE Set Name to VALUE. @@ -134,14 +159,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Description +=head2 Description Returns the current value of Description. (In the database, Description is stored as varchar(255).) -=item SetDescription VALUE +=head2 SetDescription VALUE Set Description to VALUE. @@ -152,14 +177,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item CorrespondAddress +=head2 CorrespondAddress Returns the current value of CorrespondAddress. (In the database, CorrespondAddress is stored as varchar(120).) -=item SetCorrespondAddress VALUE +=head2 SetCorrespondAddress VALUE Set CorrespondAddress to VALUE. @@ -170,14 +195,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item CommentAddress +=head2 CommentAddress Returns the current value of CommentAddress. (In the database, CommentAddress is stored as varchar(120).) -=item SetCommentAddress VALUE +=head2 SetCommentAddress VALUE Set CommentAddress to VALUE. @@ -188,14 +213,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item InitialPriority +=head2 InitialPriority Returns the current value of InitialPriority. (In the database, InitialPriority is stored as int(11).) -=item SetInitialPriority VALUE +=head2 SetInitialPriority VALUE Set InitialPriority to VALUE. @@ -206,14 +231,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item FinalPriority +=head2 FinalPriority Returns the current value of FinalPriority. (In the database, FinalPriority is stored as int(11).) -=item SetFinalPriority VALUE +=head2 SetFinalPriority VALUE Set FinalPriority to VALUE. @@ -224,14 +249,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item DefaultDueIn +=head2 DefaultDueIn Returns the current value of DefaultDueIn. (In the database, DefaultDueIn is stored as int(11).) -=item SetDefaultDueIn VALUE +=head2 SetDefaultDueIn VALUE Set DefaultDueIn to VALUE. @@ -242,7 +267,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -251,7 +276,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -260,7 +285,7 @@ Returns the current value of Created. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -269,7 +294,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -278,14 +303,14 @@ Returns the current value of LastUpdated. =cut -=item Disabled +=head2 Disabled Returns the current value of Disabled. (In the database, Disabled is stored as smallint(6).) -=item SetDisabled VALUE +=head2 SetDisabled VALUE Set Disabled to VALUE. @@ -297,57 +322,40 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Name => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Description => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, CorrespondAddress => - {read => 1, write => 1, type => 'varchar(120)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''}, CommentAddress => - {read => 1, write => 1, type => 'varchar(120)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''}, InitialPriority => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, FinalPriority => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, DefaultDueIn => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Disabled => - {read => 1, write => 1, type => 'smallint(6)', default => '0'}, + {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'}, } }; - - eval "require RT::Queue_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Queue_Overlay.pm}) { - die $@; - }; - - eval "require RT::Queue_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Queue_Vendor.pm}) { - die $@; - }; - - eval "require RT::Queue_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Queue_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -357,7 +365,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Queues.pm b/rt/lib/RT/Queues.pm index 60aec9086..e634a967c 100755 --- a/rt/lib/RT/Queues.pm +++ b/rt/lib/RT/Queues.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Queue item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Queue->new($self->CurrentUser)); } - - eval "require RT::Queues_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Queues_Overlay.pm}) { - die $@; - }; - - eval "require RT::Queues_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Queues_Vendor.pm}) { - die $@; - }; - - eval "require RT::Queues_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Queues_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Scrip.pm b/rt/lib/RT/Scrip.pm index a69dde04e..b430a77e9 100755 --- a/rt/lib/RT/Scrip.pm +++ b/rt/lib/RT/Scrip.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -65,7 +90,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -120,7 +145,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -129,14 +154,14 @@ Returns the current value of id. =cut -=item Description +=head2 Description Returns the current value of Description. (In the database, Description is stored as varchar(255).) -=item SetDescription VALUE +=head2 SetDescription VALUE Set Description to VALUE. @@ -147,14 +172,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ScripCondition +=head2 ScripCondition Returns the current value of ScripCondition. (In the database, ScripCondition is stored as int(11).) -=item SetScripCondition VALUE +=head2 SetScripCondition VALUE Set ScripCondition to VALUE. @@ -165,7 +190,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ScripConditionObj +=head2 ScripConditionObj Returns the ScripCondition Object which has the id returned by ScripCondition @@ -179,14 +204,14 @@ sub ScripConditionObj { return($ScripCondition); } -=item ScripAction +=head2 ScripAction Returns the current value of ScripAction. (In the database, ScripAction is stored as int(11).) -=item SetScripAction VALUE +=head2 SetScripAction VALUE Set ScripAction to VALUE. @@ -197,7 +222,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ScripActionObj +=head2 ScripActionObj Returns the ScripAction Object which has the id returned by ScripAction @@ -211,14 +236,14 @@ sub ScripActionObj { return($ScripAction); } -=item ConditionRules +=head2 ConditionRules Returns the current value of ConditionRules. (In the database, ConditionRules is stored as text.) -=item SetConditionRules VALUE +=head2 SetConditionRules VALUE Set ConditionRules to VALUE. @@ -229,14 +254,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ActionRules +=head2 ActionRules Returns the current value of ActionRules. (In the database, ActionRules is stored as text.) -=item SetActionRules VALUE +=head2 SetActionRules VALUE Set ActionRules to VALUE. @@ -247,14 +272,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item CustomIsApplicableCode +=head2 CustomIsApplicableCode Returns the current value of CustomIsApplicableCode. (In the database, CustomIsApplicableCode is stored as text.) -=item SetCustomIsApplicableCode VALUE +=head2 SetCustomIsApplicableCode VALUE Set CustomIsApplicableCode to VALUE. @@ -265,14 +290,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item CustomPrepareCode +=head2 CustomPrepareCode Returns the current value of CustomPrepareCode. (In the database, CustomPrepareCode is stored as text.) -=item SetCustomPrepareCode VALUE +=head2 SetCustomPrepareCode VALUE Set CustomPrepareCode to VALUE. @@ -283,14 +308,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item CustomCommitCode +=head2 CustomCommitCode Returns the current value of CustomCommitCode. (In the database, CustomCommitCode is stored as text.) -=item SetCustomCommitCode VALUE +=head2 SetCustomCommitCode VALUE Set CustomCommitCode to VALUE. @@ -301,14 +326,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Stage +=head2 Stage Returns the current value of Stage. (In the database, Stage is stored as varchar(32).) -=item SetStage VALUE +=head2 SetStage VALUE Set Stage to VALUE. @@ -319,14 +344,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Queue +=head2 Queue Returns the current value of Queue. (In the database, Queue is stored as int(11).) -=item SetQueue VALUE +=head2 SetQueue VALUE Set Queue to VALUE. @@ -337,7 +362,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item QueueObj +=head2 QueueObj Returns the Queue Object which has the id returned by Queue @@ -351,14 +376,14 @@ sub QueueObj { return($Queue); } -=item Template +=head2 Template Returns the current value of Template. (In the database, Template is stored as int(11).) -=item SetTemplate VALUE +=head2 SetTemplate VALUE Set Template to VALUE. @@ -369,7 +394,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item TemplateObj +=head2 TemplateObj Returns the Template Object which has the id returned by Template @@ -383,7 +408,7 @@ sub TemplateObj { return($Template); } -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -392,7 +417,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -401,7 +426,7 @@ Returns the current value of Created. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -410,7 +435,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -420,63 +445,46 @@ Returns the current value of LastUpdated. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Description => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, ScripCondition => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, ScripAction => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, ConditionRules => - {read => 1, write => 1, type => 'text', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''}, ActionRules => - {read => 1, write => 1, type => 'text', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''}, CustomIsApplicableCode => - {read => 1, write => 1, type => 'text', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''}, CustomPrepareCode => - {read => 1, write => 1, type => 'text', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''}, CustomCommitCode => - {read => 1, write => 1, type => 'text', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''}, Stage => - {read => 1, write => 1, type => 'varchar(32)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => ''}, Queue => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Template => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::Scrip_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Scrip_Overlay.pm}) { - die $@; - }; - - eval "require RT::Scrip_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Scrip_Vendor.pm}) { - die $@; - }; - - eval "require RT::Scrip_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Scrip_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -486,7 +494,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/ScripAction.pm b/rt/lib/RT/ScripAction.pm index 26824df5d..21a8a0ea1 100755 --- a/rt/lib/RT/ScripAction.pm +++ b/rt/lib/RT/ScripAction.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -95,7 +120,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -104,14 +129,14 @@ Returns the current value of id. =cut -=item Name +=head2 Name Returns the current value of Name. (In the database, Name is stored as varchar(200).) -=item SetName VALUE +=head2 SetName VALUE Set Name to VALUE. @@ -122,14 +147,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Description +=head2 Description Returns the current value of Description. (In the database, Description is stored as varchar(255).) -=item SetDescription VALUE +=head2 SetDescription VALUE Set Description to VALUE. @@ -140,14 +165,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ExecModule +=head2 ExecModule Returns the current value of ExecModule. (In the database, ExecModule is stored as varchar(60).) -=item SetExecModule VALUE +=head2 SetExecModule VALUE Set ExecModule to VALUE. @@ -158,14 +183,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Argument +=head2 Argument Returns the current value of Argument. (In the database, Argument is stored as varchar(255).) -=item SetArgument VALUE +=head2 SetArgument VALUE Set Argument to VALUE. @@ -176,7 +201,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -185,7 +210,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -194,7 +219,7 @@ Returns the current value of Created. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -203,7 +228,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -213,49 +238,32 @@ Returns the current value of LastUpdated. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Name => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Description => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, ExecModule => - {read => 1, write => 1, type => 'varchar(60)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 60, is_blob => 0, is_numeric => 0, type => 'varchar(60)', default => ''}, Argument => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::ScripAction_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripAction_Overlay.pm}) { - die $@; - }; - - eval "require RT::ScripAction_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripAction_Vendor.pm}) { - die $@; - }; - - eval "require RT::ScripAction_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripAction_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -265,7 +273,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/ScripActions.pm b/rt/lib/RT/ScripActions.pm index 614ff374f..d2f987c1b 100755 --- a/rt/lib/RT/ScripActions.pm +++ b/rt/lib/RT/ScripActions.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::ScripAction item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::ScripAction->new($self->CurrentUser)); } - - eval "require RT::ScripActions_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripActions_Overlay.pm}) { - die $@; - }; - - eval "require RT::ScripActions_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripActions_Vendor.pm}) { - die $@; - }; - - eval "require RT::ScripActions_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripActions_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/ScripCondition.pm b/rt/lib/RT/ScripCondition.pm index fe0aa2d5a..48ea27a00 100755 --- a/rt/lib/RT/ScripCondition.pm +++ b/rt/lib/RT/ScripCondition.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -98,7 +123,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -107,14 +132,14 @@ Returns the current value of id. =cut -=item Name +=head2 Name Returns the current value of Name. (In the database, Name is stored as varchar(200).) -=item SetName VALUE +=head2 SetName VALUE Set Name to VALUE. @@ -125,14 +150,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Description +=head2 Description Returns the current value of Description. (In the database, Description is stored as varchar(255).) -=item SetDescription VALUE +=head2 SetDescription VALUE Set Description to VALUE. @@ -143,14 +168,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ExecModule +=head2 ExecModule Returns the current value of ExecModule. (In the database, ExecModule is stored as varchar(60).) -=item SetExecModule VALUE +=head2 SetExecModule VALUE Set ExecModule to VALUE. @@ -161,14 +186,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Argument +=head2 Argument Returns the current value of Argument. (In the database, Argument is stored as varchar(255).) -=item SetArgument VALUE +=head2 SetArgument VALUE Set Argument to VALUE. @@ -179,14 +204,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ApplicableTransTypes +=head2 ApplicableTransTypes Returns the current value of ApplicableTransTypes. (In the database, ApplicableTransTypes is stored as varchar(60).) -=item SetApplicableTransTypes VALUE +=head2 SetApplicableTransTypes VALUE Set ApplicableTransTypes to VALUE. @@ -197,7 +222,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -206,7 +231,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -215,7 +240,7 @@ Returns the current value of Created. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -224,7 +249,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -234,51 +259,34 @@ Returns the current value of LastUpdated. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Name => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Description => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, ExecModule => - {read => 1, write => 1, type => 'varchar(60)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 60, is_blob => 0, is_numeric => 0, type => 'varchar(60)', default => ''}, Argument => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, ApplicableTransTypes => - {read => 1, write => 1, type => 'varchar(60)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 60, is_blob => 0, is_numeric => 0, type => 'varchar(60)', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::ScripCondition_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripCondition_Overlay.pm}) { - die $@; - }; - - eval "require RT::ScripCondition_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripCondition_Vendor.pm}) { - die $@; - }; - - eval "require RT::ScripCondition_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripCondition_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -288,7 +296,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/ScripConditions.pm b/rt/lib/RT/ScripConditions.pm index 34f788d9c..76777cbef 100755 --- a/rt/lib/RT/ScripConditions.pm +++ b/rt/lib/RT/ScripConditions.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::ScripCondition item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::ScripCondition->new($self->CurrentUser)); } - - eval "require RT::ScripConditions_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripConditions_Overlay.pm}) { - die $@; - }; - - eval "require RT::ScripConditions_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripConditions_Vendor.pm}) { - die $@; - }; - - eval "require RT::ScripConditions_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/ScripConditions_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Scrips.pm b/rt/lib/RT/Scrips.pm index a39443136..7e632171b 100755 --- a/rt/lib/RT/Scrips.pm +++ b/rt/lib/RT/Scrips.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Scrip item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Scrip->new($self->CurrentUser)); } - - eval "require RT::Scrips_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Scrips_Overlay.pm}) { - die $@; - }; - - eval "require RT::Scrips_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Scrips_Vendor.pm}) { - die $@; - }; - - eval "require RT::Scrips_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Scrips_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Template.pm b/rt/lib/RT/Template.pm index f73ea3ed6..b77820d1f 100755 --- a/rt/lib/RT/Template.pm +++ b/rt/lib/RT/Template.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -62,7 +87,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -105,7 +130,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -114,14 +139,14 @@ Returns the current value of id. =cut -=item Queue +=head2 Queue Returns the current value of Queue. (In the database, Queue is stored as int(11).) -=item SetQueue VALUE +=head2 SetQueue VALUE Set Queue to VALUE. @@ -132,7 +157,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item QueueObj +=head2 QueueObj Returns the Queue Object which has the id returned by Queue @@ -146,14 +171,14 @@ sub QueueObj { return($Queue); } -=item Name +=head2 Name Returns the current value of Name. (In the database, Name is stored as varchar(200).) -=item SetName VALUE +=head2 SetName VALUE Set Name to VALUE. @@ -164,14 +189,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Description +=head2 Description Returns the current value of Description. (In the database, Description is stored as varchar(255).) -=item SetDescription VALUE +=head2 SetDescription VALUE Set Description to VALUE. @@ -182,14 +207,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Type +=head2 Type Returns the current value of Type. (In the database, Type is stored as varchar(16).) -=item SetType VALUE +=head2 SetType VALUE Set Type to VALUE. @@ -200,14 +225,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Language +=head2 Language Returns the current value of Language. (In the database, Language is stored as varchar(16).) -=item SetLanguage VALUE +=head2 SetLanguage VALUE Set Language to VALUE. @@ -218,14 +243,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item TranslationOf +=head2 TranslationOf Returns the current value of TranslationOf. (In the database, TranslationOf is stored as int(11).) -=item SetTranslationOf VALUE +=head2 SetTranslationOf VALUE Set TranslationOf to VALUE. @@ -236,14 +261,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Content +=head2 Content Returns the current value of Content. (In the database, Content is stored as blob.) -=item SetContent VALUE +=head2 SetContent VALUE Set Content to VALUE. @@ -254,7 +279,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -263,7 +288,7 @@ Returns the current value of LastUpdated. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -272,7 +297,7 @@ Returns the current value of LastUpdatedBy. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -281,7 +306,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -291,55 +316,38 @@ Returns the current value of Created. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Queue => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Name => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Description => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, Type => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, Language => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, TranslationOf => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Content => - {read => 1, write => 1, type => 'blob', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'blob', default => ''}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::Template_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Template_Overlay.pm}) { - die $@; - }; - - eval "require RT::Template_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Template_Vendor.pm}) { - die $@; - }; - - eval "require RT::Template_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Template_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -349,7 +357,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Templates.pm b/rt/lib/RT/Templates.pm index 37db84086..97b37c5ed 100755 --- a/rt/lib/RT/Templates.pm +++ b/rt/lib/RT/Templates.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Template item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Template->new($self->CurrentUser)); } - - eval "require RT::Templates_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Templates_Overlay.pm}) { - die $@; - }; - - eval "require RT::Templates_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Templates_Vendor.pm}) { - die $@; - }; - - eval "require RT::Templates_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Templates_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Ticket.pm b/rt/lib/RT/Ticket.pm index 2f075a20c..edf38f0e6 100755 --- a/rt/lib/RT/Ticket.pm +++ b/rt/lib/RT/Ticket.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -62,7 +87,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -116,7 +141,7 @@ sub Create { Resolved => '', Disabled => '0', - @_); + @_); $self->SUPER::Create( EffectiveId => $args{'EffectiveId'}, Queue => $args{'Queue'}, @@ -144,7 +169,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -153,14 +178,14 @@ Returns the current value of id. =cut -=item EffectiveId +=head2 EffectiveId Returns the current value of EffectiveId. (In the database, EffectiveId is stored as int(11).) -=item SetEffectiveId VALUE +=head2 SetEffectiveId VALUE Set EffectiveId to VALUE. @@ -171,14 +196,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Queue +=head2 Queue Returns the current value of Queue. (In the database, Queue is stored as int(11).) -=item SetQueue VALUE +=head2 SetQueue VALUE Set Queue to VALUE. @@ -189,7 +214,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item QueueObj +=head2 QueueObj Returns the Queue Object which has the id returned by Queue @@ -197,20 +222,22 @@ Returns the Queue Object which has the id returned by Queue =cut sub QueueObj { - my $self = shift; - my $Queue = RT::Queue->new($self->CurrentUser); - $Queue->Load($self->__Value('Queue')); - return($Queue); + my $self = shift; + my $Queue = RT::Queue->new($self->CurrentUser); + $Queue->Load($self->__Value('Queue')); + return($Queue); } -=item Type + + +=head2 Type Returns the current value of Type. (In the database, Type is stored as varchar(16).) -=item SetType VALUE +=head2 SetType VALUE Set Type to VALUE. @@ -221,14 +248,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item IssueStatement +=head2 IssueStatement Returns the current value of IssueStatement. (In the database, IssueStatement is stored as int(11).) -=item SetIssueStatement VALUE +=head2 SetIssueStatement VALUE Set IssueStatement to VALUE. @@ -239,14 +266,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Resolution +=head2 Resolution Returns the current value of Resolution. (In the database, Resolution is stored as int(11).) -=item SetResolution VALUE +=head2 SetResolution VALUE Set Resolution to VALUE. @@ -257,14 +284,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Owner +=head2 Owner Returns the current value of Owner. (In the database, Owner is stored as int(11).) -=item SetOwner VALUE +=head2 SetOwner VALUE Set Owner to VALUE. @@ -275,14 +302,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Subject +=head2 Subject Returns the current value of Subject. (In the database, Subject is stored as varchar(200).) -=item SetSubject VALUE +=head2 SetSubject VALUE Set Subject to VALUE. @@ -293,14 +320,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item InitialPriority +=head2 InitialPriority Returns the current value of InitialPriority. (In the database, InitialPriority is stored as int(11).) -=item SetInitialPriority VALUE +=head2 SetInitialPriority VALUE Set InitialPriority to VALUE. @@ -311,14 +338,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item FinalPriority +=head2 FinalPriority Returns the current value of FinalPriority. (In the database, FinalPriority is stored as int(11).) -=item SetFinalPriority VALUE +=head2 SetFinalPriority VALUE Set FinalPriority to VALUE. @@ -329,14 +356,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Priority +=head2 Priority Returns the current value of Priority. (In the database, Priority is stored as int(11).) -=item SetPriority VALUE +=head2 SetPriority VALUE Set Priority to VALUE. @@ -347,14 +374,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item TimeEstimated +=head2 TimeEstimated Returns the current value of TimeEstimated. (In the database, TimeEstimated is stored as int(11).) -=item SetTimeEstimated VALUE +=head2 SetTimeEstimated VALUE Set TimeEstimated to VALUE. @@ -365,14 +392,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item TimeWorked +=head2 TimeWorked Returns the current value of TimeWorked. (In the database, TimeWorked is stored as int(11).) -=item SetTimeWorked VALUE +=head2 SetTimeWorked VALUE Set TimeWorked to VALUE. @@ -383,14 +410,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Status +=head2 Status Returns the current value of Status. (In the database, Status is stored as varchar(10).) -=item SetStatus VALUE +=head2 SetStatus VALUE Set Status to VALUE. @@ -401,14 +428,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item TimeLeft +=head2 TimeLeft Returns the current value of TimeLeft. (In the database, TimeLeft is stored as int(11).) -=item SetTimeLeft VALUE +=head2 SetTimeLeft VALUE Set TimeLeft to VALUE. @@ -419,14 +446,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Told +=head2 Told Returns the current value of Told. (In the database, Told is stored as datetime.) -=item SetTold VALUE +=head2 SetTold VALUE Set Told to VALUE. @@ -437,14 +464,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Starts +=head2 Starts Returns the current value of Starts. (In the database, Starts is stored as datetime.) -=item SetStarts VALUE +=head2 SetStarts VALUE Set Starts to VALUE. @@ -455,14 +482,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Started +=head2 Started Returns the current value of Started. (In the database, Started is stored as datetime.) -=item SetStarted VALUE +=head2 SetStarted VALUE Set Started to VALUE. @@ -473,14 +500,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Due +=head2 Due Returns the current value of Due. (In the database, Due is stored as datetime.) -=item SetDue VALUE +=head2 SetDue VALUE Set Due to VALUE. @@ -491,14 +518,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Resolved +=head2 Resolved Returns the current value of Resolved. (In the database, Resolved is stored as datetime.) -=item SetResolved VALUE +=head2 SetResolved VALUE Set Resolved to VALUE. @@ -509,7 +536,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -518,7 +545,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -527,7 +554,7 @@ Returns the current value of LastUpdated. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -536,7 +563,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -545,14 +572,14 @@ Returns the current value of Created. =cut -=item Disabled +=head2 Disabled Returns the current value of Disabled. (In the database, Disabled is stored as smallint(6).) -=item SetDisabled VALUE +=head2 SetDisabled VALUE Set Disabled to VALUE. @@ -564,81 +591,64 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, EffectiveId => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Queue => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Type => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, IssueStatement => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Resolution => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Owner => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Subject => - {read => 1, write => 1, type => 'varchar(200)', default => '[no subject]'}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => '[no subject]'}, InitialPriority => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, FinalPriority => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Priority => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, TimeEstimated => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, TimeWorked => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Status => - {read => 1, write => 1, type => 'varchar(10)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 10, is_blob => 0, is_numeric => 0, type => 'varchar(10)', default => ''}, TimeLeft => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Told => - {read => 1, write => 1, type => 'datetime', default => ''}, + {read => 1, write => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Starts => - {read => 1, write => 1, type => 'datetime', default => ''}, + {read => 1, write => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Started => - {read => 1, write => 1, type => 'datetime', default => ''}, + {read => 1, write => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Due => - {read => 1, write => 1, type => 'datetime', default => ''}, + {read => 1, write => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Resolved => - {read => 1, write => 1, type => 'datetime', default => ''}, + {read => 1, write => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, Disabled => - {read => 1, write => 1, type => 'smallint(6)', default => '0'}, + {read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'}, } }; - - eval "require RT::Ticket_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Ticket_Overlay.pm}) { - die $@; - }; - - eval "require RT::Ticket_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Ticket_Vendor.pm}) { - die $@; - }; - - eval "require RT::Ticket_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Ticket_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -648,7 +658,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Tickets.pm b/rt/lib/RT/Tickets.pm index b6b349144..b3a84ae8d 100755 --- a/rt/lib/RT/Tickets.pm +++ b/rt/lib/RT/Tickets.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Ticket item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Ticket->new($self->CurrentUser)); } - - eval "require RT::Tickets_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Tickets_Overlay.pm}) { - die $@; - }; - - eval "require RT::Tickets_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Tickets_Vendor.pm}) { - die $@; - }; - - eval "require RT::Tickets_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Tickets_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Transaction.pm b/rt/lib/RT/Transaction.pm index ca491a6c7..bc2b5cdbe 100755 --- a/rt/lib/RT/Transaction.pm +++ b/rt/lib/RT/Transaction.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -45,7 +70,6 @@ RT::Transaction package RT::Transaction; use RT::Record; -use RT::Ticket; use vars qw( @ISA ); @@ -62,18 +86,21 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: - int(11) 'EffectiveTicket'. - int(11) 'Ticket'. + varchar(64) 'ObjectType'. + int(11) 'ObjectId'. int(11) 'TimeTaken'. varchar(20) 'Type'. varchar(40) 'Field'. varchar(255) 'OldValue'. varchar(255) 'NewValue'. - varchar(100) 'Data'. + varchar(255) 'ReferenceType'. + int(11) 'OldReference'. + int(11) 'NewReference'. + varchar(255) 'Data'. =cut @@ -83,24 +110,30 @@ Create takes a hash of values and creates a row in the database: sub Create { my $self = shift; my %args = ( - EffectiveTicket => '0', - Ticket => '0', + ObjectType => '', + ObjectId => '0', TimeTaken => '0', Type => '', Field => '', OldValue => '', NewValue => '', + ReferenceType => '', + OldReference => '', + NewReference => '', Data => '', @_); $self->SUPER::Create( - EffectiveTicket => $args{'EffectiveTicket'}, - Ticket => $args{'Ticket'}, + ObjectType => $args{'ObjectType'}, + ObjectId => $args{'ObjectId'}, TimeTaken => $args{'TimeTaken'}, Type => $args{'Type'}, Field => $args{'Field'}, OldValue => $args{'OldValue'}, NewValue => $args{'NewValue'}, + ReferenceType => $args{'ReferenceType'}, + OldReference => $args{'OldReference'}, + NewReference => $args{'NewReference'}, Data => $args{'Data'}, ); @@ -108,7 +141,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -117,64 +150,50 @@ Returns the current value of id. =cut -=item EffectiveTicket +=head2 ObjectType -Returns the current value of EffectiveTicket. -(In the database, EffectiveTicket is stored as int(11).) +Returns the current value of ObjectType. +(In the database, ObjectType is stored as varchar(64).) -=item SetEffectiveTicket VALUE +=head2 SetObjectType VALUE -Set EffectiveTicket to VALUE. +Set ObjectType to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -(In the database, EffectiveTicket will be stored as a int(11).) +(In the database, ObjectType will be stored as a varchar(64).) =cut -=item Ticket +=head2 ObjectId -Returns the current value of Ticket. -(In the database, Ticket is stored as int(11).) +Returns the current value of ObjectId. +(In the database, ObjectId is stored as int(11).) -=item SetTicket VALUE +=head2 SetObjectId VALUE -Set Ticket to VALUE. +Set ObjectId to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -(In the database, Ticket will be stored as a int(11).) +(In the database, ObjectId will be stored as a int(11).) =cut -=item TicketObj - -Returns the Ticket Object which has the id returned by Ticket - - -=cut - -sub TicketObj { - my $self = shift; - my $Ticket = RT::Ticket->new($self->CurrentUser); - $Ticket->Load($self->__Value('Ticket')); - return($Ticket); -} - -=item TimeTaken +=head2 TimeTaken Returns the current value of TimeTaken. (In the database, TimeTaken is stored as int(11).) -=item SetTimeTaken VALUE +=head2 SetTimeTaken VALUE Set TimeTaken to VALUE. @@ -185,14 +204,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Type +=head2 Type Returns the current value of Type. (In the database, Type is stored as varchar(20).) -=item SetType VALUE +=head2 SetType VALUE Set Type to VALUE. @@ -203,14 +222,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Field +=head2 Field Returns the current value of Field. (In the database, Field is stored as varchar(40).) -=item SetField VALUE +=head2 SetField VALUE Set Field to VALUE. @@ -221,14 +240,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item OldValue +=head2 OldValue Returns the current value of OldValue. (In the database, OldValue is stored as varchar(255).) -=item SetOldValue VALUE +=head2 SetOldValue VALUE Set OldValue to VALUE. @@ -239,14 +258,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item NewValue +=head2 NewValue Returns the current value of NewValue. (In the database, NewValue is stored as varchar(255).) -=item SetNewValue VALUE +=head2 SetNewValue VALUE Set NewValue to VALUE. @@ -257,25 +276,79 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Data +=head2 ReferenceType + +Returns the current value of ReferenceType. +(In the database, ReferenceType is stored as varchar(255).) + + + +=head2 SetReferenceType VALUE + + +Set ReferenceType to VALUE. +Returns (1, 'Status message') on success and (0, 'Error Message') on failure. +(In the database, ReferenceType will be stored as a varchar(255).) + + +=cut + + +=head2 OldReference + +Returns the current value of OldReference. +(In the database, OldReference is stored as int(11).) + + + +=head2 SetOldReference VALUE + + +Set OldReference to VALUE. +Returns (1, 'Status message') on success and (0, 'Error Message') on failure. +(In the database, OldReference will be stored as a int(11).) + + +=cut + + +=head2 NewReference + +Returns the current value of NewReference. +(In the database, NewReference is stored as int(11).) + + + +=head2 SetNewReference VALUE + + +Set NewReference to VALUE. +Returns (1, 'Status message') on success and (0, 'Error Message') on failure. +(In the database, NewReference will be stored as a int(11).) + + +=cut + + +=head2 Data Returns the current value of Data. -(In the database, Data is stored as varchar(100).) +(In the database, Data is stored as varchar(255).) -=item SetData VALUE +=head2 SetData VALUE Set Data to VALUE. Returns (1, 'Status message') on success and (0, 'Error Message') on failure. -(In the database, Data will be stored as a varchar(100).) +(In the database, Data will be stored as a varchar(255).) =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -284,7 +357,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -294,53 +367,42 @@ Returns the current value of Created. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, - EffectiveTicket => - {read => 1, write => 1, type => 'int(11)', default => '0'}, - Ticket => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + ObjectType => + {read => 1, write => 1, sql_type => 12, length => 64, is_blob => 0, is_numeric => 0, type => 'varchar(64)', default => ''}, + ObjectId => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, TimeTaken => - {read => 1, write => 1, type => 'int(11)', default => '0'}, + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Type => - {read => 1, write => 1, type => 'varchar(20)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 20, is_blob => 0, is_numeric => 0, type => 'varchar(20)', default => ''}, Field => - {read => 1, write => 1, type => 'varchar(40)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 40, is_blob => 0, is_numeric => 0, type => 'varchar(40)', default => ''}, OldValue => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, NewValue => - {read => 1, write => 1, type => 'varchar(255)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, + ReferenceType => + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, + OldReference => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, + NewReference => + {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Data => - {read => 1, write => 1, type => 'varchar(100)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::Transaction_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Transaction_Overlay.pm}) { - die $@; - }; - - eval "require RT::Transaction_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Transaction_Vendor.pm}) { - die $@; - }; - - eval "require RT::Transaction_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Transaction_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -350,7 +412,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Transactions.pm b/rt/lib/RT/Transactions.pm index 23a475ac6..0b977c623 100755 --- a/rt/lib/RT/Transactions.pm +++ b/rt/lib/RT/Transactions.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::Transaction item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::Transaction->new($self->CurrentUser)); } - - eval "require RT::Transactions_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Transactions_Overlay.pm}) { - die $@; - }; - - eval "require RT::Transactions_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Transactions_Vendor.pm}) { - die $@; - }; - - eval "require RT::Transactions_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Transactions_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/User.pm b/rt/lib/RT/User.pm index cbc10f5b4..b7ebd5bf2 100755 --- a/rt/lib/RT/User.pm +++ b/rt/lib/RT/User.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -61,7 +86,7 @@ sub _Init { -=item Create PARAMHASH +=head2 Create PARAMHASH Create takes a hash of values and creates a row in the database: @@ -170,7 +195,7 @@ sub Create { -=item id +=head2 id Returns the current value of id. (In the database, id is stored as int(11).) @@ -179,14 +204,14 @@ Returns the current value of id. =cut -=item Name +=head2 Name Returns the current value of Name. (In the database, Name is stored as varchar(200).) -=item SetName VALUE +=head2 SetName VALUE Set Name to VALUE. @@ -197,14 +222,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Password +=head2 Password Returns the current value of Password. (In the database, Password is stored as varchar(40).) -=item SetPassword VALUE +=head2 SetPassword VALUE Set Password to VALUE. @@ -215,14 +240,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Comments +=head2 Comments Returns the current value of Comments. (In the database, Comments is stored as blob.) -=item SetComments VALUE +=head2 SetComments VALUE Set Comments to VALUE. @@ -233,14 +258,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Signature +=head2 Signature Returns the current value of Signature. (In the database, Signature is stored as blob.) -=item SetSignature VALUE +=head2 SetSignature VALUE Set Signature to VALUE. @@ -251,14 +276,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item EmailAddress +=head2 EmailAddress Returns the current value of EmailAddress. (In the database, EmailAddress is stored as varchar(120).) -=item SetEmailAddress VALUE +=head2 SetEmailAddress VALUE Set EmailAddress to VALUE. @@ -269,14 +294,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item FreeformContactInfo +=head2 FreeformContactInfo Returns the current value of FreeformContactInfo. (In the database, FreeformContactInfo is stored as blob.) -=item SetFreeformContactInfo VALUE +=head2 SetFreeformContactInfo VALUE Set FreeformContactInfo to VALUE. @@ -287,14 +312,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Organization +=head2 Organization Returns the current value of Organization. (In the database, Organization is stored as varchar(200).) -=item SetOrganization VALUE +=head2 SetOrganization VALUE Set Organization to VALUE. @@ -305,14 +330,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item RealName +=head2 RealName Returns the current value of RealName. (In the database, RealName is stored as varchar(120).) -=item SetRealName VALUE +=head2 SetRealName VALUE Set RealName to VALUE. @@ -323,14 +348,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item NickName +=head2 NickName Returns the current value of NickName. (In the database, NickName is stored as varchar(16).) -=item SetNickName VALUE +=head2 SetNickName VALUE Set NickName to VALUE. @@ -341,14 +366,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Lang +=head2 Lang Returns the current value of Lang. (In the database, Lang is stored as varchar(16).) -=item SetLang VALUE +=head2 SetLang VALUE Set Lang to VALUE. @@ -359,14 +384,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item EmailEncoding +=head2 EmailEncoding Returns the current value of EmailEncoding. (In the database, EmailEncoding is stored as varchar(16).) -=item SetEmailEncoding VALUE +=head2 SetEmailEncoding VALUE Set EmailEncoding to VALUE. @@ -377,14 +402,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item WebEncoding +=head2 WebEncoding Returns the current value of WebEncoding. (In the database, WebEncoding is stored as varchar(16).) -=item SetWebEncoding VALUE +=head2 SetWebEncoding VALUE Set WebEncoding to VALUE. @@ -395,14 +420,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ExternalContactInfoId +=head2 ExternalContactInfoId Returns the current value of ExternalContactInfoId. (In the database, ExternalContactInfoId is stored as varchar(100).) -=item SetExternalContactInfoId VALUE +=head2 SetExternalContactInfoId VALUE Set ExternalContactInfoId to VALUE. @@ -413,14 +438,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ContactInfoSystem +=head2 ContactInfoSystem Returns the current value of ContactInfoSystem. (In the database, ContactInfoSystem is stored as varchar(30).) -=item SetContactInfoSystem VALUE +=head2 SetContactInfoSystem VALUE Set ContactInfoSystem to VALUE. @@ -431,14 +456,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item ExternalAuthId +=head2 ExternalAuthId Returns the current value of ExternalAuthId. (In the database, ExternalAuthId is stored as varchar(100).) -=item SetExternalAuthId VALUE +=head2 SetExternalAuthId VALUE Set ExternalAuthId to VALUE. @@ -449,14 +474,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item AuthSystem +=head2 AuthSystem Returns the current value of AuthSystem. (In the database, AuthSystem is stored as varchar(30).) -=item SetAuthSystem VALUE +=head2 SetAuthSystem VALUE Set AuthSystem to VALUE. @@ -467,14 +492,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Gecos +=head2 Gecos Returns the current value of Gecos. (In the database, Gecos is stored as varchar(16).) -=item SetGecos VALUE +=head2 SetGecos VALUE Set Gecos to VALUE. @@ -485,14 +510,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item HomePhone +=head2 HomePhone Returns the current value of HomePhone. (In the database, HomePhone is stored as varchar(30).) -=item SetHomePhone VALUE +=head2 SetHomePhone VALUE Set HomePhone to VALUE. @@ -503,14 +528,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item WorkPhone +=head2 WorkPhone Returns the current value of WorkPhone. (In the database, WorkPhone is stored as varchar(30).) -=item SetWorkPhone VALUE +=head2 SetWorkPhone VALUE Set WorkPhone to VALUE. @@ -521,14 +546,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item MobilePhone +=head2 MobilePhone Returns the current value of MobilePhone. (In the database, MobilePhone is stored as varchar(30).) -=item SetMobilePhone VALUE +=head2 SetMobilePhone VALUE Set MobilePhone to VALUE. @@ -539,14 +564,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item PagerPhone +=head2 PagerPhone Returns the current value of PagerPhone. (In the database, PagerPhone is stored as varchar(30).) -=item SetPagerPhone VALUE +=head2 SetPagerPhone VALUE Set PagerPhone to VALUE. @@ -557,14 +582,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Address1 +=head2 Address1 Returns the current value of Address1. (In the database, Address1 is stored as varchar(200).) -=item SetAddress1 VALUE +=head2 SetAddress1 VALUE Set Address1 to VALUE. @@ -575,14 +600,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Address2 +=head2 Address2 Returns the current value of Address2. (In the database, Address2 is stored as varchar(200).) -=item SetAddress2 VALUE +=head2 SetAddress2 VALUE Set Address2 to VALUE. @@ -593,14 +618,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item City +=head2 City Returns the current value of City. (In the database, City is stored as varchar(100).) -=item SetCity VALUE +=head2 SetCity VALUE Set City to VALUE. @@ -611,14 +636,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item State +=head2 State Returns the current value of State. (In the database, State is stored as varchar(100).) -=item SetState VALUE +=head2 SetState VALUE Set State to VALUE. @@ -629,14 +654,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Zip +=head2 Zip Returns the current value of Zip. (In the database, Zip is stored as varchar(16).) -=item SetZip VALUE +=head2 SetZip VALUE Set Zip to VALUE. @@ -647,14 +672,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Country +=head2 Country Returns the current value of Country. (In the database, Country is stored as varchar(50).) -=item SetCountry VALUE +=head2 SetCountry VALUE Set Country to VALUE. @@ -665,14 +690,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Timezone +=head2 Timezone Returns the current value of Timezone. (In the database, Timezone is stored as varchar(50).) -=item SetTimezone VALUE +=head2 SetTimezone VALUE Set Timezone to VALUE. @@ -683,14 +708,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item PGPKey +=head2 PGPKey Returns the current value of PGPKey. (In the database, PGPKey is stored as text.) -=item SetPGPKey VALUE +=head2 SetPGPKey VALUE Set PGPKey to VALUE. @@ -701,7 +726,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -=item Creator +=head2 Creator Returns the current value of Creator. (In the database, Creator is stored as int(11).) @@ -710,7 +735,7 @@ Returns the current value of Creator. =cut -=item Created +=head2 Created Returns the current value of Created. (In the database, Created is stored as datetime.) @@ -719,7 +744,7 @@ Returns the current value of Created. =cut -=item LastUpdatedBy +=head2 LastUpdatedBy Returns the current value of LastUpdatedBy. (In the database, LastUpdatedBy is stored as int(11).) @@ -728,7 +753,7 @@ Returns the current value of LastUpdatedBy. =cut -=item LastUpdated +=head2 LastUpdated Returns the current value of LastUpdated. (In the database, LastUpdated is stored as datetime.) @@ -738,99 +763,82 @@ Returns the current value of LastUpdated. -sub _ClassAccessible { +sub _CoreAccessible { { id => - {read => 1, type => 'int(11)', default => ''}, + {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, Name => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Password => - {read => 1, write => 1, type => 'varchar(40)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 40, is_blob => 0, is_numeric => 0, type => 'varchar(40)', default => ''}, Comments => - {read => 1, write => 1, type => 'blob', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'blob', default => ''}, Signature => - {read => 1, write => 1, type => 'blob', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'blob', default => ''}, EmailAddress => - {read => 1, write => 1, type => 'varchar(120)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''}, FreeformContactInfo => - {read => 1, write => 1, type => 'blob', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'blob', default => ''}, Organization => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, RealName => - {read => 1, write => 1, type => 'varchar(120)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''}, NickName => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, Lang => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, EmailEncoding => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, WebEncoding => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, ExternalContactInfoId => - {read => 1, write => 1, type => 'varchar(100)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 100, is_blob => 0, is_numeric => 0, type => 'varchar(100)', default => ''}, ContactInfoSystem => - {read => 1, write => 1, type => 'varchar(30)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 30, is_blob => 0, is_numeric => 0, type => 'varchar(30)', default => ''}, ExternalAuthId => - {read => 1, write => 1, type => 'varchar(100)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 100, is_blob => 0, is_numeric => 0, type => 'varchar(100)', default => ''}, AuthSystem => - {read => 1, write => 1, type => 'varchar(30)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 30, is_blob => 0, is_numeric => 0, type => 'varchar(30)', default => ''}, Gecos => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, HomePhone => - {read => 1, write => 1, type => 'varchar(30)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 30, is_blob => 0, is_numeric => 0, type => 'varchar(30)', default => ''}, WorkPhone => - {read => 1, write => 1, type => 'varchar(30)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 30, is_blob => 0, is_numeric => 0, type => 'varchar(30)', default => ''}, MobilePhone => - {read => 1, write => 1, type => 'varchar(30)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 30, is_blob => 0, is_numeric => 0, type => 'varchar(30)', default => ''}, PagerPhone => - {read => 1, write => 1, type => 'varchar(30)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 30, is_blob => 0, is_numeric => 0, type => 'varchar(30)', default => ''}, Address1 => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, Address2 => - {read => 1, write => 1, type => 'varchar(200)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''}, City => - {read => 1, write => 1, type => 'varchar(100)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 100, is_blob => 0, is_numeric => 0, type => 'varchar(100)', default => ''}, State => - {read => 1, write => 1, type => 'varchar(100)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 100, is_blob => 0, is_numeric => 0, type => 'varchar(100)', default => ''}, Zip => - {read => 1, write => 1, type => 'varchar(16)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''}, Country => - {read => 1, write => 1, type => 'varchar(50)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 50, is_blob => 0, is_numeric => 0, type => 'varchar(50)', default => ''}, Timezone => - {read => 1, write => 1, type => 'varchar(50)', default => ''}, + {read => 1, write => 1, sql_type => 12, length => 50, is_blob => 0, is_numeric => 0, type => 'varchar(50)', default => ''}, PGPKey => - {read => 1, write => 1, type => 'text', default => ''}, + {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''}, Creator => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, LastUpdatedBy => - {read => 1, auto => 1, type => 'int(11)', default => '0'}, + {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, LastUpdated => - {read => 1, auto => 1, type => 'datetime', default => ''}, + {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''}, } }; - - eval "require RT::User_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/User_Overlay.pm}) { - die $@; - }; - - eval "require RT::User_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/User_Vendor.pm}) { - die $@; - }; - - eval "require RT::User_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/User_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -840,7 +848,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); diff --git a/rt/lib/RT/Users.pm b/rt/lib/RT/Users.pm index d58f69653..f0f07fde7 100755 --- a/rt/lib/RT/Users.pm +++ b/rt/lib/RT/Users.pm @@ -1,26 +1,51 @@ -# BEGIN LICENSE BLOCK -# -# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com> -# -# (Except where explictly superceded by other copyright notices) -# +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC +# <sales@bestpractical.com> +# +# (Except where explicitly superseded by other copyright notices) +# +# +# LICENSE: +# # This work is made available to you under the terms of Version 2 of # the GNU General Public License. A copy of that license should have # been provided with this software, but in any event can be snarfed # from www.gnu.org. -# +# # This work is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -# -# Unless otherwise specified, all modifications, corrections or -# extensions to this work which alter its source code become the -# property of Best Practical Solutions, LLC when submitted for -# inclusion in the work. -# -# -# END LICENSE BLOCK +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 or visit their web page on the internet at +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +# +# +# CONTRIBUTION SUBMISSION POLICY: +# +# (The following paragraph is not intended to limit the rights granted +# to you to modify and distribute this software under the terms of +# the GNU General Public License and is only of importance to you if +# you choose to contribute your changes and enhancements to the +# community by submitting them to Best Practical Solutions, LLC.) +# +# By intentionally submitting any modifications, corrections or +# derivatives to this work, or any other work intended for use with +# Request Tracker, to Best Practical Solutions, LLC, you confirm that +# you are the copyright holder for those contributions and you grant +# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +# royalty-free, perpetual, license to use, copy, create derivative +# works based on those contributions, and sublicense and distribute +# those contributions and any derivatives thereof. +# +# END BPS TAGGED BLOCK }}} + # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>) # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST. # @@ -64,7 +89,7 @@ sub _Init { } -=item NewItem +=head2 NewItem Returns an empty new RT::User item @@ -74,24 +99,7 @@ sub NewItem { my $self = shift; return(RT::User->new($self->CurrentUser)); } - - eval "require RT::Users_Overlay"; - if ($@ && $@ !~ qr{^Can't locate RT/Users_Overlay.pm}) { - die $@; - }; - - eval "require RT::Users_Vendor"; - if ($@ && $@ !~ qr{^Can't locate RT/Users_Vendor.pm}) { - die $@; - }; - - eval "require RT::Users_Local"; - if ($@ && $@ !~ qr{^Can't locate RT/Users_Local.pm}) { - die $@; - }; - - - +RT::Base->_ImportOverlays(); =head1 SEE ALSO @@ -101,7 +109,7 @@ _Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customiz These overlay files can contain new subs or subs to replace existing subs in this module. -If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line +Each of these files should begin with the line no warnings qw(redefine); |