1 /*
2    SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
3 
4    SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "sieveeditorutil.h"
8 #include "sieveeditor_debug.h"
9 #include "sieveeditorsavepasswordjob.h"
10 #include "sieveserversettings.h"
11 
12 #include <KConfig>
13 
14 #include <KConfigGroup>
15 
16 #include <KSharedConfig>
17 #include <QRegularExpression>
18 #include <QUrlQuery>
19 
20 #include <qt5keychain/keychain.h>
21 using namespace QKeychain;
22 
url() const23 QUrl SieveEditorUtil::SieveServerConfig::url() const
24 {
25     QUrl u;
26     u.setHost(sieveSettings.serverName);
27     u.setUserName(sieveSettings.userName);
28     u.setPassword(sieveSettings.password);
29     u.setPort(sieveSettings.port);
30 
31     QString authStr;
32     switch (sieveSettings.authenticationType) {
33     case MailTransport::Transport::EnumAuthenticationType::CLEAR:
34     case MailTransport::Transport::EnumAuthenticationType::PLAIN:
35         authStr = QStringLiteral("PLAIN");
36         break;
37     case MailTransport::Transport::EnumAuthenticationType::LOGIN:
38         authStr = QStringLiteral("LOGIN");
39         break;
40     case MailTransport::Transport::EnumAuthenticationType::CRAM_MD5:
41         authStr = QStringLiteral("CRAM-MD5");
42         break;
43     case MailTransport::Transport::EnumAuthenticationType::DIGEST_MD5:
44         authStr = QStringLiteral("DIGEST-MD5");
45         break;
46     case MailTransport::Transport::EnumAuthenticationType::GSSAPI:
47         authStr = QStringLiteral("GSSAPI");
48         break;
49     case MailTransport::Transport::EnumAuthenticationType::ANONYMOUS:
50         authStr = QStringLiteral("ANONYMOUS");
51         break;
52     default:
53         authStr = QStringLiteral("PLAIN");
54         break;
55     }
56     QUrlQuery query;
57     query.addQueryItem(QStringLiteral("x-mech"), authStr);
58     u.setQuery(query);
59     return u;
60 }
61 
operator ==(const SieveEditorUtil::SieveServerConfig & other) const62 bool SieveEditorUtil::SieveServerConfig::operator==(const SieveEditorUtil::SieveServerConfig &other) const
63 {
64     const bool result = (enabled == other.enabled) && (useImapCustomServer == other.useImapCustomServer) && (sieveSettings == other.sieveSettings)
65         && (sieveImapAccountSettings == other.sieveImapAccountSettings);
66     if (!result) {
67         qCDebug(SIEVEEDITOR_LOG) << "enabled " << enabled << " other.enabled " << other.enabled;
68         qCDebug(SIEVEEDITOR_LOG) << "useImapCustomServer " << useImapCustomServer << " other.useImapCustomServer " << other.useImapCustomServer;
69         qCDebug(SIEVEEDITOR_LOG) << "sieveSettings " << sieveSettings << " other.sieveSettings " << other.sieveSettings;
70         qCDebug(SIEVEEDITOR_LOG) << "sieveImapAccountSettings " << sieveImapAccountSettings << " other.sieveImapAccountSettings "
71                                  << other.sieveImapAccountSettings;
72     }
73     return result;
74 }
75 
writeServerSieveConfig(const QVector<SieveServerConfig> & lstConfig)76 void SieveEditorUtil::writeServerSieveConfig(const QVector<SieveServerConfig> &lstConfig)
77 {
78     KSharedConfigPtr cfg = KSharedConfig::openConfig();
79     const QRegularExpression re(QStringLiteral("^ServerSieve (.+)$"));
80     // Delete Old Group
81     const QStringList groups = cfg->groupList().filter(re);
82     for (const QString &conf : groups) {
83         KConfigGroup group = cfg->group(conf);
84         group.deleteGroup();
85     }
86 
87     int i = 0;
88     for (const SieveEditorUtil::SieveServerConfig &conf : lstConfig) {
89         writeSieveSettings(cfg, conf, i);
90         ++i;
91     }
92     cfg->sync();
93     cfg->reparseConfiguration();
94 }
95 
sievePasswordIdentifier(const QString & userName,const QString & serverName)96 QString SieveEditorUtil::sievePasswordIdentifier(const QString &userName, const QString &serverName)
97 {
98     return userName + QLatin1Char('@') + serverName;
99 }
100 
imapPasswordIdentifier(const QString & userName,const QString & serverName)101 QString SieveEditorUtil::imapPasswordIdentifier(const QString &userName, const QString &serverName)
102 {
103     return QLatin1String("Imap") + userName + QLatin1Char('@') + serverName;
104 }
105 
writeSieveSettings(const KSharedConfigPtr & cfg,const SieveEditorUtil::SieveServerConfig & conf,int index)106 void SieveEditorUtil::writeSieveSettings(const KSharedConfigPtr &cfg, const SieveEditorUtil::SieveServerConfig &conf, int index)
107 {
108     KConfigGroup group = cfg->group(QStringLiteral("ServerSieve %1").arg(index));
109     group.writeEntry(QStringLiteral("Port"), conf.sieveSettings.port);
110     group.writeEntry(QStringLiteral("ServerName"), conf.sieveSettings.serverName);
111     group.writeEntry(QStringLiteral("UserName"), conf.sieveSettings.userName);
112     group.writeEntry(QStringLiteral("Enabled"), conf.enabled);
113 
114     const QString walletEntry = SieveEditorUtil::sievePasswordIdentifier(conf.sieveSettings.userName, conf.sieveSettings.serverName);
115     auto writeJob = new SieveEditorSavePasswordJob;
116     writeJob->setName(SieveEditorUtil::walletFolderName());
117     writeJob->setPassword(conf.sieveSettings.password);
118     writeJob->setKey(walletEntry);
119 
120     writeJob->start();
121 
122     group.writeEntry(QStringLiteral("Authentication"), static_cast<int>(conf.sieveSettings.authenticationType));
123 
124     // Imap Account Settings
125     group.writeEntry(QStringLiteral("ImapPort"), conf.sieveImapAccountSettings.port());
126     group.writeEntry(QStringLiteral("ImapAuthentication"), static_cast<int>(conf.sieveImapAccountSettings.authenticationType()));
127     group.writeEntry(QStringLiteral("ImapEncrypt"), static_cast<int>(conf.sieveImapAccountSettings.encryptionMode()));
128 
129     if ((conf.sieveImapAccountSettings.serverName() != conf.sieveSettings.serverName)
130         && (conf.sieveImapAccountSettings.userName() != conf.sieveSettings.userName) && !conf.sieveImapAccountSettings.serverName().isEmpty()
131         && !conf.sieveImapAccountSettings.userName().isEmpty()) {
132         group.writeEntry(QStringLiteral("useImapCustomServer"), true);
133         group.writeEntry(QStringLiteral("ImapServerName"), conf.sieveImapAccountSettings.serverName());
134         group.writeEntry(QStringLiteral("ImapUserName"), conf.sieveImapAccountSettings.userName());
135         const QString imapWalletEntry = imapPasswordIdentifier(conf.sieveImapAccountSettings.userName(), conf.sieveImapAccountSettings.serverName());
136 
137         auto writeImapSettingJob = new SieveEditorSavePasswordJob;
138         writeImapSettingJob->setName(SieveEditorUtil::walletFolderName());
139         writeImapSettingJob->setPassword(conf.sieveImapAccountSettings.password());
140         writeImapSettingJob->setKey(imapWalletEntry);
141         writeImapSettingJob->start();
142     }
143 }
144 
walletFolderName()145 QString SieveEditorUtil::walletFolderName()
146 {
147     return QStringLiteral("sieveeditor");
148 }
149 
addServerSieveConfig(const SieveEditorUtil::SieveServerConfig & conf)150 void SieveEditorUtil::addServerSieveConfig(const SieveEditorUtil::SieveServerConfig &conf)
151 {
152     KSharedConfigPtr cfg = KSharedConfig::openConfig();
153     const QRegularExpression re(QStringLiteral("^ServerSieve (.+)$"));
154     const QStringList groups = cfg->groupList().filter(re);
155 
156     writeSieveSettings(cfg, conf, groups.count());
157     cfg->sync();
158 }
159 
operator <<(QDebug d,const SieveEditorUtil::SieveServerConfig & settings)160 QDebug operator<<(QDebug d, const SieveEditorUtil::SieveServerConfig &settings)
161 {
162     d << "sieveSettings " << settings.sieveSettings;
163     d << "sieveImapAccountSettings " << settings.sieveImapAccountSettings;
164     d << "url " << settings.url();
165     d << "enabled " << settings.enabled;
166     d << "useImapCustomServer " << settings.useImapCustomServer;
167     return d;
168 }
169 
operator <<(QDebug d,const SieveEditorUtil::SieveAccountSettings & settings)170 QDebug operator<<(QDebug d, const SieveEditorUtil::SieveAccountSettings &settings)
171 {
172     d << "serverName " << settings.serverName;
173     d << "userName " << settings.userName;
174     d << "password " << settings.password;
175     d << "authenticationType " << settings.authenticationType;
176     d << "port " << settings.port;
177     return d;
178 }
179 
operator ==(const SieveEditorUtil::SieveAccountSettings & other) const180 bool SieveEditorUtil::SieveAccountSettings::operator==(const SieveEditorUtil::SieveAccountSettings &other) const
181 {
182     bool result = (serverName == other.serverName) && (userName == other.userName) && (password == other.password)
183         && (authenticationType == other.authenticationType) && (port == other.port);
184     if (!result) {
185         qCDebug(SIEVEEDITOR_LOG) << "serverName " << serverName << " other.serverName " << other.serverName;
186         qCDebug(SIEVEEDITOR_LOG) << "userName " << userName << " other.userName " << other.userName;
187         qCDebug(SIEVEEDITOR_LOG) << "password " << password << " other.password " << other.password;
188         qCDebug(SIEVEEDITOR_LOG) << "authenticationType " << authenticationType << " other.authenticationType " << other.authenticationType;
189         qCDebug(SIEVEEDITOR_LOG) << "port " << port << " other.port " << other.port;
190     }
191     return result;
192 }
193 
isValid() const194 bool SieveEditorUtil::SieveAccountSettings::isValid() const
195 {
196     return !serverName.isEmpty() && !userName.isEmpty() && (port != -1);
197 }
198 
isValid() const199 bool SieveEditorUtil::SieveServerConfig::isValid() const
200 {
201     return sieveSettings.isValid();
202 }
203