cutelyst  5.0.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 using namespace Qt::StringLiterals;
22 
23 ViewEmail::ViewEmail(QObject *parent, const QString &name)
24  : View(new ViewEmailPrivate, parent, name)
25 {
26  initSender();
27 }
28 
30 {
31  Q_D(const ViewEmail);
32  return d->stashKey;
33 }
34 
35 void ViewEmail::setStashKey(const QString &stashKey)
36 {
37  Q_D(ViewEmail);
38  d->stashKey = stashKey;
39  Q_EMIT changed();
40 }
41 
43 {
44  Q_D(const ViewEmail);
45  return d->defaultContentType;
46 }
47 
49 {
50  Q_D(ViewEmail);
51  d->defaultContentType = contentType;
52  Q_EMIT changed();
53 }
54 
56 {
57  Q_D(const ViewEmail);
58  return d->defaultCharset;
59 }
60 
62 {
63  Q_D(ViewEmail);
64  d->defaultCharset = charset;
65  Q_EMIT changed();
66 }
67 
69 {
70  Q_D(const ViewEmail);
71  return d->defaultEncoding;
72 }
73 
75 {
76  Q_D(ViewEmail);
77  d->defaultEncoding = encoding;
78  Q_EMIT changed();
79 }
80 
82 {
83  Q_D(const ViewEmail);
84  return d->server->host();
85 }
86 
88 {
89  Q_D(ViewEmail);
90  d->server->setHost(host);
91 }
92 
94 {
95  Q_D(const ViewEmail);
96  return d->server->port();
97 }
98 
100 {
101  Q_D(ViewEmail);
102  d->server->setPort(quint16(port));
103 }
104 
106 {
107  Q_D(const ViewEmail);
108  return static_cast<ViewEmail::ConnectionType>(d->server->connectionType());
109 }
110 
112 {
113  Q_D(ViewEmail);
114  d->server->setConnectionType(static_cast<Server::ConnectionType>(ct));
115 }
116 
118 {
119  Q_D(const ViewEmail);
120  return static_cast<ViewEmail::AuthMethod>(d->server->authMethod());
121 }
122 
124 {
125  Q_D(ViewEmail);
126  d->server->setAuthMethod(static_cast<Server::AuthMethod>(method));
127 }
128 
130 {
131  Q_D(const ViewEmail);
132  return d->server->username();
133 }
134 
136 {
137  Q_D(ViewEmail);
138  d->server->setUsername(user);
139 }
140 
142 {
143  Q_D(const ViewEmail);
144  return d->server->password();
145 }
146 
148 {
149  Q_D(ViewEmail);
150  d->server->setPassword(password);
151 }
152 
154 {
155  Q_D(const ViewEmail);
156  QVariantHash email = c->stash(d->stashKey).toHash();
157  if (email.isEmpty()) {
158  c->appendError(QStringLiteral(
159  "Cannot render template, template name or template stash key not defined"));
160  return {};
161  }
162 
163  MimeMessage message;
164 
165  QVariant value;
166  value = email.value(u"to"_s);
167  if (value.typeId() == QMetaType::QString && !value.toString().isEmpty()) {
168  message.addTo(SimpleMail::EmailAddress{value.toString()});
169  } else if (value.typeId() == QMetaType::QStringList) {
170  const auto rcpts = value.toStringList();
171  for (const QString &rcpt : rcpts) {
172  message.addTo(SimpleMail::EmailAddress{rcpt});
173  }
174  }
175 
176  value = email.value(u"cc"_s);
177  if (value.typeId() == QMetaType::QString && !value.toString().isEmpty()) {
178  message.addCc(SimpleMail::EmailAddress{value.toString()});
179  } else if (value.typeId() == QMetaType::QStringList) {
180  const auto rcpts = value.toStringList();
181  for (const QString &rcpt : rcpts) {
182  message.addCc(SimpleMail::EmailAddress{rcpt});
183  }
184  }
185 
186  value = email.value(u"bcc"_s);
187  if (value.typeId() == QMetaType::QString && !value.toString().isEmpty()) {
188  message.addBcc(SimpleMail::EmailAddress{value.toString()});
189  } else if (value.typeId() == QMetaType::QStringList) {
190  const auto rcpts = value.toStringList();
191  for (const QString &rcpt : rcpts) {
192  message.addBcc(SimpleMail::EmailAddress{rcpt});
193  }
194  }
195 
196  message.setSender(SimpleMail::EmailAddress{email.value(u"from"_s).toString()});
197  message.setSubject(email.value(u"subject"_s).toString());
198 
199  QVariant body = email.value(u"body"_s);
200  QVariant parts = email.value(u"parts"_s);
201  if (body.isNull() && parts.isNull()) {
202  c->appendError(u"Can't send email without parts or body, check stash"_s);
203  return {};
204  }
205 
206  if (!parts.isNull()) {
207  const QVariantList partsVariant = parts.toList();
208  for (const QVariant &part : partsVariant) {
209  auto mime = part.value<std::shared_ptr<MimePart>>();
210  if (mime) {
211  message.addPart(mime);
212  } else {
213  qCCritical(CUTELYST_VIEW_EMAIL) << "Failed to cast MimePart";
214  }
215  }
216 
217  auto contentTypeIt = email.constFind(u"content_type"_s);
218  if (contentTypeIt != email.constEnd() && !contentTypeIt.value().isNull() &&
219  !contentTypeIt.value().toString().isEmpty()) {
220  const QByteArray contentType = contentTypeIt.value().toString().toLatin1();
221  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified content_type" << contentType;
222  message.getContent().setContentType(contentType);
223  } else if (!d->defaultContentType.isEmpty()) {
224  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default content_type" << d->defaultContentType;
225  message.getContent().setContentType(d->defaultContentType);
226  }
227  } else {
228  auto part = std::make_shared<MimeText>(body.toString());
229  d->setupAttributes(part, email);
230  message.setContent(part);
231  }
232 
233  ServerReply *reply = d->server->sendMail(message);
234  connect(reply, &ServerReply::finished, reply, &ServerReply::deleteLater);
235 
236  return {};
237 }
238 
239 ViewEmail::ViewEmail(ViewEmailPrivate *d, QObject *parent, const QString &name)
240  : View(d, parent, name)
241 {
242  initSender();
243 }
244 
245 void ViewEmail::initSender()
246 {
247  Q_D(ViewEmail);
248  d->server = new Server(this);
249 
250  QVariantHash config;
251  const auto app = qobject_cast<Application *>(parent());
252  if (app) {
253  config = app->config(u"VIEW_EMAIL"_s).toHash();
254  }
255 
256  d->stashKey = config.value(u"stash_key"_s, u"email"_s).toString();
257 
258  if (!config.value(u"sender_host"_s).isNull()) {
259  d->server->setHost(config.value(u"sender_host"_s).toString());
260  }
261  if (!config.value(u"sender_port"_s).isNull()) {
262  d->server->setPort(quint16(config.value(u"sender_port"_s).toInt()));
263  }
264  if (!config.value(u"sender_username"_s).isNull()) {
265  d->server->setUsername(config.value(u"sender_username"_s).toString());
266  }
267  if (!config.value(u"sender_password"_s).isNull()) {
268  d->server->setPassword(config.value(u"sender_password"_s).toString());
269  }
270 }
271 
272 void ViewEmailPrivate::setupAttributes(std::shared_ptr<MimePart> part,
273  const QVariantHash &attrs) const
274 {
275  auto contentTypeIt = attrs.constFind(u"content_type"_s);
276  if (contentTypeIt != attrs.constEnd() && !contentTypeIt.value().isNull() &&
277  !contentTypeIt.value().toString().isEmpty()) {
278  const QByteArray contentType = contentTypeIt.value().toString().toLatin1();
279  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified content_type" << contentType;
280  part->setContentType(contentType);
281  } else if (!defaultContentType.isEmpty()) {
282  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default content_type" << defaultContentType;
283  part->setContentType(defaultContentType);
284  }
285 
286  auto charsetIt = attrs.constFind(u"charset"_s);
287  if (charsetIt != attrs.constEnd() && !charsetIt.value().isNull() &&
288  !charsetIt.value().toString().isEmpty()) {
289  const QByteArray charset = charsetIt.value().toString().toLatin1();
290  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified charset" << charset;
291  part->setCharset(charset);
292  } else if (!defaultCharset.isEmpty()) {
293  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default charset" << defaultCharset;
294  part->setCharset(defaultCharset);
295  }
296 
297  auto encodingIt = attrs.constFind(u"encoding"_s);
298  if (encodingIt != attrs.constEnd() && !encodingIt.value().isNull() &&
299  !encodingIt.value().toString().isEmpty()) {
300  const QByteArray encoding = encodingIt.value().toString().toLatin1();
301  qCDebug(CUTELYST_VIEW_EMAIL) << "Using specified encoding" << encoding;
302  setupEncoding(part, encoding);
303  } else if (!defaultEncoding.isEmpty()) {
304  qCDebug(CUTELYST_VIEW_EMAIL) << "Using default charset" << defaultEncoding;
305  setupEncoding(part, defaultEncoding);
306  }
307 }
308 
309 void ViewEmailPrivate::setupEncoding(std::shared_ptr<MimePart> part,
310  const QByteArray &encoding) const
311 {
312  if (encoding == "7bit") {
313  part->setEncoding(MimePart::_7Bit);
314  } else if (encoding == "8bit") {
315  part->setEncoding(MimePart::_8Bit);
316  } else if (encoding == "base64") {
317  part->setEncoding(MimePart::Base64);
318  } else if (encoding == "quoted-printable") {
319  part->setEncoding(MimePart::QuotedPrintable);
320  } else {
321  qCCritical(CUTELYST_VIEW_EMAIL) << "Unknown encoding" << encoding;
322  }
323 }
324 
325 #include "moc_viewemail.cpp"
QHash< QString, QVariant > toHash() const const
void setDefaultEncoding(const QByteArray &encoding)
Definition: viewemail.cpp:74
void setSenderUser(const QString &user)
Definition: viewemail.cpp:135
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QList< QVariant > toList() const const
void setSenderPassword(const QString &password)
Definition: viewemail.cpp:147
T value() const const
Implements a web server.
Definition: server.h:59
int senderPort() const
Definition: viewemail.cpp:93
void setSenderHost(const QString &host)
Definition: viewemail.cpp:87
void appendError(const QString &error)
Definition: context.cpp:57
The Cutelyst Context.
Definition: context.h:42
QByteArray render(Context *c) const override
Definition: viewemail.cpp:153
QByteArray defaultCharset() const
bool isNull() const const
void stash(const QVariantHash &unite)
Definition: context.cpp:562
QByteArray defaultContentType() const
bool isEmpty() const const
AuthMethod senderAuthMethod() const
Definition: viewemail.cpp:117
ConnectionType senderConnectionType() const
Definition: viewemail.cpp:105
The Cutelyst namespace holds all public Cutelyst API.
int typeId() const const
void setSenderPort(int port)
Definition: viewemail.cpp:99
QByteArray defaultEncoding() const
QStringList toStringList() const const
A view that sends stash data via e-mail.
Definition: viewemail.h:24
QString senderPassword() const
Definition: viewemail.cpp:141
void setDefaultCharset(const QByteArray &charset)
Definition: viewemail.cpp:61
void setSenderAuthMethod(AuthMethod method)
Definition: viewemail.cpp:123
Abstract View component for Cutelyst.
Definition: view.h:24
QString stashKey() const
QVariant config(const QString &key, const QVariant &defaultValue={}) const
The Cutelyst application.
Definition: application.h:72
ViewEmail(QObject *parent, const QString &name={})
Definition: viewemail.cpp:23
void setStashKey(const QString &stashKey)
Definition: viewemail.cpp:35
QString senderHost() const
Definition: viewemail.cpp:81
T qobject_cast(QObject *object)
QObject * parent() const const
QString toString() const const
void setDefaultContentType(const QByteArray &contentType)
Definition: viewemail.cpp:48
Q_EMITQ_EMIT
void setSenderConnectionType(ConnectionType ct)
Definition: viewemail.cpp:111
QString senderUser() const
Definition: viewemail.cpp:129