MailTransport

transport.cpp
1 /*
2  SPDX-FileCopyrightText: 2006-2007 Volker Krause <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "transport.h"
8 #include "transport_p.h"
9 #include "mailtransport_defs.h"
10 #include "transportmanager.h"
11 #include "transporttype_p.h"
12 
13 
14 #include <KConfigGroup>
15 #include "mailtransport_debug.h"
16 #include <KLocalizedString>
17 #include <KMessageBox>
18 #include <KStringHandler>
19 #include <KWallet/KWallet>
20 #include <qt5keychain/keychain.h>
21 using namespace QKeychain;
22 using namespace MailTransport;
23 using namespace KWallet;
24 
25 Transport::Transport(const QString &cfgGroup)
26  : TransportBase(cfgGroup)
27  , d(new TransportPrivate)
28 {
29  qCDebug(MAILTRANSPORT_LOG) << cfgGroup;
30  d->passwordLoaded = false;
31  d->passwordDirty = false;
32  d->storePasswordInFile = false;
33  d->needsWalletMigration = false;
34  load();
35  loadPassword();
36 }
37 
39 {
40  delete d;
41 }
42 
43 bool Transport::isValid() const
44 {
45  return (id() > 0) && !host().isEmpty() && port() <= 65536;
46 }
47 
48 void Transport::loadPassword()
49 {
50  if (!d->passwordLoaded && requiresAuthentication() && storePassword()
51  && d->password.isEmpty()) {
52  readPassword();
53  }
54 }
55 
57 {
58  return d->password;
59 }
60 
61 void Transport::setPassword(const QString &passwd)
62 {
63  d->passwordLoaded = true;
64  if (d->password == passwd) {
65  return;
66  }
67  d->passwordDirty = true;
68  d->password = passwd;
69 }
70 
72 {
73  QStringList existingNames;
74  const auto lstTransports = TransportManager::self()->transports();
75  for (Transport *t : lstTransports) {
76  if (t->id() != id()) {
77  existingNames << t->name();
78  }
79  }
80  int suffix = 1;
81  QString origName = name();
82  while (existingNames.contains(name())) {
83  setName(i18nc("%1: name; %2: number appended to it to make "
84  "it unique among a list of names", "%1 #%2", origName, suffix));
85  ++suffix;
86  }
87 }
88 
90 {
91  Transport *original = TransportManager::self()->transportById(id(), false);
92  if (original == this) {
93  qCWarning(MAILTRANSPORT_LOG) << "Tried to update password state of non-cloned transport.";
94  return;
95  }
96  if (original) {
97  d->password = original->d->password;
98  d->passwordLoaded = original->d->passwordLoaded;
99  d->passwordDirty = original->d->passwordDirty;
100  } else {
101  qCWarning(MAILTRANSPORT_LOG) << "Transport with this ID not managed by transport manager.";
102  }
103 }
104 
106 {
107  return !requiresAuthentication() || !storePassword() || d->passwordLoaded;
108 }
109 
111 {
112  return Transport::authenticationTypeString(authenticationType());
113 }
114 
116 {
117  switch (type) {
118  case EnumAuthenticationType::LOGIN:
119  return QStringLiteral("LOGIN");
120  case EnumAuthenticationType::PLAIN:
121  return QStringLiteral("PLAIN");
122  case EnumAuthenticationType::CRAM_MD5:
123  return QStringLiteral("CRAM-MD5");
124  case EnumAuthenticationType::DIGEST_MD5:
125  return QStringLiteral("DIGEST-MD5");
126  case EnumAuthenticationType::NTLM:
127  return QStringLiteral("NTLM");
128  case EnumAuthenticationType::GSSAPI:
129  return QStringLiteral("GSSAPI");
130  case EnumAuthenticationType::CLEAR:
131  return i18nc("Authentication method", "Clear text");
132  case EnumAuthenticationType::APOP:
133  return QStringLiteral("APOP");
134  case EnumAuthenticationType::ANONYMOUS:
135  return i18nc("Authentication method", "Anonymous");
136  case EnumAuthenticationType::XOAUTH2:
137  return QStringLiteral("XOAUTH2");
138  }
139  Q_ASSERT(false);
140  return QString();
141 }
142 
143 void Transport::usrRead()
144 {
145  TransportBase::usrRead();
146 
147  setHost(host().trimmed());
148 
149  if (d->oldName.isEmpty()) {
150  d->oldName = name();
151  }
152 
153  // Set TransportType.
154  {
155  d->transportType = TransportType();
156  d->transportType.d->mIdentifier = identifier();
157  //qCDebug(MAILTRANSPORT_LOG) << "type" << identifier();
158  // Now we have the type and possibly agentType. Get the name, description
159  // etc. from TransportManager.
161  int index = types.indexOf(d->transportType);
162  if (index != -1) {
163  d->transportType = types[ index ];
164  } else {
165  qCWarning(MAILTRANSPORT_LOG) << "Type unknown to manager.";
166  d->transportType.d->mName = i18nc("An unknown transport type", "Unknown");
167  }
168  }
169 
170  // we have everything we need
171  if (!storePassword()) {
172  return;
173  }
174 
175  if (d->passwordLoaded) {
176  return;
177  }
178 
179  // try to find a password in the config file otherwise
180  KConfigGroup group(config(), currentGroup());
181  if (group.hasKey("password")) {
182  d->password = KStringHandler::obscure(group.readEntry("password"));
183  }
184 
185  if (!d->password.isEmpty()) {
186  d->passwordLoaded = true;
187  if (Wallet::isEnabled()) {
188  d->needsWalletMigration = true;
189  } else {
190  d->storePasswordInFile = true;
191  }
192  }
193 }
194 
195 bool Transport::usrSave()
196 {
197  if (requiresAuthentication() && storePassword() && d->passwordDirty) {
198  const QString storePassword = d->password;
199  Wallet *wallet = TransportManager::self()->wallet();
200  if (!wallet || wallet->writePassword(QString::number(id()), d->password) != 0) {
201  // wallet saving failed, ask if we should store in the config file instead
202  if (d->storePasswordInFile || KMessageBox::warningYesNo(
203  nullptr,
204  i18n("KWallet is not available. It is strongly recommended to use "
205  "KWallet for managing your passwords.\n"
206  "However, the password can be stored in the configuration "
207  "file instead. The password is stored in an obfuscated format, "
208  "but should not be considered secure from decryption efforts "
209  "if access to the configuration file is obtained.\n"
210  "Do you want to store the password for server '%1' in the "
211  "configuration file?", name()),
212  i18n("KWallet Not Available"),
213  KGuiItem(i18n("Store Password")),
214  KGuiItem(i18n("Do Not Store Password"))) == KMessageBox::Yes) {
215  // write to config file
216  KConfigGroup group(config(), currentGroup());
217  group.writeEntry("password", KStringHandler::obscure(storePassword));
218  d->storePasswordInFile = true;
219  }
220  }
221  d->passwordDirty = false;
222  }
223 
224  if (!TransportBase::usrSave()) {
225  return false;
226  }
227  TransportManager::self()->emitChangesCommitted();
228  if (name() != d->oldName) {
229  Q_EMIT TransportManager::self()->transportRenamed(id(), d->oldName, name());
230  d->oldName = name();
231  }
232 
233  return true;
234 }
235 
236 void Transport::readPassword()
237 {
238  // no need to load a password if the account doesn't require auth
239  if (!requiresAuthentication()) {
240  return;
241  }
242  d->passwordLoaded = true;
243 
244  auto readJob = new ReadPasswordJob(WALLET_FOLDER, this);
245  connect(readJob, &Job::finished, this, &Transport::readTransportPasswordFinished);
246  readJob->setKey(QString::number(id()));
247  readJob->start();
248 }
249 
250 void Transport::readTransportPasswordFinished(QKeychain::Job *baseJob)
251 {
252  auto *job = qobject_cast<ReadPasswordJob *>(baseJob);
253  Q_ASSERT(job);
254  if (job->error()) {
255  d->password.clear();
256  d->passwordLoaded = false;
257  qWarning() << "We have an error during reading password " << job->errorString();
258  } else {
259  setPassword(job->textData());
260  }
261 
262 }
263 
265 {
266  return d->needsWalletMigration;
267 }
268 
270 {
271  qCDebug(MAILTRANSPORT_LOG) << "migrating" << id() << "to wallet";
272  d->needsWalletMigration = false;
273  KConfigGroup group(config(), currentGroup());
274  group.deleteEntry("password");
275  d->passwordDirty = true;
276  d->storePasswordInFile = false;
277  save();
278 }
279 
281 {
282  const QString id = currentGroup().mid(10);
283  return new Transport(id);
284 }
285 
287 {
288  if (!d->transportType.isValid()) {
289  qCWarning(MAILTRANSPORT_LOG) << "Invalid transport type.";
290  }
291  return d->transportType;
292 }
A representation of a transport type.
Definition: transporttype.h:29
void migrateToWallet()
Try to migrate the password from the config file to the wallet.
Definition: transport.cpp:269
bool isComplete() const
Returns true if all settings have been loaded.
Definition: transport.cpp:105
int indexOf(const T &value, int from) const const
static TransportManager * self()
Returns the TransportManager instance.
void setPassword(const QString &passwd)
Sets the password of this transport.
Definition: transport.cpp:61
KWallet::Wallet * wallet()
Returns a pointer to an open wallet if available, 0 otherwise.
QString password()
Returns the password of this transport.
Definition: transport.cpp:56
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
virtual int writePassword(const QString &key, const QString &value)
void deleteEntry(const QString &pKey, WriteConfigFlags pFlags=Normal)
QString number(int n, int base)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString authenticationTypeString() const
Returns a string representation of the authentication type.
Definition: transport.cpp:110
bool needsWalletMigration() const
Returns true if the password was not stored in the wallet.
Definition: transport.cpp:264
bool isValid() const
Returns true if this transport is valid, ie.
Definition: transport.cpp:43
bool hasKey(const QString &key) const
QList< Transport * > transports() const
Returns a list of all available transports.
QString i18n(const char *text, const TYPE &arg...)
QString mid(int position, int n) const const
void transportRenamed(int id, const QString &oldName, const QString &newName)
Emitted when a transport has been renamed.
Transport * clone() const
Returns a deep copy of this Transport object which will no longer be automatically updated...
Definition: transport.cpp:280
void forceUniqueName()
Makes sure the transport has a unique name.
Definition: transport.cpp:71
Internal file containing constant definitions etc.
void updatePasswordState()
This function synchronizes the password of this transport with the password of the transport with the...
Definition: transport.cpp:89
Transport(const QString &cfgGroup)
Creates a Transport object.
Definition: transport.cpp:25
Represents the settings of a specific mail transport.
Definition: transport.h:29
Transport * transportById(int id, bool def=true) const
Returns the Transport object with the given id.
KCOREADDONS_EXPORT QString obscure(const QString &str)
T readEntry(const QString &key, const T &aDefault) const
TransportType::List types() const
Returns a list of all available transport types.
ButtonCode warningYesNo(QWidget *parent, const QString &text, const QString &caption=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous))
TransportType transportType() const
Returns the type of this transport.
Definition: transport.cpp:286
~Transport() override
Destructor.
Definition: transport.cpp:38
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Jan 16 2021 23:21:36 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.