cutelyst  3.9.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
viewemail.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2015-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "viewemail_p.h"
6 
7 #include <Cutelyst/application.h>
8 #include <Cutelyst/context.h>
9 #include <Cutelyst/response.h>
10 #include <SimpleMail/emailaddress.h>
11 #include <SimpleMail/mimemessage.h>
12 #include <SimpleMail/mimetext.h>
13 #include <SimpleMail/serverreply.h>
14 
15 #include <QtCore/QLoggingCategory>
16 
17 Q_LOGGING_CATEGORY(CUTELYST_VIEW_EMAIL, "cutelyst.view.email", QtWarningMsg)
18 
19 using namespace Cutelyst;
20 using namespace SimpleMail;
21 
22 ViewEmail::ViewEmail(QObject *parent, const QString &name)
23  : View(new ViewEmailPrivate, parent, name)
24 {
25  initSender();
26 }
27 
29 {
30  Q_D(const ViewEmail);
31  return d->stashKey;
32 }
33 
34 void ViewEmail::setStashKey(const QString &stashKey)
35 {
36  Q_D(ViewEmail);
37  d->stashKey = stashKey;
38  Q_EMIT changed();
39 }
40 
42 {
43  Q_D(const ViewEmail);
44  return d->defaultContentType;
45 }
46 
48 {
49  Q_D(ViewEmail);
50  d->defaultContentType = contentType;
51  Q_EMIT changed();
52 }
53 
55 {
56  Q_D(const ViewEmail);
57  return d->defaultCharset;
58 }
59 
61 {
62  Q_D(ViewEmail);
63  d->defaultCharset = charset;
64  Q_EMIT changed();
65 }
66 
68 {
69  Q_D(const ViewEmail);
70  return d->defaultEncoding;
71 }
72 
74 {
75  Q_D(ViewEmail);
76  d->defaultEncoding = encoding;
77  Q_EMIT changed();
78 }
79 
81 {
82  Q_D(const ViewEmail);
83  return d->sender->host();
84 }
85 
87 {
88  Q_D(ViewEmail);
89  d->sender->setHost(host);
90  if (d->server) {
91  d->server->setHost(host);
92  }
93 }
94 
96 {
97  Q_D(const ViewEmail);
98  return d->sender->port();
99 }
100 
102 {
103  Q_D(ViewEmail);
104  d->sender->setPort(quint16(port));
105  if (d->server) {
106  d->server->setPort(quint16(port));
107  }
108 }
109 
111 {
112  Q_D(const ViewEmail);
113  return static_cast<ViewEmail::ConnectionType>(d->sender->connectionType());
114 }
115 
117 {
118  Q_D(ViewEmail);
119  d->sender->setConnectionType(static_cast<Sender::ConnectionType>(ct));
120  if (d->server) {
121  d->server->setConnectionType(static_cast<Server::ConnectionType>(ct));
122  }
123 }
124 
126 {
127  Q_D(const ViewEmail);
128  return static_cast<ViewEmail::AuthMethod>(d->sender->authMethod());
129 }
130 
132 {
133  Q_D(ViewEmail);
134  d->sender->setAuthMethod(static_cast<Sender::AuthMethod>(method));
135  if (d->server) {
136  d->server->setAuthMethod(static_cast<Server::AuthMethod>(method));
137  }
138 }
139 
141 {
142  Q_D(const ViewEmail);
143  return d->sender->user();
144 }
145 
147 {
148  Q_D(ViewEmail);
149  d->sender->setUser(user);
150  if (d->server) {
151  d->server->setUsername(user);
152  }
153 }
154 
156 {
157  Q_D(const ViewEmail);
158  return d->sender->password();
159 }
160 
162 {
163  Q_D(ViewEmail);
164  d->sender->setPassword(password);
165  if (d->server) {
166  d->server->setPassword(password);
167  }
168 }
169 
170 bool ViewEmail::async() const
171 {
172  Q_D(const ViewEmail);
173  return d->server;
174 }
175 
176 void ViewEmail::setAsync(bool enable)
177 {
178  Q_D(ViewEmail);
179  if (enable) {
180  if (!d->server) {
181  d->server = new Server(this);
182  d->server->setHost(d->sender->host());
183  d->server->setPort(d->sender->port());
184  d->server->setUsername(d->sender->user());
185  d->server->setPassword(d->sender->password());
186  d->server->setAuthMethod(static_cast<Server::AuthMethod>(d->sender->authMethod()));
187  d->server->setConnectionType(
188  static_cast<Server::ConnectionType>(d->sender->connectionType()));
189  }
190  } else {
191  delete d->server;
192  d->server = nullptr;
193  }
194 }
195 
197 {
198  Q_D(const ViewEmail);
199  QByteArray ret;
200  QVariantHash email = c->stash(d->stashKey).toHash();
201  if (email.isEmpty()) {
202  c->error(QStringLiteral(
203  "Cannot render template, template name or template stash key not defined"));
204  return ret;
205  }
206 
207  MimeMessage message;
208 
209  QVariant value;
210  value = email.value(QStringLiteral("to"));
211  if (value.type() == QVariant::String && !value.toString().isEmpty()) {
212  message.addTo(value.toString());
213  } else if (value.type() == QVariant::StringList) {
214  const auto rcpts = value.toStringList();
215  for (const QString &rcpt : rcpts) {
216  message.addTo(rcpt);
217  }
218  }
219 
220  value = email.value(QStringLiteral("cc"));
221  if (value.type() == QVariant::String && !value.toString().isEmpty()) {
222  message.addCc(value.toString());
223  } else if (value.type() == QVariant::StringList) {
224  const auto rcpts = value.toStringList();
225  for (const QString &rcpt : rcpts) {
226  message.addCc(rcpt);
227  }
228  }
229 
230  value = email.value(QStringLiteral("bcc"));
231  if (value.type() == QVariant::String && !value.toString().isEmpty()) {
232  message.addBcc(value.toString());
233  } else if (value.type() == QVariant::StringList) {
234  const auto rcpts = value.toStringList();
235  for (const QString &rcpt : rcpts) {
236  message.addBcc(rcpt);
237  }
238  }
239 
240  message.setSender(email.value(QStringLiteral("from")).toString());
241  message.setSubject(email.value(QStringLiteral("subject")).toString());
242 
243  QVariant body = email.value(QStringLiteral("body"));
244  QVariant parts = email.value(QStringLiteral("parts"));
245  if (body.isNull() && parts.isNull()) {
246  c->error(QStringLiteral("Can't send email without parts or body, check stash"));
247  return ret;
248  }
249 
250  if (!parts.isNull()) {
251  const QVariantList partsVariant = parts.toList();
252  for (const QVariant &part : partsVariant) {
253  auto mime = part.value<MimePart *>();
254  if (mime) {
255  message.addPart(mime);
256  } else {
257  qCCritical(CUTELYST_VIEW_EMAIL) << "Failed to cast MimePart";
258  }
259  }
260 
261  auto contentTypeIt = email.constFind(QStringLiteral("content_type"));
262  if (contentTypeIt != email.constEnd() && !contentTypeIt.value().isNull() &&
263  !contentTypeIt.value().toString().isEmpty()) {
264  const QByteArray contentType = contentTypeIt.value().toString().toLatin1();
265  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified content_type" << contentType;
266  message.getContent().setContentType(contentType);
267  } else if (!d->defaultContentType.isEmpty()) {
268  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default content_type" << d->defaultContentType;
269  message.getContent().setContentType(d->defaultContentType);
270  }
271  } else {
272  auto part = new MimeText(body.toString());
273  d->setupAttributes(part, email);
274  message.setContent(part);
275  }
276 
277  if (d->server) {
278  ServerReply *reply = d->server->sendMail(message);
279  connect(reply, &ServerReply::finished, reply, &ServerReply::deleteLater);
280  } else if (!d->sender->sendMail(message)) {
281  c->error(QString::fromLatin1(d->sender->responseText()));
282  return ret;
283  }
284 
285  return ret;
286 }
287 
288 ViewEmail::ViewEmail(ViewEmailPrivate *d, QObject *parent, const QString &name)
289  : View(d, parent, name)
290 {
291  initSender();
292 }
293 
294 void ViewEmail::initSender()
295 {
296  Q_D(ViewEmail);
297  d->sender = new Sender(this);
298 
299  QVariantHash config;
300  const auto app = qobject_cast<Application *>(parent());
301  if (app) {
302  config = app->config(QStringLiteral("VIEW_EMAIL")).toHash();
303  }
304 
305  d->stashKey = config.value(QStringLiteral("stash_key"), QStringLiteral("email")).toString();
306 
307  if (!config.value(QStringLiteral("sender_host")).isNull()) {
308  d->sender->setHost(config.value(QStringLiteral("sender_host")).toString());
309  }
310  if (!config.value(QStringLiteral("sender_port")).isNull()) {
311  d->sender->setPort(quint16(config.value(QStringLiteral("sender_port")).toInt()));
312  }
313  if (!config.value(QStringLiteral("sender_username")).isNull()) {
314  d->sender->setUser(config.value(QStringLiteral("sender_username")).toString());
315  }
316  if (!config.value(QStringLiteral("sender_password")).isNull()) {
317  d->sender->setPassword(config.value(QStringLiteral("sender_password")).toString());
318  }
319 }
320 
321 void ViewEmailPrivate::setupAttributes(MimePart *part, const QVariantHash &attrs) const
322 {
323  auto contentTypeIt = attrs.constFind(QStringLiteral("content_type"));
324  if (contentTypeIt != attrs.constEnd() && !contentTypeIt.value().isNull() &&
325  !contentTypeIt.value().toString().isEmpty()) {
326  const QByteArray contentType = contentTypeIt.value().toString().toLatin1();
327  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified content_type" << contentType;
328  part->setContentType(contentType);
329  } else if (!defaultContentType.isEmpty()) {
330  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default content_type" << defaultContentType;
331  part->setContentType(defaultContentType);
332  }
333 
334  auto charsetIt = attrs.constFind(QStringLiteral("charset"));
335  if (charsetIt != attrs.constEnd() && !charsetIt.value().isNull() &&
336  !charsetIt.value().toString().isEmpty()) {
337  const QByteArray charset = charsetIt.value().toString().toLatin1();
338  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified charset" << charset;
339  part->setCharset(charset);
340  } else if (!defaultCharset.isEmpty()) {
341  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default charset" << defaultCharset;
342  part->setCharset(defaultCharset);
343  }
344 
345  auto encodingIt = attrs.constFind(QStringLiteral("encoding"));
346  if (encodingIt != attrs.constEnd() && !encodingIt.value().isNull() &&
347  !encodingIt.value().toString().isEmpty()) {
348  const QByteArray encoding = encodingIt.value().toString().toLatin1();
349  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified encoding" << encoding;
350  setupEncoding(part, encoding);
351  } else if (!defaultEncoding.isEmpty()) {
352  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default charset" << defaultEncoding;
353  setupEncoding(part, defaultEncoding);
354  }
355 }
356 
357 void ViewEmailPrivate::setupEncoding(MimePart *part, const QByteArray &encoding) const
358 {
359  if (encoding == "7bit") {
360  part->setEncoding(MimePart::_7Bit);
361  } else if (encoding == "8bit") {
362  part->setEncoding(MimePart::_8Bit);
363  } else if (encoding == "base64") {
364  part->setEncoding(MimePart::Base64);
365  } else if (encoding == "quoted-printable") {
366  part->setEncoding(MimePart::QuotedPrintable);
367  } else {
368  qCCritical(CUTELYST_VIEW_EMAIL) << "Unknown encoding" << encoding;
369  }
370 }
371 
372 #include "moc_viewemail.cpp"
QHash< QString, QVariant > toHash() const const
void setDefaultEncoding(const QByteArray &encoding)
Definition: viewemail.cpp:73
void setSenderUser(const QString &user)
Definition: viewemail.cpp:146
bool error() const noexcept
Returns true if an error was set.
Definition: context.cpp:49
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QList< QVariant > toList() const const
ViewEmail(QObject *parent, const QString &name=QString())
Constructs a new ViewEmail object with the given parent and name.
Definition: viewemail.cpp:22
void setSenderPassword(const QString &password)
Definition: viewemail.cpp:161
T value() const const
int senderPort() const
Definition: viewemail.cpp:95
void setSenderHost(const QString &host)
Definition: viewemail.cpp:86
The Cutelyst Context.
Definition: context.h:38
virtual QByteArray render(Context *c) const override
Definition: viewemail.cpp:196
QByteArray defaultCharset() const
bool isNull() const const
void stash(const QVariantHash &unite)
Definition: context.cpp:566
QByteArray defaultContentType() const
AuthMethod senderAuthMethod() const
Definition: viewemail.cpp:125
ConnectionType senderConnectionType() const
Definition: viewemail.cpp:110
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
void setAsync(bool enable)
Definition: viewemail.cpp:176
bool async() const
void setSenderPort(int port)
Definition: viewemail.cpp:101
QString fromLatin1(QByteArrayView str)
QByteArray defaultEncoding() const
QString senderPassword() const
Definition: viewemail.cpp:155
void setDefaultCharset(const QByteArray &charset)
Definition: viewemail.cpp:60
void setSenderAuthMethod(AuthMethod method)
Definition: viewemail.cpp:131
Cutelyst View abstract view component
Definition: view.h:21
QString stashKey() const
QVariant config(const QString &key, const QVariant &defaultValue={}) const
The Cutelyst Application.
Definition: application.h:42
void setStashKey(const QString &stashKey)
Definition: viewemail.cpp:34
QString senderHost() const
Definition: viewemail.cpp:80
T qobject_cast(QObject *object)
QObject * parent() const const
QString toString() const const
void setDefaultContentType(const QByteArray &contentType)
Definition: viewemail.cpp:47
Q_EMITQ_EMIT
void setSenderConnectionType(ConnectionType ct)
Definition: viewemail.cpp:116
QString senderUser() const
Definition: viewemail.cpp:140