[Rt-commit] rt branch, customerA, created. 1e6852af90266819f284ee8ec997bb36c1d83296

sartak at bestpractical.com sartak at bestpractical.com
Wed Jul 29 17:16:26 EDT 2009


The branch, customerA has been created
        at  1e6852af90266819f284ee8ec997bb36c1d83296 (commit)

- Log -----------------------------------------------------------------
commit c22c08be36226d6fd4ce26ece1fd9ba290bb07d2
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Mon Jun 8 15:32:19 2009 +0000

    bump version for 3.8.4rc1 release
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/3.8.4-releng@19940 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/configure.ac b/configure.ac
index d6b3eda..ba65b17 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ AC_REVISION($Revision$)dnl
 
 dnl Setup autoconf
 AC_PREREQ([2.53])
-AC_INIT(RT, 3.8.HEAD, [rt-bugs at bestpractical.com])
+AC_INIT(RT, 3.8.4rc1, [rt-bugs at bestpractical.com])
 AC_CONFIG_SRCDIR([lib/RT.pm.in])
 
 dnl Extract RT version number components

commit 979b5423bda919dd00d1d5a0352ac44d90730d6a
Merge: c22c08b... c476345...
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Mon Jun 8 15:42:20 2009 +0000

    - Merge //mirror/bps-public/rt/3.8/trunk to //mirror/bps-public/rt/3.8/branches/3.8.4-releng
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/3.8.4-releng@19943 e417ac7c-1bcc-0310-8ffa-8f5827389a85


commit b8e41c6690c5e9e3aec85a3a9c0daccc841bd49f
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Wed Jun 10 16:03:25 2009 +0000

    fix copyright
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/3.8.4-releng@19961 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/share/html/Elements/Footer b/share/html/Elements/Footer
index d5e3177..bb6c337 100755
--- a/share/html/Elements/Footer
+++ b/share/html/Elements/Footer
@@ -56,7 +56,7 @@
 %}
   <p id="bpscredits">
     <span>
-<&|/l,     '&#187;&#124;&#171;', $RT::VERSION, '2008', '<a href="http://www.bestpractical.com?rt='.$RT::VERSION.'">Best Practical Solutions, LLC</a>', &>[_1] RT [_2] Copyright 1996-[_3] [_4].</&>
+<&|/l,     '&#187;&#124;&#171;', $RT::VERSION, '2009', '<a href="http://www.bestpractical.com?rt='.$RT::VERSION.'">Best Practical Solutions, LLC</a>', &>[_1] RT [_2] Copyright 1996-[_3] [_4].</&>
 </span>
 </p>
 % if (!$Menu) {

commit 006fdd2ff1dba8686d549e1b718e5ea5da4f9408
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Wed Jun 10 16:03:57 2009 +0000

    bump version to 3.8.4 to get ready for a release
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/3.8.4-releng@19962 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/configure.ac b/configure.ac
index ba65b17..31e2b13 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ AC_REVISION($Revision$)dnl
 
 dnl Setup autoconf
 AC_PREREQ([2.53])
-AC_INIT(RT, 3.8.4rc1, [rt-bugs at bestpractical.com])
+AC_INIT(RT, 3.8.4, [rt-bugs at bestpractical.com])
 AC_CONFIG_SRCDIR([lib/RT.pm.in])
 
 dnl Extract RT version number components

commit 232f31c1b11eae998a6f3bac19224d5cdf33ea9d
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Tue May 12 22:09:19 2009 +0000

    19552:  elacour | 2009-05-07 03:33:31 -0400
     When downloading message with headers, try to add charset information to
     content_type so the raw message is displayed correctly in browser.
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/forward-message-encoding@19643 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/share/html/Ticket/Attachment/WithHeaders/dhandler b/share/html/Ticket/Attachment/WithHeaders/dhandler
index 7cd5f50..89a64de 100644
--- a/share/html/Ticket/Attachment/WithHeaders/dhandler
+++ b/share/html/Ticket/Attachment/WithHeaders/dhandler
@@ -59,8 +59,16 @@
         Abort("Couldn't load attachment #$id");
     }
 
+    my $content_type = 'text/plain';
+    if ( my $enc = $AttachmentObj->OriginalEncoding ) {
+        # normalize Encode.pm convention with IANA ones
+        $enc = 'big5'  if $enc eq 'big5-eten';
+        $enc = 'utf-8' if $enc eq 'utf8';
+        $content_type .= ";charset=$enc";
+    }
+
     # XXX: should we check handle html here and integrate headers into html?
-    $r->content_type( 'text/plain' );
+    $r->content_type( $content_type );
     $m->clear_buffer;
     $m->out( $AttachmentObj->Headers );
     $m->out( "\n\n" );

commit 56b34876d008f5ce4143d334d258ee189038f9ba
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Tue May 12 22:09:36 2009 +0000

    r19576:  elacour | 2009-05-07 04:08:18 -0400
     Properly MIME encode (RFC 2047) headers of forwarded messages, so for example
     non ascii subject are properly displayed in MUA.
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/forward-message-encoding@19644 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index 37884f5..bd888ee 100755
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -622,7 +622,7 @@ sub ForwardTransaction {
         );
     }
 
-    $mail->head->set( $_ => $args{ $_ } )
+    $mail->head->set( $_ => Encode::encode('MIME-Header', $args{ $_ }) )
         foreach grep defined $args{$_}, qw(To Cc Bcc);
 
     $mail->attach(
@@ -643,8 +643,8 @@ sub ForwardTransaction {
         $from = $obj->QueueObj->CorrespondAddress
             || RT->Config->Get('CorrespondAddress');
     }
-    $mail->head->set( Subject => "Fwd: $subject" );
-    $mail->head->set( From    => $from );
+    $mail->head->set( Subject => Encode::encode('MIME-Header', "Fwd: $subject") );
+    $mail->head->set( From    => Encode::encode('MIME-Header', $from) );
 
     my $status = RT->Config->Get('ForwardFromUser')
         # never sign if we forward from User

commit f42c88c0812bd253838e2e91011fa6c9bfc35791
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Tue May 12 22:10:08 2009 +0000

    r19578:  elacour | 2009-05-07 06:13:05 -0400
     Fix encoding differences between attachment content and headers when
     downloading attachments with headers.
    
     - $AttachmentsObj->Headers is always UTF-8 as it's converted when saved to DB,
       and it has utf8 flag on
     - $AttachmentsObj->OriginalContent is in the original encoding and has utf8
       flag off
    
     so this patch adds an Attachment::OriginalHeaders method.
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/forward-message-encoding@19645 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/lib/RT/Attachment_Overlay.pm b/lib/RT/Attachment_Overlay.pm
index b7e52e7..033c088 100755
--- a/lib/RT/Attachment_Overlay.pm
+++ b/lib/RT/Attachment_Overlay.pm
@@ -320,6 +320,46 @@ sub OriginalContent {
     return $content;
 }
 
+=head2 OriginalHeaders
+
+Returns the attachment's headers as octets before RT's mangling.  Currently,
+this just means restoring text content back to its original encoding.
+
+=cut
+
+sub OriginalHeaders {
+    my $self = shift;
+
+    return $self->Headers unless RT::I18N::IsTextualContentType($self->ContentType);
+    my $enc = $self->OriginalEncoding;
+
+    my $headers;
+    if ( !$self->ContentEncoding || $self->ContentEncoding eq 'none' ) {
+        $headers = $self->_Value('Headers', decode_utf8 => 0);
+    } elsif ( $self->ContentEncoding eq 'base64' ) {
+        $headers = MIME::Base64::decode_base64($self->_Value('Headers', decode_utf8 => 0));
+    } elsif ( $self->ContentEncoding eq 'quoted-printable' ) {
+        $headers = MIME::QuotedPrint::decode($self->_Value('Headers', decode_utf8 => 0));
+    } else {
+        return( $self->loc("Unknown ContentEncoding [_1]", $self->ContentEncoding));
+    }
+
+    # Turn *off* the SvUTF8 bits here so decode_utf8 and from_to below can work.
+    local $@;
+    Encode::_utf8_off($headers);
+
+    if (!$enc || $enc eq '' ||  $enc eq 'utf8' || $enc eq 'utf-8') {
+        # If we somehow fail to do the decode, at least push out the raw bits
+        eval { return( Encode::decode_utf8($headers)) } || return ($headers);
+    }
+
+    eval { Encode::from_to($headers, 'utf8' => $enc) } if $enc;
+    if ($@) {
+        $RT::Logger->error("Could not convert attachment headers from assumed utf8 to '$enc' :".$@);
+    }
+    return $headers;
+}
+
 =head2 OriginalEncoding
 
 Returns the attachment's original encoding.
diff --git a/share/html/Ticket/Attachment/WithHeaders/dhandler b/share/html/Ticket/Attachment/WithHeaders/dhandler
index 89a64de..43f1de0 100644
--- a/share/html/Ticket/Attachment/WithHeaders/dhandler
+++ b/share/html/Ticket/Attachment/WithHeaders/dhandler
@@ -70,7 +70,7 @@
     # XXX: should we check handle html here and integrate headers into html?
     $r->content_type( $content_type );
     $m->clear_buffer;
-    $m->out( $AttachmentObj->Headers );
+    $m->out( $AttachmentObj->OriginalHeaders );
     $m->out( "\n\n" );
     $m->out( $AttachmentObj->OriginalContent );
     $m->abort;

commit ad243f4fda48c4ed8027cc7a45451df393be9abe
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Tue May 12 22:10:20 2009 +0000

    r19579:  elacour | 2009-05-07 06:20:22 -0400
     Typo.
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/forward-message-encoding@19646 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/lib/RT/Attachment_Overlay.pm b/lib/RT/Attachment_Overlay.pm
index 033c088..471f9f7 100755
--- a/lib/RT/Attachment_Overlay.pm
+++ b/lib/RT/Attachment_Overlay.pm
@@ -323,7 +323,7 @@ sub OriginalContent {
 =head2 OriginalHeaders
 
 Returns the attachment's headers as octets before RT's mangling.  Currently,
-this just means restoring text content back to its original encoding.
+this just means restoring text headers back to their original encoding.
 
 =cut
 

commit 8cf605e63a3714165bd2ea3b504ccd90e3561dfb
Author: Kevin Falcone <falcone at bestpractical.com>
Date:   Tue May 12 22:10:46 2009 +0000

    r19580:  elacour | 2009-05-07 06:49:19 -0400
     Fix display problem with non ascii headers in forwarded emails.
    
     We forward OriginalContent, which uses OriginalEncoding, but we forward Headers
     for this content as recorded by RT i.e. always using UTF-8. If content is text
     and uses different encoding than UTF-8, display in MUA is broken.
     So this patch encode headers as RFC 2047 to make sure MUA can read them.
    
    git-svn-id: svn+ssh://svn.bestpractical.com/svn/bps-public/rt/3.8/branches/forward-message-encoding@19647 e417ac7c-1bcc-0310-8ffa-8f5827389a85

diff --git a/lib/RT/Attachment_Overlay.pm b/lib/RT/Attachment_Overlay.pm
old mode 100755
new mode 100644
index 471f9f7..e1eba64
--- a/lib/RT/Attachment_Overlay.pm
+++ b/lib/RT/Attachment_Overlay.pm
@@ -457,8 +457,12 @@ sub ContentAsMIME {
     my $self = shift;
 
     my $entity = new MIME::Entity;
-    $entity->head->add( split /:/, $_, 2 )
-        foreach $self->SplitHeaders;
+    foreach my $header ($self->SplitHeaders) {
+        my ($h_key, $h_val) = split /:/, $header, 2;
+	# We need to encode header as RFC 2047, to avoid conflict with
+	# OrignalContent Encoding that may break display
+        $entity->head->add( $h_key, Encode::encode('MIME-Header', $h_val ) );
+    }
 
     use MIME::Body;
     $entity->bodyhandle(

commit b12d9be516c102557f82cceb3317a5902d0895b6
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Thu Jul 23 05:54:23 2009 +0400

    replace OriginalHeaders with EncodedHeaders
    
    There is no such thing as OriginalHeaders, if a field in the head
    contains not-ASCII characters then you have to use Q or B encodings.
    These encodings define character set of the content and can have
    multiple chunks with mixed character sets. We don't store all these
    variations in charsets across fields, so we can not restore original
    headers.
    
    As far as I know OriginalEncoding can not be base64 or quoted printable,
    so some parts of the code has never worked.
    
    For purpose of "Download with headers" feature it's better to have
    EncodedHeaders method that just encodes headers into a character set.

diff --git a/lib/RT/Attachment_Overlay.pm b/lib/RT/Attachment_Overlay.pm
index e1eba64..3892595 100644
--- a/lib/RT/Attachment_Overlay.pm
+++ b/lib/RT/Attachment_Overlay.pm
@@ -320,46 +320,6 @@ sub OriginalContent {
     return $content;
 }
 
-=head2 OriginalHeaders
-
-Returns the attachment's headers as octets before RT's mangling.  Currently,
-this just means restoring text headers back to their original encoding.
-
-=cut
-
-sub OriginalHeaders {
-    my $self = shift;
-
-    return $self->Headers unless RT::I18N::IsTextualContentType($self->ContentType);
-    my $enc = $self->OriginalEncoding;
-
-    my $headers;
-    if ( !$self->ContentEncoding || $self->ContentEncoding eq 'none' ) {
-        $headers = $self->_Value('Headers', decode_utf8 => 0);
-    } elsif ( $self->ContentEncoding eq 'base64' ) {
-        $headers = MIME::Base64::decode_base64($self->_Value('Headers', decode_utf8 => 0));
-    } elsif ( $self->ContentEncoding eq 'quoted-printable' ) {
-        $headers = MIME::QuotedPrint::decode($self->_Value('Headers', decode_utf8 => 0));
-    } else {
-        return( $self->loc("Unknown ContentEncoding [_1]", $self->ContentEncoding));
-    }
-
-    # Turn *off* the SvUTF8 bits here so decode_utf8 and from_to below can work.
-    local $@;
-    Encode::_utf8_off($headers);
-
-    if (!$enc || $enc eq '' ||  $enc eq 'utf8' || $enc eq 'utf-8') {
-        # If we somehow fail to do the decode, at least push out the raw bits
-        eval { return( Encode::decode_utf8($headers)) } || return ($headers);
-    }
-
-    eval { Encode::from_to($headers, 'utf8' => $enc) } if $enc;
-    if ($@) {
-        $RT::Logger->error("Could not convert attachment headers from assumed utf8 to '$enc' :".$@);
-    }
-    return $headers;
-}
-
 =head2 OriginalEncoding
 
 Returns the attachment's original encoding.
@@ -539,6 +499,21 @@ sub Headers {
     return join("\n", $_[0]->SplitHeaders);
 }
 
+=head2 EncodedHeaders
+
+Takes encoding as argument and returns the attachment's headers as octets in encoded
+using the encoding.
+
+This is not protection using quoted printable or base64 encoding.
+
+=cut
+
+sub EncodedHeaders {
+    my $self = shift;
+    my $encoding = shift || 'utf8';
+    return Encode::encode( $encoding, $self->Headers );
+}
+
 =head2 GetHeader $TAG
 
 Returns the value of the header Tag as a string. This bypasses the weeding out

commit 4bacc3ab78a4511e01f5a50695c132a8db7aba89
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Thu Jul 23 06:03:26 2009 +0400

    use Encode to get canonic IANA name of an encoding

diff --git a/sbin/rt-test-dependencies.in b/sbin/rt-test-dependencies.in
index d68fa14..92dfccd 100755
--- a/sbin/rt-test-dependencies.in
+++ b/sbin/rt-test-dependencies.in
@@ -234,7 +234,7 @@ Scalar::Util
 Module::Versions::Report 1.05
 Cache::Simple::TimedExpiry
 Calendar::Simple
-Encode 2.13
+Encode 2.21
 CSS::Squish 0.06
 File::Glob
 Devel::StackTrace 1.19
diff --git a/share/html/Ticket/Attachment/WithHeaders/dhandler b/share/html/Ticket/Attachment/WithHeaders/dhandler
index 43f1de0..399da37 100644
--- a/share/html/Ticket/Attachment/WithHeaders/dhandler
+++ b/share/html/Ticket/Attachment/WithHeaders/dhandler
@@ -60,11 +60,11 @@
     }
 
     my $content_type = 'text/plain';
-    if ( my $enc = $AttachmentObj->OriginalEncoding ) {
-        # normalize Encode.pm convention with IANA ones
-        $enc = 'big5'  if $enc eq 'big5-eten';
-        $enc = 'utf-8' if $enc eq 'utf8';
-        $content_type .= ";charset=$enc";
+    my $enc = $AttachmentObj->OriginalEncoding;
+    if ( $enc ) {
+        my $iana = Encode::find_encoding($enc);
+        $iana = $iana ? $iana->mime_name : $enc;
+        $content_type .= ";charset=$iana";
     }
 
     # XXX: should we check handle html here and integrate headers into html?

commit 4eb0e0e9b494bec9015888d2e20a7515695393f7
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Thu Jul 23 06:07:05 2009 +0400

    use Encode to find IANA name in Ticket/Attachment/dhandler

diff --git a/share/html/Ticket/Attachment/dhandler b/share/html/Ticket/Attachment/dhandler
index 1ad51d9..d4d556b 100755
--- a/share/html/Ticket/Attachment/dhandler
+++ b/share/html/Ticket/Attachment/dhandler
@@ -74,10 +74,9 @@
      }
 
      if (my $enc = $AttachmentObj->OriginalEncoding) {
-	# normalize Encode.pm convention with IANA ones
-        $enc = 'big5'  if $enc eq 'big5-eten';
-        $enc = 'utf-8' if $enc eq 'utf8';
-	$content_type .= ";charset=$enc";
+        my $iana = Encode::find_encoding( $enc );
+        $iana = $iana? $iana->mime_name : $enc;
+	$content_type .= ";charset=$iana";
      }
 
      # unless (RT->Config->Get('TrustMIMEAttachments')) {

commit e23706ef4013205958a269b2aa90578a58b2936a
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Thu Jul 23 07:51:25 2009 +0400

    use EncodedHeaders when show an attachment with headers

diff --git a/share/html/Ticket/Attachment/WithHeaders/dhandler b/share/html/Ticket/Attachment/WithHeaders/dhandler
index 399da37..18c39eb 100644
--- a/share/html/Ticket/Attachment/WithHeaders/dhandler
+++ b/share/html/Ticket/Attachment/WithHeaders/dhandler
@@ -70,7 +70,7 @@
     # XXX: should we check handle html here and integrate headers into html?
     $r->content_type( $content_type );
     $m->clear_buffer;
-    $m->out( $AttachmentObj->OriginalHeaders );
+    $m->out( $AttachmentObj->EncodedHeaders( $enc ) );
     $m->out( "\n\n" );
     $m->out( $AttachmentObj->OriginalContent );
     $m->abort;

commit e97ccf8bad8218704ad1a171d34afd3762c278c2
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Thu Jul 23 14:25:56 2009 +0400

    factor out EncodeToMIME from SendEmail action into RT::Interface::Email

diff --git a/lib/RT/Action/SendEmail.pm b/lib/RT/Action/SendEmail.pm
index 7b756be..a09bd3e 100755
--- a/lib/RT/Action/SendEmail.pm
+++ b/lib/RT/Action/SendEmail.pm
@@ -55,8 +55,6 @@ use warnings;
 
 use base qw(RT::Action);
 
-use MIME::Words qw(encode_mimeword);
-
 use RT::EmailParser;
 use RT::Interface::Email;
 use Email::Address;
@@ -413,10 +411,7 @@ sub AddAttachment {
         Type     => $attach->ContentType,
         Charset  => $attach->OriginalEncoding,
         Data     => $attach->OriginalContent,
-        Filename => defined( $attach->Filename )
-        ? $self->MIMEEncodeString( $attach->Filename,
-            RT->Config->Get('EmailOutputEncoding') )
-        : undef,
+        Filename => $self->MIMEEncodeString( $attach->Filename ),
         'RT-Attachment:' => $self->TicketObj->Id . "/"
             . $self->TransactionObj->Id . "/"
             . $attach->id,
@@ -1075,68 +1070,18 @@ sub SetHeaderAsEncoding {
 
 }
 
-=head2 MIMEEncodeString STRING ENCODING
+=head2 MIMEEncodeString
+
+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;
-
-    # using RFC2047 notation, sec 2.
-    # encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
-    my $charset  = shift;
-    my $encoding = 'B';
-
-    # 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 encode_mimeword( $_, $encoding, $charset ), @chunks;
-    return ($value);
+    return RT::Interface::Email::EncodeToMIME( String => $_[0], Charset => $_[1] );
 }
 
 eval "require RT::Action::SendEmail_Vendor";
diff --git a/lib/RT/Attachment_Overlay.pm b/lib/RT/Attachment_Overlay.pm
index 3892595..9c0fcf6 100644
--- a/lib/RT/Attachment_Overlay.pm
+++ b/lib/RT/Attachment_Overlay.pm
@@ -419,9 +419,7 @@ sub ContentAsMIME {
     my $entity = new MIME::Entity;
     foreach my $header ($self->SplitHeaders) {
         my ($h_key, $h_val) = split /:/, $header, 2;
-	# We need to encode header as RFC 2047, to avoid conflict with
-	# OrignalContent Encoding that may break display
-        $entity->head->add( $h_key, Encode::encode('MIME-Header', $h_val ) );
+        $entity->head->add( $h_key, RT::Interface::Email::EncodeToMIME( String => $h_val ) );
     }
 
     use MIME::Body;
diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index bd888ee..703338b 100755
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -622,7 +622,7 @@ sub ForwardTransaction {
         );
     }
 
-    $mail->head->set( $_ => Encode::encode('MIME-Header', $args{ $_ }) )
+    $mail->head->set( $_ => EncodeToMIME( String => $args{$_} ) )
         foreach grep defined $args{$_}, qw(To Cc Bcc);
 
     $mail->attach(
@@ -643,8 +643,8 @@ sub ForwardTransaction {
         $from = $obj->QueueObj->CorrespondAddress
             || RT->Config->Get('CorrespondAddress');
     }
-    $mail->head->set( Subject => Encode::encode('MIME-Header', "Fwd: $subject") );
-    $mail->head->set( From    => Encode::encode('MIME-Header', $from) );
+    $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
@@ -759,6 +759,84 @@ sub SignEncrypt {
     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 $self  = shift;
+    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 ) = @_;

commit c56ae37660a910ecaf6a7baceb852a16bd176d4d
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:12:09 2009 +0400

    * ContentAsMIME into transactions

diff --git a/lib/RT/Transaction_Overlay.pm b/lib/RT/Transaction_Overlay.pm
index 3878c61..5dd9118 100755
--- a/lib/RT/Transaction_Overlay.pm
+++ b/lib/RT/Transaction_Overlay.pm
@@ -522,6 +522,53 @@ sub _Attach {
 
 # }}}
 
+sub ContentAsMIME {
+    my $self = shift;
+
+    my $main_content = $self->ContentObj;
+    my $entity = $main_content->ContentAsMIME;
+
+    if ( $main_content->Parent ) {
+        # main content is not top most entity, we shouldn't loose
+        # From/To/Cc headers that are on a top part
+        my $attachments = RT::Attachments->new( $self->CurrentUser );
+        $attachments->Columns(qw(id Parent TransactionId Headers));
+        $attachments->Limit( FIELD => 'TransactionId', VALUE => $self->id );
+        $attachments->Limit( FIELD => 'Parent', VALUE => 0 );
+        $attachments->Limit( FIELD => 'Parent', OPERATOR => 'IS', VALUE => 'NULL', QUOTEVALUE => 0 );
+        $attachments->OrderBy( FIELD => 'id', ORDER => 'ASC' );
+        my $tmp = $attachments->First;
+        if ( $tmp && $tmp->id ne $main_content->id ) {
+            $entity->make_multipart;
+            $entity->head->add( split /:/, $_, 2 ) foreach $tmp->SplitHeaders;
+            $entity->make_singlepart;
+        }
+    }
+
+    my $attachments = RT::Attachments->new( $self->CurrentUser );
+    $attachments->Limit( FIELD => 'TransactionId', VALUE => $self->id );
+    $attachments->Limit(
+        FIELD => 'id',
+        OPERATOR => '!=',
+        VALUE => $main_content->id,
+    );
+    $attachments->Limit(
+        FIELD => 'ContentType',
+        OPERATOR => 'NOT STARTSWITH',
+        VALUE => 'multipart/',
+    );
+    $attachments->Limit(
+        FIELD => 'Content',
+        OPERATOR => '!=',
+        VALUE => '',
+    );
+    while ( my $a = $attachments->Next ) {
+        $entity->make_multipart unless $entity->is_multipart;
+        $entity->add_part( $a->ContentAsMIME );
+    }
+    return $entity;
+}
+
 # {{{ Routines dealing with Transaction Attributes
 
 # {{{ sub Description 

commit 25ff4583996e8c6712b023210bced7bcdc6358dd
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:12:53 2009 +0400

    * limit when user has no rights

diff --git a/lib/RT/Ticket_Overlay.pm b/lib/RT/Ticket_Overlay.pm
index 6d63077..f658f60 100755
--- a/lib/RT/Ticket_Overlay.pm
+++ b/lib/RT/Ticket_Overlay.pm
@@ -3470,6 +3470,13 @@ sub Transactions {
             );
 
         }
+    } else {
+        $transactions->Limit(
+            SUBCLAUSE => 'acl',
+            FIELD    => 'id',
+            VALUE    => 0,
+            ENTRYAGGREGATOR => 'AND'
+        );
     }
 
     return ($transactions);

commit 6dd3ce595ad7814b807113bf176cb95aafe6b118
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:14:12 2009 +0400

    * split ForwardTransaction into ForwardTicket and SendForward

diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index 703338b..d57f8eb 100755
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -548,7 +548,7 @@ sub SendEmailUsingTemplate {
 
 =head2 ForwardTransaction TRANSACTION, To => '', Cc => '', Bcc => ''
 
-Forwards transaction with all attachments 'message/rfc822'.
+Forwards transaction with all attachments as 'message/rfc822'.
 
 =cut
 
@@ -556,55 +556,72 @@ sub ForwardTransaction {
     my $txn = shift;
     my %args = ( To => '', Cc => '', Bcc => '', @_ );
 
-    my $main_content = $txn->ContentObj;
-    my $entity = $main_content->ContentAsMIME;
-
-    if ( $main_content->Parent ) {
-        # main content is not top most entity, we shouldn't loose
-        # From/To/Cc headers that are on a top part
-        my $attachments = RT::Attachments->new( $txn->CurrentUser );
-        $attachments->Columns(qw(id Parent TransactionId Headers));
-        $attachments->Limit( FIELD => 'TransactionId', VALUE => $txn->id );
-        $attachments->Limit( FIELD => 'Parent', VALUE => 0 );
-        $attachments->Limit( FIELD => 'Parent', OPERATOR => 'IS', VALUE => 'NULL', QUOTEVALUE => 0 );
-        $attachments->OrderBy( FIELD => 'id', ORDER => 'ASC' );
-        my $tmp = $attachments->First;
-        if ( $tmp && $tmp->id ne $main_content->id ) {
-            $entity->make_multipart;
-            $entity->head->add( split /:/, $_, 2 ) foreach $tmp->SplitHeaders;
-            $entity->make_singlepart;
-        }
-    }
+    my $entity = $txn->ContentAsMIME;
 
-    my $attachments = RT::Attachments->new( $txn->CurrentUser );
-    $attachments->Limit( FIELD => 'TransactionId', VALUE => $txn->id );
-    $attachments->Limit(
-        FIELD => 'id',
-        OPERATOR => '!=',
-        VALUE => $main_content->id,
-    );
-    $attachments->Limit(
-        FIELD => 'ContentType',
-        OPERATOR => 'NOT STARTSWITH',
-        VALUE => 'multipart/',
+    return SendForward( %args, Entity => $entity, Transaction => $txn );
+}
+
+=head2 ForwardTicket TICKET, To => '', Cc => '', Bcc => ''
+
+Forwards ticket with all transactions and 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',
     );
-    $attachments->Limit(
-        FIELD => 'Content',
-        OPERATOR => '!=',
-        VALUE => '',
+    $entity->add_part( $_ ) foreach 
+        map $_->ContentAsMIME,
+        @{ $txns->ItemsArrayRef };
+
+    return SendForward( %args, Entity => $entity, Ticket => $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 => '',
+        @_
     );
-    while ( my $a = $attachments->Next ) {
-        $entity->make_multipart unless $entity->is_multipart;
-        $entity->add_part( $a->ContentAsMIME );
+
+    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  => 'Forward',
+        Template  => $args{'Template'},
         Arguments => {
+            Ticket      => $ticket,
             Transaction => $txn,
-            Ticket      => $txn->Object,
         },
     );
+
     my $mail;
     if ( $template ) {
         $mail = $template->MIMEObj;
@@ -614,8 +631,13 @@ sub ForwardTransaction {
     unless ( $mail ) {
         $RT::Logger->warning("Couldn't generate email using template 'Forward'");
 
-        my $description = 'This is forward of transaction #'
-            . $txn->id ." of a ticket #". $txn->ObjectId;
+        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,
@@ -633,14 +655,15 @@ sub ForwardTransaction {
     );
 
     my $from;
-    my $subject = $txn->Subject || $txn->Object->Subject;
+    my $subject = '';
+    $subject = $txn->Subject if $txn;
+    $subject ||= $ticket->Subject if $ticket;
     if ( RT->Config->Get('ForwardFromUser') ) {
-        $from = $txn->CurrentUser->UserObj->EmailAddress;
+        $from = ($txn || $ticket)->CurrentUser->UserObj->EmailAddress;
     } else {
         # XXX: what if want to forward txn of other object than ticket?
-        my $obj = $txn->Object;
-        $subject = AddSubjectTag( $subject, $obj );
-        $from = $obj->QueueObj->CorrespondAddress
+        $subject = AddSubjectTag( $subject, $ticket );
+        $from = $ticket->QueueObj->CorrespondAddress
             || RT->Config->Get('CorrespondAddress');
     }
     $mail->head->set( Subject => EncodeToMIME( String => "Fwd: $subject" ) );
@@ -648,10 +671,10 @@ sub ForwardTransaction {
 
     my $status = RT->Config->Get('ForwardFromUser')
         # never sign if we forward from User
-        ? SendEmail( Entity => $mail, Transaction => $txn, Sign => 0 )
-        : SendEmail( Entity => $mail, Transaction => $txn );
-    return (0, $txn->loc("Couldn't send email")) unless $status;
-    return (1, $txn->loc("Send email successfully"));
+        ? 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

commit 8035003bd370ccefa79745df3c2ffbabe5908e30
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:15:49 2009 +0400

    * heh, in RT::I::Email everything else is a function

diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index d57f8eb..e987a02 100755
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -797,7 +797,6 @@ is used, or "latin-1" if that is not set.
 =cut
 
 sub EncodeToMIME {
-    my $self  = shift;
     my %args = (
         String => undef,
         Charset  => undef,

commit 79aa1ddd4c373bbb86a805bb0035e75b22d79279
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:16:39 2009 +0400

    * register forward in actions

diff --git a/share/html/Ticket/Elements/Tabs b/share/html/Ticket/Elements/Tabs
index f288013..83d9382 100755
--- a/share/html/Ticket/Elements/Tabs
+++ b/share/html/Ticket/Elements/Tabs
@@ -173,6 +173,14 @@ if ($Ticket) {
         };
     }
 
+    if ( $Ticket->CurrentUserHasRight('ForwardMessage') )
+    {
+        $actions->{'FA'} = {
+            title => loc('Forward'),
+            path  => "Ticket/Forward.html?id=" . $id,
+        };
+    }
+
     if ( $can{'ModifyTicket'} ) {
         if ( $Ticket->Status ne 'resolved' ) {
             $actions->{'G'} = {

commit 2ef6feb021e9c0f62e7c392f18269a2e9c98e9ec
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:17:23 2009 +0400

    * change web ui according to new API

diff --git a/share/html/Ticket/Forward.html b/share/html/Ticket/Forward.html
index a0d0b41..9830f91 100644
--- a/share/html/Ticket/Forward.html
+++ b/share/html/Ticket/Forward.html
@@ -85,15 +85,20 @@ $id = $ARGS{'id'} = $TicketObj->id;
 Abort( loc("Permission Denied") )
     unless $TicketObj->CurrentUserHasRight('ForwardMessage');
 
-my $txn = RT::Transaction->new( $session{'CurrentUser'} );
-$txn->Load( $QuoteTransaction );
-Abort( loc("Couldn't load transaction #[_1]", $QuoteTransaction) )
-    unless $txn->id;
+my $txn;
+if ( $QuoteTransaction ) {
+    $txn = RT::Transaction->new( $session{'CurrentUser'} );
+    $txn->Load( $QuoteTransaction );
+    Abort( loc("Couldn't load transaction #[_1]", $QuoteTransaction) )
+        unless $txn->id;
+}
 
 my @results;
 if ( $Forward || $ForwardAndReturn ) {
     require RT::Interface::Email;
-    my ($status, $msg) = RT::Interface::Email::ForwardTransaction( $txn, %ARGS );
+    my ($status, $msg) = $txn
+        ? RT::Interface::Email::ForwardTransaction( $txn, %ARGS )
+        : RT::Interface::Email::ForwardTicket( $TicketObj, %ARGS );
     push @results, $msg;
 
     if ( $ForwardAndReturn ) {
@@ -104,7 +109,9 @@ if ( $Forward || $ForwardAndReturn ) {
     }
 }
 
-my $Title = loc('Forward message');
+my $Title = $txn
+    ? loc('Forward transaction #[_1]', $txn->id)
+    : loc('Forward ticket #[_1]', $TicketObj->id);
 
 </%INIT>
 

commit 1e6852af90266819f284ee8ec997bb36c1d83296
Author: Ruslan Zakirov <Ruslan.Zakirov at gmail.com>
Date:   Wed Jul 29 02:18:30 2009 +0400

    * update initial data

diff --git a/etc/initialdata b/etc/initialdata
index 6fa740a..ec4e1d9 100755
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -380,7 +380,7 @@ The ticket has been approved, you may now start to act on it.
        Description => "Heading of a forwarded message", # loc
        Content => q{
 
-This is forward of transaction #{ $Transaction->id } of a ticket #{ $Ticket->id }
+This is forward { $Transaction? ('of transaction #'. $Transaction->id) : '' }of a ticket #{ $Ticket->id }
 }
     },
     {  Queue       => 0,

-----------------------------------------------------------------------


More information about the Rt-commit mailing list