1<?php
2/**
3 * Copyright 2013-2017 Horde LLC (http://www.horde.org/)
4 *
5 * See the enclosed file COPYING for license information (LGPL). If you
6 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
7 *
8 * @category  Horde
9 * @copyright 2013-2017 Horde LLC
10 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
11 * @package   Smtp
12 */
13
14/**
15 * Stream filter to escape output to the SMTP DATA command (RFC 5321
16 * [4.1.1.4]).
17 *
18 * @author    Michael Slusarz <slusarz@horde.org>
19 * @category  Horde
20 * @copyright 2013-2017 Horde LLC
21 * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
22 * @package   Smtp
23 */
24class Horde_Smtp_Filter_Data extends php_user_filter
25{
26    /**
27     * Last character.
28     *
29     * @var string
30     */
31    private $_last = null;
32
33    /**
34     * @see stream_filter_register()
35     */
36    public function filter($in, $out, &$consumed, $closing)
37    {
38        while ($bucket = stream_bucket_make_writeable($in)) {
39            $consumed += $bucket->datalen;
40
41            // Handle split EOL in the next data bucket.
42            if ($bucket->data[$bucket->datalen - 1] === "\r") {
43                $bucket->data = substr($bucket->data, 0, -1);
44            }
45
46            // If the first character is '.', need to check if it has to be
47            // doubled.
48            if (($bucket->data[0] === '.') &&
49                (is_null($this->_last) || ($this->_last === "\n"))) {
50                $bucket->data = '.' . $bucket->data;
51            }
52
53            // EOLs need to be CRLF; double leading periods.
54            $bucket->data = str_replace(
55                array("\r\n", "\r", "\n", "\n."),
56                array("\n", "\n", "\r\n", "\n.."),
57                $bucket->data
58            );
59
60            $this->_last = substr($bucket->data, -1);
61
62            stream_bucket_append($out, $bucket);
63        }
64
65        return PSFS_PASS_ON;
66    }
67
68}
69