1<?php
2/* Copyright (c) 1998-2012 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4/**
5 * Class ilMimeMail
6 */
7class ilMimeMail
8{
9    /**
10     * @var \ilMailMimeTransport|null
11     */
12    protected static $defaultTransport;
13
14    /**
15     * @var string
16     */
17    protected $subject = '';
18
19    /**
20     * @var string
21     */
22    protected $body = '';
23
24    /**
25     * @var string
26     */
27    protected $finalBody = '';
28
29    /**
30     * @var string
31     */
32    protected $finalBodyAlt = '';
33
34    /**
35     * list of To addresses
36     * @var	array
37     */
38    protected $sendto = array();
39
40    /**
41     * @var	array
42     */
43    protected $acc = array();
44
45    /**
46     * @var	array
47     */
48    protected $abcc = array();
49
50    /**
51     * @var array
52     */
53    protected $images = array();
54
55    /**
56     * 	paths of attached files
57     * 	@var array
58     */
59    protected $aattach = array();
60
61    /**
62     * @var array
63     */
64    protected $actype = array();
65
66    /**
67     * @var array
68     */
69    protected $adispo = array();
70
71    /**
72     * @var array
73     */
74    protected $adisplay = array();
75
76    /**
77     * @var \ilMailMimeSender
78     */
79    protected $sender;
80
81    /**
82     * ilMimeMail constructor.
83     */
84    public function __construct()
85    {
86        global $DIC;
87
88        if (!(self::getDefaultTransport() instanceof \ilMailMimeTransport)) {
89            $factory = $DIC["mail.mime.transport.factory"];
90            self::setDefaultTransport($factory->getTransport());
91        }
92    }
93
94    /**
95     * @param \ilMailMimeTransport|null $transport
96     * @throws \InvalidArgumentException
97     */
98    public static function setDefaultTransport($transport)
99    {
100        if (!is_null($transport) && !($transport instanceof \ilMailMimeTransport)) {
101            throw new \InvalidArgumentException(\sprintf(
102                "The passed argument must be null or of type 'ilMailMimeTransport', %s given!",
103                gettype($transport)
104            ));
105        }
106
107        self::$defaultTransport = $transport;
108    }
109
110    /**
111     * @return \ilMailMimeTransport|null
112     */
113    public static function getDefaultTransport()
114    {
115        return self::$defaultTransport;
116    }
117
118    /**
119     * @param string $subject Define the subject line of the email
120     * @param bool   $a_add_prefix
121     */
122    public function Subject($subject, $a_add_prefix = false)
123    {
124        if ($a_add_prefix) {
125            // #9096
126            require_once 'Services/Mail/classes/class.ilMail.php';
127            $prefix = ilMail::getSubjectPrefix();
128            if (trim($prefix)) {
129                $subject = trim($prefix) . ' ' . $subject;
130            }
131        }
132
133        $this->subject = $subject;
134    }
135
136    /**
137     * @return string
138     */
139    public function getSubject()
140    {
141        return $this->subject;
142    }
143
144    /**
145     * @param ilMailMimeSender $sender
146     */
147    public function From(ilMailMimeSender $sender)
148    {
149        $this->sender = $sender;
150    }
151
152    /**
153     * Set the mail recipient
154     * @param string|array To email address, accept both a single address or an array of addresses
155     */
156    public function To($to)
157    {
158        if (is_array($to)) {
159            $this->sendto = $to;
160        } else {
161            $this->sendto[] = $to;
162        }
163    }
164
165    /**
166     * Set the cc mail recipient
167     * @param string|array CC email address, accept both a single address or an array of addresses
168     */
169    public function Cc($cc)
170    {
171        if (is_array($cc)) {
172            $this->acc = $cc;
173        } else {
174            $this->acc[] = $cc;
175        }
176    }
177
178    /**
179     * Set the bcc mail recipient
180     * @param string|array BCC email address, accept both a single address or an array of addresses
181     */
182    public function Bcc($bcc)
183    {
184        if (is_array($bcc)) {
185            $this->abcc = $bcc;
186        } else {
187            $this->abcc[] = $bcc;
188        }
189    }
190
191    /**
192     * @return array
193     */
194    public function getTo()
195    {
196        return $this->sendto;
197    }
198
199    /**
200     * @return array
201     */
202    public function getCc()
203    {
204        return $this->acc;
205    }
206
207    /**
208     * @return array
209     */
210    public function getBcc()
211    {
212        return $this->abcc;
213    }
214
215    /**
216     * @param string $body
217     */
218    public function Body($body)
219    {
220        $this->body = $body;
221    }
222
223    /**
224     * @return string
225     */
226    public function getFinalBody()
227    {
228        return $this->finalBody;
229    }
230
231    /**
232     * @return string
233     */
234    public function getFinalBodyAlt()
235    {
236        return $this->finalBodyAlt;
237    }
238
239    /**
240     * @return ilMailMimeSender
241     */
242    public function getFrom()
243    {
244        return $this->sender;
245    }
246
247    /**
248     * Attach a file to the mail
249     * @param string $filename     Path of the file to attach
250     * @param string $file_type    MIME-type of the file. default to 'application/x-unknown-content-type'
251     * @param string $disposition  Instruct the Mailclient to display the file if possible ("inline") or always as a link ("attachment") possible values are "inline", "attachment"
252     * @param string $display_name Filename to use in email (if different from source file)
253     */
254    public function Attach($filename, $file_type = '', $disposition = 'inline', $display_name = null)
255    {
256        if ($file_type == '') {
257            $file_type = 'application/octet-stream';
258        }
259
260        $this->aattach[] = $filename;
261        $this->actype[] = $file_type;
262        $this->adispo[] = $disposition;
263        $this->adisplay[] = $display_name;
264    }
265
266    /**
267     * @return array An array of attachments. Each element must container to associative keys, 'path' and 'name'
268     */
269    public function getAttachments()
270    {
271        $attachments = array();
272
273        $i = 0;
274        foreach ($this->aattach as $attachment) {
275            $name = '';
276            if (isset($this->adisplay[$i]) && strlen($this->adisplay[$i]) > 0) {
277                $name = $this->adisplay[$i];
278            }
279
280            $attachments[] = array(
281                'path' => $attachment,
282                'name' => $name
283            );
284            ++$i;
285        }
286
287        return $attachments;
288    }
289
290    /**
291     * @return array An array of images. Each element must container to associative keys, 'path', 'cid' and 'name'
292     */
293    public function getImages()
294    {
295        return array_values($this->images);
296    }
297
298    /**
299     * Build the relevant email data
300     */
301    protected function build()
302    {
303        global $DIC;
304
305        $this->finalBodyAlt = '';
306        $this->finalBody = '';
307        $this->images = array();
308
309        if ($DIC->settings()->get('mail_send_html', 0)) {
310            $skin = $DIC['ilClientIniFile']->readVariable('layout', 'skin');
311
312            $this->buildBodyParts($skin);
313            $this->buildHtmlInlineImages($skin);
314        } else {
315            $this->finalBody = $this->body;
316        }
317    }
318
319    /**
320     * @param string $skin
321     */
322    protected function buildBodyParts($skin)
323    {
324        if (0 == strlen($this->body)) {
325            $this->body = ' ';
326        }
327
328        if (strip_tags($this->body, '<b><u><i><a>') == $this->body) {
329            // Let's assume(!) that there is no HTML (except certain tags, e.g. used for object title formatting, where the consumer is not aware of this), so convert "\n" to "<br>"
330            $this->finalBodyAlt = $this->body;
331            $this->body = \ilUtil::makeClickable(nl2br($this->body));
332        } else {
333            // if there is HTML, convert "<br>" to "\n" and strip tags for plain text alternative
334            $this->finalBodyAlt = strip_tags(str_ireplace(array("<br />", "<br>", "<br/>"), "\n", $this->body));
335        }
336
337        $this->finalBody = str_replace('{PLACEHOLDER}', $this->body, $this->getHtmlEnvelope($skin));
338    }
339
340    /**
341     * @param string $skin
342     * @return string
343     */
344    protected function getHtmlEnvelope($skin)
345    {
346        $bracket_path = './Services/Mail/templates/default/tpl.html_mail_template.html';
347
348        if ($skin != 'default') {
349            $tplpath = './Customizing/global/skin/' . $skin . '/Services/Mail/tpl.html_mail_template.html';
350
351            if (file_exists($tplpath)) {
352                $bracket_path = './Customizing/global/skin/' . $skin . '/Services/Mail/tpl.html_mail_template.html';
353            }
354        }
355
356        return file_get_contents($bracket_path);
357    }
358
359    /**
360     * @param string $skin
361     */
362    protected function buildHtmlInlineImages($skin)
363    {
364        $this->gatherImagesFromDirectory('./Services/Mail/templates/default/img');
365
366        if ($skin != 'default') {
367            $skinDirectory = './Customizing/global/skin/' . $skin . '/Services/Mail/img';
368            if (is_dir($skinDirectory) && is_readable($skinDirectory)) {
369                $this->gatherImagesFromDirectory($skinDirectory, true);
370            }
371        }
372    }
373
374    /**
375     * @param $directory
376     * @param bool $clearPrevious
377     */
378    protected function gatherImagesFromDirectory($directory, $clearPrevious = false)
379    {
380        if ($clearPrevious) {
381            $this->images = array();
382        }
383
384        foreach (new \RegexIterator(new \DirectoryIterator($directory), '/\.(jpg|svg|png)$/i') as $file) {
385            /**
386             * @var $file \SplFileInfo
387             */
388            $cid = 'img/' . $file->getFilename();
389
390            $this->images[$cid] = array(
391                'path' => $file->getPathname(),
392                'cid' => $cid,
393                'name' => $file->getFilename()
394            );
395        }
396    }
397
398    /**
399     * @param $transport \ilMailMimeTransport|null
400     * @return bool A boolean flag whether or not the transport might be successful
401     */
402    public function Send(\ilMailMimeTransport $transport = null)
403    {
404        if (!($transport instanceof \ilMailMimeTransport)) {
405            $transport = self::getDefaultTransport();
406        }
407
408        $this->build();
409
410        return $transport->send($this);
411    }
412}
413