1<?php
2
3declare(strict_types=1);
4
5/**
6 * @copyright 2017, Morris Jobke <hey@morrisjobke.de>
7 * @copyright 2017, Lukas Reschke <lukas@statuscode.ch>
8 *
9 * @author Bjoern Schiessle <bjoern@schiessle.org>
10 * @author brad2014 <brad2014@users.noreply.github.com>
11 * @author Joas Schilling <coding@schilljs.com>
12 * @author Julius Härtl <jus@bitgrid.net>
13 * @author Lukas Reschke <lukas@statuscode.ch>
14 * @author Morris Jobke <hey@morrisjobke.de>
15 * @author Roeland Jago Douma <roeland@famdouma.nl>
16 * @author Tomasz Paluszkiewicz <tomasz.paluszkiewicz@gmail.com>
17 *
18 * @license GNU AGPL version 3 or any later version
19 *
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU Affero General Public License as
22 * published by the Free Software Foundation, either version 3 of the
23 * License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 * GNU Affero General Public License for more details.
29 *
30 * You should have received a copy of the GNU Affero General Public License
31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 *
33 */
34
35namespace OCA\Appointments\Email;
36
37use OCP\Defaults;
38use OCP\IL10N;
39use OCP\IURLGenerator;
40use OCP\Mail\IEMailTemplate;
41
42/**
43 * Class EMailTemplate
44 *
45 * addBodyText and addBodyButtonGroup automatically opens the body
46 * addFooter, renderHtml, renderText automatically closes the body and the HTML if opened
47 *
48 */
49class EMailTemplateNC implements IEMailTemplate {
50    /** @var Defaults */
51    protected $themingDefaults;
52    /** @var IURLGenerator */
53    protected $urlGenerator;
54    /** @var IL10N */
55    protected $l10n;
56    /** @var string */
57    protected $emailId;
58    /** @var array */
59    protected $data;
60
61    /** @var string */
62    protected $subject = '';
63    /** @var string */
64    protected $htmlBody = '';
65    /** @var string */
66    protected $plainBody = '';
67    /** @var bool indicated if the footer is added */
68    protected $headerAdded = false;
69    /** @var bool indicated if the body is already opened */
70    protected $bodyOpened = false;
71    /** @var bool indicated if there is a list open in the body */
72    protected $bodyListOpened = false;
73    /** @var bool indicated if the footer is added */
74    protected $footerAdded = false;
75
76    protected $head = <<<EOF
77<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
78<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" style="-webkit-font-smoothing:antialiased;background:#f3f3f3!important">
79<head>
80	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
81	<meta name="viewport" content="width=device-width">
82	<title></title>
83	<style type="text/css">@media only screen{html{min-height:100%;background:#F5F5F5}}@media only screen and (max-width:610px){table.body img{width:auto;height:auto}table.body center{min-width:0!important}table.body .container{width:95%!important}table.body .columns{height:auto!important;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:30px!important;padding-right:30px!important}th.small-12{display:inline-block!important;width:100%!important}table.menu{width:100%!important}table.menu td,table.menu th{width:auto!important;display:inline-block!important}table.menu.vertical td,table.menu.vertical th{display:block!important}table.menu[align=center]{width:auto!important}}</style>
84</head>
85<body style="-moz-box-sizing:border-box;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;Margin:0;background:#f3f3f3!important;box-sizing:border-box;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;min-width:100%;padding:0;text-align:left;width:100%!important">
86	<span class="preheader" style="color:#F5F5F5;display:none!important;font-size:1px;line-height:1px;max-height:0;max-width:0;mso-hide:all!important;opacity:0;overflow:hidden;visibility:hidden">
87	</span>
88	<table class="body" style="-webkit-font-smoothing:antialiased;Margin:0;background:#f3f3f3!important;border-collapse:collapse;border-spacing:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;height:100%;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;width:100%">
89		<tr style="padding:0;text-align:left;vertical-align:top">
90			<td class="center" align="center" valign="top" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
91				<center data-parsed="" style="min-width:580px;width:100%">
92EOF;
93
94    protected $tail = <<<EOF
95					</center>
96				</td>
97			</tr>
98		</table>
99		<!-- prevent Gmail on iOS font size manipulation -->
100		<div style="display:none;white-space:nowrap;font:15px courier;line-height:0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div>
101	</body>
102</html>
103EOF;
104
105    protected $header = <<<EOF
106<table align="center" class="wrapper header float-center" style="Margin:0 auto;background:#8a8a8a;background-color:%s;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
107	<tr style="padding:0;text-align:left;vertical-align:top">
108		<td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:20px;text-align:left;vertical-align:top;word-wrap:break-word">
109			<table align="center" class="container" style="Margin:0 auto;background:0 0;border-collapse:collapse;border-spacing:0;margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px">
110				<tbody>
111				<tr style="padding:0;text-align:left;vertical-align:top">
112					<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
113						<table class="row collapse" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
114							<tbody>
115							<tr style="padding:0;text-align:left;vertical-align:top">
116								<center data-parsed="" style="min-width:580px;width:100%%">
117									<img class="logo float-center" src="%s" alt="%s" align="center" style="-ms-interpolation-mode:bicubic;Margin:0 auto;clear:both;display:block;float:none;margin:0 auto;outline:0;text-align:center;text-decoration:none" height="50">
118								</center>
119							</tr>
120							</tbody>
121						</table>
122					</td>
123				</tr>
124				</tbody>
125			</table>
126		</td>
127	</tr>
128</table>
129<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
130	<tbody>
131	<tr style="padding:0;text-align:left;vertical-align:top">
132		<td height="80px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:80px;font-weight:400;hyphens:auto;line-height:80px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
133	</tr>
134	</tbody>
135</table>
136EOF;
137
138    protected $heading = <<<EOF
139<table align="center" class="container main-heading float-center" style="Margin:0 auto;background:0 0!important;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:580px">
140	<tbody>
141	<tr style="padding:0;text-align:left;vertical-align:top">
142		<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
143			<h1 class="text-center" style="Margin:0;Margin-bottom:10px;color:inherit;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:24px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:center;word-wrap:normal">%s</h1>
144		</td>
145	</tr>
146	</tbody>
147</table>
148<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
149	<tbody>
150	<tr style="padding:0;text-align:left;vertical-align:top">
151		<td height="40px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:40px;font-weight:400;hyphens:auto;line-height:40px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
152	</tr>
153	</tbody>
154</table>
155EOF;
156
157    protected $bodyBegin = <<<EOF
158<table align="center" class="wrapper content float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%">
159	<tr style="padding:0;text-align:left;vertical-align:top">
160		<td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
161			<table align="center" class="container has-shadow" style="Margin:0 auto;background:#fefefe;border-collapse:collapse;border-spacing:0;box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 1px 3px 0 rgba(0,0,0,.1);margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px">
162				<tbody>
163				<tr style="padding:0;text-align:left;vertical-align:top">
164					<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
165						<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
166							<tbody>
167							<tr style="padding:0;text-align:left;vertical-align:top">
168								<td height="60px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:60px;font-weight:400;hyphens:auto;line-height:60px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
169							</tr>
170							</tbody>
171						</table>
172EOF;
173
174    protected $bodyText = <<<EOF
175<table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
176	<tbody>
177	<tr style="padding:0;text-align:left;vertical-align:top">
178		<th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
179			<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
180				<tr style="padding:0;text-align:left;vertical-align:top">
181					<th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
182						<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left">%s</p>
183					</th>
184					<th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
185				</tr>
186			</table>
187		</th>
188	</tr>
189	</tbody>
190</table>
191EOF;
192
193    // note: listBegin (like bodyBegin) is not processed through sprintf, so "%" is not escaped as "%%". (bug #12151)
194    protected $listBegin = <<<EOF
195<table class="row description" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%">
196	<tbody>
197	<tr style="padding:0;text-align:left;vertical-align:top">
198		<th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
199			<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
200EOF;
201
202    protected $listItem = <<<EOF
203				<tr style="padding:0;text-align:left;vertical-align:top">
204					<td style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left;width:15px;">
205						<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p>
206					</td>
207					<td style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
208						<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#555;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;padding-left:10px;text-align:left">%s</p>
209					</td>
210					<td class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></td>
211				</tr>
212EOF;
213
214    protected $listEnd = <<<EOF
215			</table>
216		</th>
217	</tr>
218	</tbody>
219</table>
220EOF;
221
222    protected $buttonGroup = <<<EOF
223<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
224	<tbody>
225	<tr style="padding:0;text-align:left;vertical-align:top">
226		<td height="50px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:50px;font-weight:400;hyphens:auto;line-height:50px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
227	</tr>
228	</tbody>
229</table>
230<table align="center" class="row btn-group" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
231	<tbody>
232	<tr style="padding:0;text-align:left;vertical-align:top">
233		<th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
234			<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
235				<tr style="padding:0;text-align:left;vertical-align:top">
236					<th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
237						<center data-parsed="" style="min-width:490px;width:100%%">
238							<table class="button btn default primary float-center" style="Margin:0 0 30px 0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0 0 30px 0;margin-right:15px;max-height:40px;max-width:200px;padding:0;text-align:center;vertical-align:top;width:auto;background:%1\$s;background-color:%1\$s;color:#fefefe;">
239								<tr style="padding:0;text-align:left;vertical-align:top">
240									<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
241										<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
242											<tr style="padding:0;text-align:left;vertical-align:top">
243												<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:0 solid %2\$s;border-collapse:collapse!important;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
244													<a href="%3\$s" style="Margin:0;border:0 solid %4\$s;border-radius:2px;color:%5\$s;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %6\$s;text-decoration:none">%7\$s</a>
245												</td>
246											</tr>
247										</table>
248									</td>
249								</tr>
250							</table>
251							<table class="button btn default secondary float-center" style="Margin:0 0 30px 0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0 0 30px 0;max-height:40px;max-width:200px;padding:0;text-align:center;vertical-align:top;width:auto">
252								<tr style="padding:0;text-align:left;vertical-align:top">
253									<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
254										<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
255											<tr style="padding:0;text-align:left;vertical-align:top">
256												<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:#777;border:0 solid #777;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
257													<a href="%8\$s" style="Margin:0;background-color:#fff;border:0 solid #777;border-radius:2px;color:#6C6C6C!important;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;outline:1px solid #CBCBCB;padding:10px 25px 10px 25px;text-align:left;text-decoration:none">%9\$s</a>
258												</td>
259											</tr>
260										</table>
261									</td>
262								</tr>
263							</table>
264						</center>
265					</th>
266					<th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
267				</tr>
268			</table>
269		</th>
270	</tr>
271	</tbody>
272</table>
273EOF;
274
275    protected $button = <<<EOF
276<table class="spacer" style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
277	<tbody>
278	<tr style="padding:0;text-align:left;vertical-align:top">
279		<td height="50px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:50px;font-weight:400;hyphens:auto;line-height:50px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
280	</tr>
281	</tbody>
282</table>
283<table align="center" class="row btn-group" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
284	<tbody>
285	<tr style="padding:0;text-align:left;vertical-align:top">
286		<th class="small-12 large-12 columns first last" style="Margin:0 auto;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0 auto;padding:0;padding-bottom:30px;padding-left:30px;padding-right:30px;text-align:left;width:550px">
287			<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
288				<tr style="padding:0;text-align:left;vertical-align:top">
289					<th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
290						<center data-parsed="" style="min-width:490px;width:100%%">
291							<table class="button btn default primary float-center" style="Margin:0;border-collapse:collapse;border-spacing:0;display:inline-block;float:none;margin:0;max-height:40px;padding:0;text-align:center;vertical-align:top;width:auto;background:%1\$s;color:#fefefe;background-color:%1\$s;">
292								<tr style="padding:0;text-align:left;vertical-align:top">
293									<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
294										<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
295											<tr style="padding:0;text-align:left;vertical-align:top">
296												<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:0 solid %2\$;border-collapse:collapse!important;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
297													<a href="%3\$s" style="Margin:0;border:0 solid %4\$s;border-radius:2px;color:%5\$s;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %5\$s;text-decoration:none">%7\$s</a>
298												</td>
299											</tr>
300										</table>
301									</td>
302								</tr>
303							</table>
304						</center>
305					</th>
306					<th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
307				</tr>
308			</table>
309		</th>
310	</tr>
311	</tbody>
312</table>
313EOF;
314
315    protected $bodyEnd = <<<EOF
316
317					</td>
318				</tr>
319				</tbody>
320			</table>
321		</td>
322	</tr>
323</table>
324EOF;
325
326    protected $footer = <<<EOF
327<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
328	<tbody>
329	<tr style="padding:0;text-align:left;vertical-align:top">
330		<td height="60px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:60px;font-weight:400;hyphens:auto;line-height:60px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
331	</tr>
332	</tbody>
333</table>
334<table align="center" class="wrapper footer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
335	<tr style="padding:0;text-align:left;vertical-align:top">
336		<td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
337			<center data-parsed="" style="min-width:580px;width:100%%">
338				<table class="spacer float-center" style="Margin:0 auto;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%%">
339					<tbody>
340					<tr style="padding:0;text-align:left;vertical-align:top">
341						<td height="15px" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:15px;font-weight:400;hyphens:auto;line-height:15px;margin:0;mso-line-height-rule:exactly;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">&#xA0;</td>
342					</tr>
343					</tbody>
344				</table>
345				<p class="text-center float-center" align="center" style="Margin:0;Margin-bottom:10px;color:#C8C8C8;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:12px;font-weight:400;line-height:16px;margin:0;margin-bottom:10px;padding:0;text-align:center">%s</p>
346			</center>
347		</td>
348	</tr>
349</table>
350EOF;
351
352    /**
353     * @param Defaults $themingDefaults
354     * @param IURLGenerator $urlGenerator
355     * @param IL10N $l10n
356     * @param string $emailId
357     * @param array $data
358     */
359    public function __construct(Defaults $themingDefaults,
360                                IURLGenerator $urlGenerator,
361                                IL10N $l10n,
362                                $emailId,
363                                array $data) {
364        $this->themingDefaults = $themingDefaults;
365        $this->urlGenerator = $urlGenerator;
366        $this->l10n = $l10n;
367        $this->htmlBody .= $this->head;
368        $this->emailId = $emailId;
369        $this->data = $data;
370    }
371
372    /**
373     * Sets the subject of the email
374     *
375     * @param string $subject
376     */
377    public function setSubject(string $subject) {
378        $this->subject = $subject;
379    }
380
381    /**
382     * Adds a header to the email
383     */
384    public function addHeader() {
385        if ($this->headerAdded) {
386            return;
387        }
388        $this->headerAdded = true;
389
390        $logoUrl = $this->urlGenerator->getAbsoluteURL($this->themingDefaults->getLogo(false));
391        $this->htmlBody .= vsprintf($this->header, [$this->themingDefaults->getColorPrimary(), $logoUrl, $this->themingDefaults->getName()]);
392    }
393
394    /**
395     * Adds a heading to the email
396     *
397     * @param string $title
398     * @param string|bool $plainTitle Title that is used in the plain text email
399     *   if empty the $title is used, if false none will be used
400     */
401    public function addHeading(string $title, $plainTitle = '') {
402        if ($this->footerAdded) {
403            return;
404        }
405        if ($plainTitle === '') {
406            $plainTitle = $title;
407        }
408
409        $this->htmlBody .= vsprintf($this->heading, [htmlspecialchars($title)]);
410        if ($plainTitle !== false) {
411            $this->plainBody .= $plainTitle . PHP_EOL . PHP_EOL;
412        }
413    }
414
415    /**
416     * Open the HTML body when it is not already
417     */
418    protected function ensureBodyIsOpened() {
419        if ($this->bodyOpened) {
420            return;
421        }
422
423        $this->htmlBody .= $this->bodyBegin;
424        $this->bodyOpened = true;
425    }
426
427    /**
428     * Adds a paragraph to the body of the email
429     *
430     * @param string $text Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email
431     * @param string|bool $plainText Text that is used in the plain text email
432     *   if empty the $text is used, if false none will be used
433     */
434    public function addBodyText(string $text, $plainText = '') {
435        if ($this->footerAdded) {
436            return;
437        }
438        if ($plainText === '') {
439            $plainText = $text;
440            $text = htmlspecialchars($text);
441        }
442
443        $this->ensureBodyListClosed();
444        $this->ensureBodyIsOpened();
445
446        $this->htmlBody .= vsprintf($this->bodyText, [$text]);
447        if ($plainText !== false) {
448            $this->plainBody .= $plainText . PHP_EOL . PHP_EOL;
449        }
450    }
451
452    /**
453     * Adds a list item to the body of the email
454     *
455     * @param string $text Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email
456     * @param string $metaInfo Note: When $plainMetaInfo falls back to this, HTML is automatically escaped in the HTML email
457     * @param string $icon Absolute path, must be 16*16 pixels
458     * @param string|bool $plainText Text that is used in the plain text email
459     *   if empty the $text is used, if false none will be used
460     * @param string|bool $plainMetaInfo Meta info that is used in the plain text email
461     *   if empty the $metaInfo is used, if false none will be used
462     * @since 12.0.0
463     */
464    public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '') {
465        $this->ensureBodyListOpened();
466
467        if ($plainText === '') {
468            $plainText = $text;
469            $text = htmlspecialchars($text);
470        }
471        if ($plainMetaInfo === '') {
472            $plainMetaInfo = $metaInfo;
473            $metaInfo = htmlspecialchars($metaInfo);
474        }
475
476        $htmlText = $text;
477        if ($metaInfo) {
478            $htmlText = '<em style="color:#777;">' . $metaInfo . '</em><br>' . $htmlText;
479        }
480        if ($icon !== '') {
481            $icon = '<img src="' . htmlspecialchars($icon) . '" alt="&bull;">';
482        } else {
483            $icon = '&bull;';
484        }
485        $this->htmlBody .= vsprintf($this->listItem, [$icon, $htmlText]);
486        if ($plainText !== false) {
487            $this->plainBody .= '  * ' . $plainText;
488            if ($plainMetaInfo !== false) {
489                $this->plainBody .= ' (' . $plainMetaInfo . ')';
490            }
491            $this->plainBody .= PHP_EOL;
492        }
493    }
494
495    protected function ensureBodyListOpened() {
496        if ($this->bodyListOpened) {
497            return;
498        }
499
500        $this->ensureBodyIsOpened();
501        $this->bodyListOpened = true;
502        $this->htmlBody .= $this->listBegin;
503    }
504
505    protected function ensureBodyListClosed() {
506        if (!$this->bodyListOpened) {
507            return;
508        }
509
510        $this->bodyListOpened = false;
511        $this->htmlBody .= $this->listEnd;
512    }
513
514    /**
515     * Adds a button group of two buttons to the body of the email
516     *
517     * @param string $textLeft Text of left button; Note: When $plainTextLeft falls back to this, HTML is automatically escaped in the HTML email
518     * @param string $urlLeft URL of left button
519     * @param string $textRight Text of right button; Note: When $plainTextRight falls back to this, HTML is automatically escaped in the HTML email
520     * @param string $urlRight URL of right button
521     * @param string $plainTextLeft Text of left button that is used in the plain text version - if unset the $textLeft is used
522     * @param string $plainTextRight Text of right button that is used in the plain text version - if unset the $textRight is used
523     */
524    public function addBodyButtonGroup(string $textLeft,
525                                       string $urlLeft,
526                                       string $textRight,
527                                       string $urlRight,
528                                       string $plainTextLeft = '',
529                                       string $plainTextRight = '') {
530        if ($this->footerAdded) {
531            return;
532        }
533        if ($plainTextLeft === '') {
534            $plainTextLeft = $textLeft;
535            $textLeft = htmlspecialchars($textLeft);
536        }
537
538        if ($plainTextRight === '') {
539            $plainTextRight = $textRight;
540            $textRight = htmlspecialchars($textRight);
541        }
542
543        $this->ensureBodyIsOpened();
544        $this->ensureBodyListClosed();
545
546        $color = $this->themingDefaults->getColorPrimary();
547        $textColor = $this->themingDefaults->getTextColorPrimary();
548
549        $this->htmlBody .= vsprintf($this->buttonGroup, [$color, $color, $urlLeft, $color, $textColor, $textColor, $textLeft, $urlRight, $textRight]);
550        $this->plainBody .= $plainTextLeft . ': ' . $urlLeft . PHP_EOL;
551        $this->plainBody .= $plainTextRight . ': ' . $urlRight . PHP_EOL . PHP_EOL;
552
553    }
554
555    /**
556     * Adds a button to the body of the email
557     *
558     * @param string $text Text of button; Note: When $plainText falls back to this, HTML is automatically escaped in the HTML email
559     * @param string $url URL of button
560     * @param string $plainText Text of button in plain text version
561     * 		if empty the $text is used, if false none will be used
562     *
563     * @since 12.0.0
564     */
565    public function addBodyButton(string $text, string $url, $plainText = '') {
566        if ($this->footerAdded) {
567            return;
568        }
569
570        $this->ensureBodyIsOpened();
571        $this->ensureBodyListClosed();
572
573        if ($plainText === '') {
574            $plainText = $text;
575            $text = htmlspecialchars($text);
576        }
577
578        $color = $this->themingDefaults->getColorPrimary();
579        $textColor = $this->themingDefaults->getTextColorPrimary();
580        $this->htmlBody .= vsprintf($this->button, [$color, $color, $url, $color, $textColor, $textColor, $text]);
581
582        if ($plainText !== false) {
583            $this->plainBody .= $plainText . ': ';
584        }
585
586        $this->plainBody .=  $url . PHP_EOL;
587
588    }
589
590    /**
591     * Close the HTML body when it is open
592     */
593    protected function ensureBodyIsClosed() {
594        if (!$this->bodyOpened) {
595            return;
596        }
597
598        $this->ensureBodyListClosed();
599
600        $this->htmlBody .= $this->bodyEnd;
601        $this->bodyOpened = false;
602    }
603
604    /**
605     * Adds a logo and a text to the footer. <br> in the text will be replaced by new lines in the plain text email
606     *
607     * @param string $text If the text is empty the default "Name - Slogan<br>This is an automatically sent email" will be used
608     * @param string|null $lang
609     */
610    public function addFooter(string $text = '',?string $lang = null) {
611        if($text === '') {
612            $text = $this->themingDefaults->getName() . ' - ' . $this->themingDefaults->getSlogan() . '<br>' . $this->l10n->t('This is an automatically sent email, please do not reply.');
613        }
614
615        if ($this->footerAdded) {
616            return;
617        }
618        $this->footerAdded = true;
619
620        $this->ensureBodyIsClosed();
621
622        $this->htmlBody .= vsprintf($this->footer, [$text]);
623        $this->htmlBody .= $this->tail;
624        $this->plainBody .= PHP_EOL . '-- ' . PHP_EOL;
625        $this->plainBody .= str_replace('<br>', PHP_EOL, $text);
626    }
627
628    /**
629     * Returns the rendered email subject as string
630     *
631     * @return string
632     */
633    public function renderSubject(): string {
634        return $this->subject;
635    }
636
637    /**
638     * Returns the rendered HTML email as string
639     *
640     * @return string
641     */
642    public function renderHtml(): string {
643        if (!$this->footerAdded) {
644            $this->footerAdded = true;
645            $this->ensureBodyIsClosed();
646            $this->htmlBody .= $this->tail;
647        }
648        return $this->htmlBody;
649    }
650
651    /**
652     * Returns the rendered plain text email as string
653     *
654     * @return string
655     */
656    public function renderText(): string {
657        if (!$this->footerAdded) {
658            $this->footerAdded = true;
659            $this->ensureBodyIsClosed();
660            $this->htmlBody .= $this->tail;
661        }
662        return $this->plainBody;
663    }
664}
665