1<?php
2
3/*
4 * This file is part of SwiftMailer.
5 * (c) 2009 Fabien Potencier
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 * Redirects all email to a single recipient.
13 *
14 * @author     Fabien Potencier
15 */
16class Swift_Plugins_RedirectingPlugin implements Swift_Events_SendListener
17{
18    /**
19     * The recipient who will receive all messages.
20     *
21     * @var mixed
22     */
23    private $recipient;
24
25    /**
26     * List of regular expression for recipient whitelisting.
27     *
28     * @var array
29     */
30    private $whitelist = array();
31
32    /**
33     * Create a new RedirectingPlugin.
34     *
35     * @param mixed $recipient
36     * @param array $whitelist
37     */
38    public function __construct($recipient, array $whitelist = array())
39    {
40        $this->recipient = $recipient;
41        $this->whitelist = $whitelist;
42    }
43
44    /**
45     * Set the recipient of all messages.
46     *
47     * @param mixed $recipient
48     */
49    public function setRecipient($recipient)
50    {
51        $this->recipient = $recipient;
52    }
53
54    /**
55     * Get the recipient of all messages.
56     *
57     * @return mixed
58     */
59    public function getRecipient()
60    {
61        return $this->recipient;
62    }
63
64    /**
65     * Set a list of regular expressions to whitelist certain recipients.
66     *
67     * @param array $whitelist
68     */
69    public function setWhitelist(array $whitelist)
70    {
71        $this->whitelist = $whitelist;
72    }
73
74    /**
75     * Get the whitelist.
76     *
77     * @return array
78     */
79    public function getWhitelist()
80    {
81        return $this->whitelist;
82    }
83
84    /**
85     * Invoked immediately before the Message is sent.
86     *
87     * @param Swift_Events_SendEvent $evt
88     */
89    public function beforeSendPerformed(Swift_Events_SendEvent $evt)
90    {
91        $message = $evt->getMessage();
92        $headers = $message->getHeaders();
93
94        // conditionally save current recipients
95
96        if ($headers->has('to')) {
97            $headers->addMailboxHeader('X-Swift-To', $message->getTo());
98        }
99
100        if ($headers->has('cc')) {
101            $headers->addMailboxHeader('X-Swift-Cc', $message->getCc());
102        }
103
104        if ($headers->has('bcc')) {
105            $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc());
106        }
107
108        // Filter remaining headers against whitelist
109        $this->filterHeaderSet($headers, 'To');
110        $this->filterHeaderSet($headers, 'Cc');
111        $this->filterHeaderSet($headers, 'Bcc');
112
113        // Add each hard coded recipient
114        $to = $message->getTo();
115        if (null === $to) {
116            $to = array();
117        }
118
119        foreach ((array) $this->recipient as $recipient) {
120            if (!array_key_exists($recipient, $to)) {
121                $message->addTo($recipient);
122            }
123        }
124    }
125
126    /**
127     * Filter header set against a whitelist of regular expressions.
128     *
129     * @param Swift_Mime_SimpleHeaderSet $headerSet
130     * @param string                     $type
131     */
132    private function filterHeaderSet(Swift_Mime_SimpleHeaderSet $headerSet, $type)
133    {
134        foreach ($headerSet->getAll($type) as $headers) {
135            $headers->setNameAddresses($this->filterNameAddresses($headers->getNameAddresses()));
136        }
137    }
138
139    /**
140     * Filtered list of addresses => name pairs.
141     *
142     * @param array $recipients
143     *
144     * @return array
145     */
146    private function filterNameAddresses(array $recipients)
147    {
148        $filtered = array();
149
150        foreach ($recipients as $address => $name) {
151            if ($this->isWhitelisted($address)) {
152                $filtered[$address] = $name;
153            }
154        }
155
156        return $filtered;
157    }
158
159    /**
160     * Matches address against whitelist of regular expressions.
161     *
162     * @param $recipient
163     *
164     * @return bool
165     */
166    protected function isWhitelisted($recipient)
167    {
168        if (in_array($recipient, (array) $this->recipient)) {
169            return true;
170        }
171
172        foreach ($this->whitelist as $pattern) {
173            if (preg_match($pattern, $recipient)) {
174                return true;
175            }
176        }
177
178        return false;
179    }
180
181    /**
182     * Invoked immediately after the Message is sent.
183     *
184     * @param Swift_Events_SendEvent $evt
185     */
186    public function sendPerformed(Swift_Events_SendEvent $evt)
187    {
188        $this->restoreMessage($evt->getMessage());
189    }
190
191    private function restoreMessage(Swift_Mime_SimpleMessage $message)
192    {
193        // restore original headers
194        $headers = $message->getHeaders();
195
196        if ($headers->has('X-Swift-To')) {
197            $message->setTo($headers->get('X-Swift-To')->getNameAddresses());
198            $headers->removeAll('X-Swift-To');
199        } else {
200            $message->setTo(null);
201        }
202
203        if ($headers->has('X-Swift-Cc')) {
204            $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses());
205            $headers->removeAll('X-Swift-Cc');
206        }
207
208        if ($headers->has('X-Swift-Bcc')) {
209            $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses());
210            $headers->removeAll('X-Swift-Bcc');
211        }
212    }
213}
214