cutelyst  4.4.0
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->server->host();
84 }
85 
87 {
88  Q_D(ViewEmail);
89  d->server->setHost(host);
90 }
91 
93 {
94  Q_D(const ViewEmail);
95  return d->server->port();
96 }
97 
99 {
100  Q_D(ViewEmail);
101  d->server->setPort(quint16(port));
102 }
103 
105 {
106  Q_D(const ViewEmail);
107  return static_cast<ViewEmail::ConnectionType>(d->server->connectionType());
108 }
109 
111 {
112  Q_D(ViewEmail);
113  d->server->setConnectionType(static_cast<Server::ConnectionType>(ct));
114 }
115 
117 {
118  Q_D(const ViewEmail);
119  return static_cast<ViewEmail::AuthMethod>(d->server->authMethod());
120 }
121 
123 {
124  Q_D(ViewEmail);
125  d->server->setAuthMethod(static_cast<Server::AuthMethod>(method));
126 }
127 
129 {
130  Q_D(const ViewEmail);
131  return d->server->username();
132 }
133 
135 {
136  Q_D(ViewEmail);
137  d->server->setUsername(user);
138 }
139 
141 {
142  Q_D(const ViewEmail);
143  return d->server->password();
144 }
145 
147 {
148  Q_D(ViewEmail);
149  d->server->setPassword(password);
150 }
151 
153 {
154  Q_D(const ViewEmail);
155  QByteArray ret;
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 ret;
161  }
162 
163  MimeMessage message;
164 
165  QVariant value;
166  value = email.value(QStringLiteral("to"));
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(QStringLiteral("cc"));
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(QStringLiteral("bcc"));
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(QStringLiteral("from")).toString()});
197  message.setSubject(email.value(QStringLiteral("subject")).toString());
198 
199  QVariant body = email.value(QStringLiteral("body"));
200  QVariant parts = email.value(QStringLiteral("parts"));
201  if (body.isNull() && parts.isNull()) {
202  c->appendError(QStringLiteral("Can't send email without parts or body, check stash"));
203  return ret;
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(QStringLiteral("content_type"));
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 ret;
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(QStringLiteral("VIEW_EMAIL")).toHash();
254  }
255 
256  d->stashKey = config.value(QStringLiteral("stash_key"), QStringLiteral("email")).toString();
257 
258  if (!config.value(QStringLiteral("sender_host")).isNull()) {
259  d->server->setHost(config.value(QStringLiteral("sender_host")).toString());
260  }
261  if (!config.value(QStringLiteral("sender_port")).isNull()) {
262  d->server->setPort(quint16(config.value(QStringLiteral("sender_port")).toInt()));
263  }
264  if (!config.value(QStringLiteral("sender_username")).isNull()) {
265  d->server->setUsername(config.value(QStringLiteral("sender_username")).toString());
266  }
267  if (!config.value(QStringLiteral("sender_password")).isNull()) {
268  d->server->setPassword(config.value(QStringLiteral("sender_password")).toString());
269  }
270 }
271 
272 void ViewEmailPrivate::setupAttributes(std::shared_ptr<MimePart> part,
273  const QVariantHash &attrs) const
274 {
275  auto contentTypeIt = attrs.constFind(QStringLiteral("content_type"));
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(QStringLiteral("charset"));
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(QStringLiteral("encoding"));
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"
The Cutelyst Context.
Definition: context.h:42
void stash(const QVariantHash &unite)
Definition: context.cpp:562
void appendError(const QString &error)
Definition: context.cpp:56
Implements a web server.
Definition: server.h:60
A view that sends stash data via e-mail.
Definition: viewemail.h:24
QString senderUser() const
Definition: viewemail.cpp:128
void setSenderConnectionType(ConnectionType ct)
Definition: viewemail.cpp:110
QByteArray defaultEncoding
Definition: viewemail.h:46
int senderPort() const
Definition: viewemail.cpp:92
QString senderPassword() const
Definition: viewemail.cpp:140
void setSenderUser(const QString &user)
Definition: viewemail.cpp:134
QByteArray defaultContentType
Definition: viewemail.h:36
QByteArray defaultCharset
Definition: viewemail.h:41
void setSenderHost(const QString &host)
Definition: viewemail.cpp:86
ConnectionType senderConnectionType() const
Definition: viewemail.cpp:104
QString senderHost() const
Definition: viewemail.cpp:80
void setStashKey(const QString &stashKey)
Definition: viewemail.cpp:34
void setDefaultContentType(const QByteArray &contentType)
Definition: viewemail.cpp:47
void setSenderPort(int port)
Definition: viewemail.cpp:98
void setSenderAuthMethod(AuthMethod method)
Definition: viewemail.cpp:122
void setDefaultCharset(const QByteArray &charset)
Definition: viewemail.cpp:60
void setDefaultEncoding(const QByteArray &encoding)
Definition: viewemail.cpp:73
AuthMethod senderAuthMethod() const
Definition: viewemail.cpp:116
ViewEmail(QObject *parent, const QString &name=QString())
Definition: viewemail.cpp:22
void setSenderPassword(const QString &password)
Definition: viewemail.cpp:146
QByteArray render(Context *c) const override
Definition: viewemail.cpp:152
Abstract View component for Cutelyst.
Definition: view.h:25
The Cutelyst namespace holds all public Cutelyst API.
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
bool isNull() const const
QList< QVariant > toList() const const
QString toString() const const
T value() const const