1<?php
2
3/*
4 * This file is part of SwiftMailer.
5 * (c) 2004-2009 Chris Corbyn
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11/**
12 * Handles Quoted Printable (QP) Transfer Encoding in Swift Mailer.
13 *
14 * @author     Chris Corbyn
15 */
16class Swift_Mime_ContentEncoder_QpContentEncoder extends Swift_Encoder_QpEncoder implements Swift_Mime_ContentEncoder
17{
18    protected $dotEscape;
19
20    /**
21     * Creates a new QpContentEncoder for the given CharacterStream.
22     *
23     * @param Swift_CharacterStream $charStream to use for reading characters
24     * @param Swift_StreamFilter    $filter     if canonicalization should occur
25     * @param bool                  $dotEscape  if dot stuffing workaround must be enabled
26     */
27    public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null, $dotEscape = false)
28    {
29        $this->dotEscape = $dotEscape;
30        parent::__construct($charStream, $filter);
31    }
32
33    public function __sleep()
34    {
35        return ['charStream', 'filter', 'dotEscape'];
36    }
37
38    protected function getSafeMapShareId()
39    {
40        return static::class.($this->dotEscape ? '.dotEscape' : '');
41    }
42
43    protected function initSafeMap()
44    {
45        parent::initSafeMap();
46        if ($this->dotEscape) {
47            /* Encode . as =2e for buggy remote servers */
48            unset($this->safeMap[0x2e]);
49        }
50    }
51
52    /**
53     * Encode stream $in to stream $out.
54     *
55     * QP encoded strings have a maximum line length of 76 characters.
56     * If the first line needs to be shorter, indicate the difference with
57     * $firstLineOffset.
58     *
59     * @param Swift_OutputByteStream $os              output stream
60     * @param Swift_InputByteStream  $is              input stream
61     * @param int                    $firstLineOffset
62     * @param int                    $maxLineLength
63     */
64    public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
65    {
66        if ($maxLineLength > 76 || $maxLineLength <= 0) {
67            $maxLineLength = 76;
68        }
69
70        $thisLineLength = $maxLineLength - $firstLineOffset;
71
72        $this->charStream->flushContents();
73        $this->charStream->importByteStream($os);
74
75        $currentLine = '';
76        $prepend = '';
77        $size = $lineLen = 0;
78
79        while (false !== $bytes = $this->nextSequence()) {
80            // If we're filtering the input
81            if (isset($this->filter)) {
82                // If we can't filter because we need more bytes
83                while ($this->filter->shouldBuffer($bytes)) {
84                    // Then collect bytes into the buffer
85                    if (false === $moreBytes = $this->nextSequence(1)) {
86                        break;
87                    }
88
89                    foreach ($moreBytes as $b) {
90                        $bytes[] = $b;
91                    }
92                }
93                // And filter them
94                $bytes = $this->filter->filter($bytes);
95            }
96
97            $enc = $this->encodeByteSequence($bytes, $size);
98
99            $i = strpos($enc, '=0D=0A');
100            $newLineLength = $lineLen + (false === $i ? $size : $i);
101
102            if ($currentLine && $newLineLength >= $thisLineLength) {
103                $is->write($prepend.$this->standardize($currentLine));
104                $currentLine = '';
105                $prepend = "=\r\n";
106                $thisLineLength = $maxLineLength;
107                $lineLen = 0;
108            }
109
110            $currentLine .= $enc;
111
112            if (false === $i) {
113                $lineLen += $size;
114            } else {
115                // 6 is the length of '=0D=0A'.
116                $lineLen = $size - strrpos($enc, '=0D=0A') - 6;
117            }
118        }
119        if (\strlen($currentLine)) {
120            $is->write($prepend.$this->standardize($currentLine));
121        }
122    }
123
124    /**
125     * Get the name of this encoding scheme.
126     * Returns the string 'quoted-printable'.
127     *
128     * @return string
129     */
130    public function getName()
131    {
132        return 'quoted-printable';
133    }
134}
135