/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Messaging Framework. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "imapsettings.h" #include "imapconfiguration.h" #include #include #include #include #include #include #include #include namespace { const QString serviceKey("imap4"); class PortValidator : public QValidator { public: PortValidator(QWidget *parent = Q_NULLPTR, const char *name = Q_NULLPTR); QValidator::State validate(QString &str, int &) const override; }; PortValidator::PortValidator(QWidget *parent, const char *name) : QValidator(parent) { setObjectName(name); } QValidator::State PortValidator::validate(QString &str, int &) const { // allow empty strings, as it's a bit awkward to edit otherwise if ( str.isEmpty() ) return QValidator::Acceptable; bool ok = false; int i = str.toInt(&ok); if ( !ok ) return QValidator::Invalid; if ( i <= 0 || i >= 65536 ) return QValidator::Invalid; return QValidator::Acceptable; } } class PushFolderList : public QObject { Q_OBJECT public: PushFolderList(QWidget *parent, QGridLayout *parentLayout); void setAccountId(const QMailAccountId &id); void addRow(const QString &s); void populate(const QStringList &pushFolderNames); QStringList folderNames(); public slots: void setHasFolders(bool hasFolders); void setPushEnabled(int pushEnabled); void selectFolder(); private: QWidget *_parent; QGridLayout *_parentLayout; QMailAccountId _accountId; bool _hasFolders; bool _pushEnabled; int _startRow; int _items; QList _widgets; QList _layouts; QList _dirTexts; QList _clearButtons; QList _dirButtons; }; PushFolderList::PushFolderList(QWidget *parent, QGridLayout *parentLayout) :QObject(parent), _parent(parent), _parentLayout(parentLayout), _hasFolders(false), _pushEnabled(false), _startRow(parentLayout->rowCount()), _items(0) { } void PushFolderList::setAccountId(const QMailAccountId &id) { _accountId = id; } void PushFolderList::setHasFolders(bool hasFolders) { _hasFolders = hasFolders; foreach(QWidget *widget, _widgets) widget->setEnabled(_hasFolders && _pushEnabled); } void PushFolderList::setPushEnabled(int pushEnabled) { _pushEnabled = (pushEnabled != Qt::Unchecked); foreach(QWidget *widget, _widgets) widget->setEnabled(_hasFolders && _pushEnabled); } void PushFolderList::addRow(const QString &s) { QIcon clearIcon(":icon/clear_left"); QLabel *pushLabel = new QLabel(tr("Push folder"), _parent); QHBoxLayout *layout = new QHBoxLayout(); QLineEdit *pushDir = new QLineEdit(_parent); QToolButton *clearPushEmailButton = new QToolButton(_parent); QToolButton *choosePushDirButton = new QToolButton(_parent); pushDir->setReadOnly(true); pushDir->setFocusPolicy(Qt::NoFocus); pushDir->setText(s); clearPushEmailButton->setIcon(clearIcon); clearPushEmailButton->setEnabled(!s.isEmpty()); choosePushDirButton->setText(tr("...")); pushLabel->setEnabled(_hasFolders && _pushEnabled); pushDir->setEnabled(_hasFolders && _pushEnabled); clearPushEmailButton->setEnabled(_hasFolders && _pushEnabled); choosePushDirButton->setEnabled(_hasFolders && _pushEnabled); connect(clearPushEmailButton, SIGNAL(clicked()), pushDir, SLOT(clear())); connect(choosePushDirButton, SIGNAL(clicked()), this, SLOT(selectFolder())); _dirTexts.append(pushDir); _clearButtons.append(clearPushEmailButton); _dirButtons.append(choosePushDirButton); _layouts.append(layout); _widgets.append(pushLabel); _widgets.append(pushDir); _widgets.append(clearPushEmailButton); _widgets.append(choosePushDirButton); layout->addWidget(pushDir); layout->addWidget(clearPushEmailButton); layout->addWidget(choosePushDirButton); _parentLayout->addWidget(pushLabel, _startRow + _items, 0); _parentLayout->addLayout(layout, _startRow + _items, 1); ++_items; } void PushFolderList::populate(const QStringList &pushFolderNames) { _items = 0; foreach(QWidget *widget, _widgets) { _parentLayout->removeWidget(widget); delete widget; } foreach(QHBoxLayout *layout, _layouts) { _parentLayout->removeItem(layout); delete layout; } _widgets.clear(); _layouts.clear(); _dirTexts.clear(); _clearButtons.clear(); _dirButtons.clear(); QStringList folderNames(pushFolderNames); folderNames.append(""); foreach(const QString &s, folderNames) { addRow(s); } } void PushFolderList::selectFolder() { AccountFolderModel model(_accountId, _parent); model.init(); // The account itself is not a selectable folder QList invalidItems; invalidItems.append(model.itemFromIndex(model.indexFromAccountId(_accountId))); SelectFolderDialog selectFolderDialog(&model); selectFolderDialog.setInvalidSelections(invalidItems); selectFolderDialog.exec(); if (selectFolderDialog.result() == QDialog::Accepted) { QMailFolder folder(model.folderIdFromIndex(model.indexFromItem(selectFolderDialog.selectedItem()))); int index(_dirButtons.indexOf(static_cast(sender()))); if (index != -1) { _dirTexts.at(index)->setText(folder.path()); _clearButtons.at(index)->setEnabled(true); if (index + 1 == _dirTexts.count()) { addRow(""); } } } } QStringList PushFolderList::folderNames() { QStringList result; foreach(QLineEdit* edit, _dirTexts) { if (!edit->text().isEmpty()) result.append(edit->text()); } result.removeDuplicates(); return result; } ImapSettings::ImapSettings() : QMailMessageServiceEditor(), warningEmitted(false), pushFolderList(0) { setupUi(this); setLayoutDirection(qApp->layoutDirection()); connect(intervalCheckBox, SIGNAL(stateChanged(int)), this, SLOT(intervalCheckChanged(int))); const QString uncapitalised("email noautocapitalization"); // These fields should not be autocapitalised mailPortInput->setValidator(new PortValidator(this)); mailPasswInput->setEchoMode(QLineEdit::Password); // This functionality is not currently used: mailboxButton->hide(); #ifdef QT_NO_SSL encryptionIncoming->hide(); lblEncryptionIncoming->hide(); #endif connect(draftsButton, SIGNAL(clicked()), this, SLOT(selectFolder())); connect(sentButton, SIGNAL(clicked()), this, SLOT(selectFolder())); connect(trashButton, SIGNAL(clicked()), this, SLOT(selectFolder())); connect(junkButton, SIGNAL(clicked()), this, SLOT(selectFolder())); QIcon clearIcon(":icon/clear_left"); clearBaseButton->setIcon(clearIcon); connect(clearBaseButton, SIGNAL(clicked()), imapBaseDir, SLOT(clear())); clearDraftsButton->setIcon(clearIcon); connect(clearDraftsButton, SIGNAL(clicked()), imapDraftsDir, SLOT(clear())); clearSentButton->setIcon(clearIcon); connect(clearSentButton, SIGNAL(clicked()), imapSentDir, SLOT(clear())); clearTrashButton->setIcon(clearIcon); connect(clearTrashButton, SIGNAL(clicked()), imapTrashDir, SLOT(clear())); clearJunkButton->setIcon(clearIcon); connect(clearJunkButton, SIGNAL(clicked()), imapJunkDir, SLOT(clear())); QGridLayout *gridLayout = findChild("gridlayout1"); if (gridLayout) { pushFolderList = new PushFolderList(this, gridLayout); connect(pushCheckBox, SIGNAL(stateChanged(int)), pushFolderList, SLOT(setPushEnabled(int))); } else { qWarning() << "Gridlayout not found"; } } void ImapSettings::intervalCheckChanged(int enabled) { intervalPeriod->setEnabled(enabled); roamingCheckBox->setEnabled(enabled); } void ImapSettings::selectFolder() { AccountFolderModel model(accountId, this); model.init(); // The account itself is not a selectable folder QList invalidItems; invalidItems.append(model.itemFromIndex(model.indexFromAccountId(accountId))); SelectFolderDialog selectFolderDialog(&model); selectFolderDialog.setInvalidSelections(invalidItems); selectFolderDialog.exec(); if (selectFolderDialog.result() == QDialog::Accepted) { QMailFolder folder(model.folderIdFromIndex(model.indexFromItem(selectFolderDialog.selectedItem()))); if (sender() == static_cast(draftsButton)) { imapDraftsDir->setText(folder.path()); clearDraftsButton->setEnabled(true); } else if (sender() == static_cast(sentButton)) { imapSentDir->setText(folder.path()); clearSentButton->setEnabled(true); } else if (sender() == static_cast(trashButton)) { imapTrashDir->setText(folder.path()); clearTrashButton->setEnabled(true); } else if (sender() == static_cast(junkButton)) { imapJunkDir->setText(folder.path()); clearJunkButton->setEnabled(true); } } } void ImapSettings::displayConfiguration(const QMailAccount &account, const QMailAccountConfiguration &config) { accountId = account.id(); QStringList pushFolders; bool hasFolders(false); if (accountId.isValid()) { hasFolders = (QMailStore::instance()->countFolders(QMailFolderKey::parentAccountId(accountId)) > 0); pushFolderList->setAccountId(accountId); } // Only allow the base folder to be specified before retrieval occurs baseFolderLabel->setEnabled(!hasFolders); imapBaseDir->setEnabled(!hasFolders); // Only allow the other folders to be specified after we have a folder listing draftsFolderLabel->setEnabled(hasFolders); draftsButton->setEnabled(hasFolders); imapDraftsDir->setEnabled(hasFolders); sentFolderLabel->setEnabled(hasFolders); sentButton->setEnabled(hasFolders); imapSentDir->setEnabled(hasFolders); trashFolderLabel->setEnabled(hasFolders); trashButton->setEnabled(hasFolders); imapTrashDir->setEnabled(hasFolders); junkFolderLabel->setEnabled(hasFolders); junkButton->setEnabled(hasFolders); imapJunkDir->setEnabled(hasFolders); pushCheckBox->setEnabled(hasFolders); if (!config.services().contains(serviceKey)) { // New account mailUserInput->setText(""); mailPasswInput->setText(""); mailServerInput->setText(""); mailPortInput->setText("143"); #ifndef QT_NO_SSL encryptionIncoming->setCurrentIndex(0); #endif preferHtml->setChecked(true); pushCheckBox->setChecked(false); intervalCheckBox->setChecked(false); roamingCheckBox->setChecked(false); pushFolders << "INBOX"; } else { ImapConfiguration imapConfig(config); mailUserInput->setText(imapConfig.mailUserName()); mailPasswInput->setText(imapConfig.mailPassword()); mailServerInput->setText(imapConfig.mailServer()); mailPortInput->setText(QString::number(imapConfig.mailPort())); #ifndef QT_NO_SSL encryptionIncoming->setCurrentIndex(static_cast(imapConfig.mailEncryption())); authentication->setCurrentIndex(imapConfig.mailAuthentication()); #endif deleteCheckBox->setChecked(imapConfig.canDeleteMail()); maxSize->setValue(imapConfig.maxMailSize()); thresholdCheckBox->setChecked(imapConfig.maxMailSize() != -1); preferHtml->setChecked(imapConfig.preferredTextSubtype() == "html"); pushCheckBox->setChecked(imapConfig.pushEnabled()); intervalCheckBox->setChecked(imapConfig.checkInterval() > 0); intervalPeriod->setValue(qAbs(imapConfig.checkInterval())); roamingCheckBox->setChecked(!imapConfig.intervalCheckRoamingEnabled()); imapBaseDir->setText(imapConfig.baseFolder()); clearBaseButton->setEnabled(!imapBaseDir->text().isEmpty()); QMailFolderId draftFolderId = account.standardFolder(QMailFolder::DraftsFolder); imapDraftsDir->setText(draftFolderId.isValid() ? QMailFolder(draftFolderId).path() : ""); clearDraftsButton->setEnabled(!imapDraftsDir->text().isEmpty()); QMailFolderId sentFolderId = account.standardFolder(QMailFolder::SentFolder); imapSentDir->setText(sentFolderId.isValid() ? QMailFolder(sentFolderId).path() : ""); clearSentButton->setEnabled(!imapSentDir->text().isEmpty()); QMailFolderId trashFolderId = account.standardFolder(QMailFolder::TrashFolder); imapTrashDir->setText(trashFolderId.isValid() ? QMailFolder(trashFolderId).path() : ""); clearTrashButton->setEnabled(!imapTrashDir->text().isEmpty()); QMailFolderId junkFolderId = account.standardFolder(QMailFolder::JunkFolder); imapJunkDir->setText(junkFolderId.isValid() ? QMailFolder(junkFolderId).path() : ""); clearJunkButton->setEnabled(!imapJunkDir->text().isEmpty()); pushFolders = imapConfig.pushFolders(); } if (pushFolderList) { pushFolderList->setHasFolders(hasFolders); pushFolderList->setPushEnabled(pushCheckBox->checkState()); pushFolderList->populate(pushFolders); } } bool ImapSettings::updateAccount(QMailAccount *account, QMailAccountConfiguration *config) { bool result; int port = mailPortInput->text().toInt(&result); if ( (!result) ) { // should only happen when the string is empty, since we use a validator. port = -1; } if (!config->services().contains(serviceKey)) config->addServiceConfiguration(serviceKey); ImapConfigurationEditor imapConfig(config); imapConfig.setVersion(100); imapConfig.setType(QMailServiceConfiguration::Source); imapConfig.setMailUserName(mailUserInput->text()); imapConfig.setMailPassword(mailPasswInput->text()); imapConfig.setMailServer(mailServerInput->text()); imapConfig.setMailPort(port == -1 ? 143 : port); #ifndef QT_NO_SSL imapConfig.setMailEncryption(static_cast(encryptionIncoming->currentIndex())); int index(authentication->currentIndex()); Q_ASSERT(index >= 0); imapConfig.setMailAuthentication(index); #endif imapConfig.setDeleteMail(deleteCheckBox->isChecked()); imapConfig.setMaxMailSize(thresholdCheckBox->isChecked() ? maxSize->value() : -1); imapConfig.setPreferredTextSubtype(preferHtml->isChecked() ? "html" : "plain"); imapConfig.setAutoDownload(false); imapConfig.setPushEnabled(pushCheckBox->isChecked()); imapConfig.setCheckInterval(intervalPeriod->value() * (intervalCheckBox->isChecked() ? 1 : -1)); imapConfig.setIntervalCheckRoamingEnabled(!roamingCheckBox->isChecked()); imapConfig.setBaseFolder(imapBaseDir->text()); setStandardFolder(account, QMailFolder::DraftsFolder, imapDraftsDir->text()); setStandardFolder(account, QMailFolder::SentFolder, imapSentDir->text()); setStandardFolder(account, QMailFolder::TrashFolder, imapTrashDir->text()); setStandardFolder(account, QMailFolder::JunkFolder, imapJunkDir->text()); if (pushFolderList) imapConfig.setPushFolders(pushFolderList->folderNames()); account->setStatus(QMailAccount::CanCreateFolders, true); // Do we have a configuration we can use? if (!imapConfig.mailServer().isEmpty() && !imapConfig.mailUserName().isEmpty()) account->setStatus(QMailAccount::CanRetrieve, true); return true; } void ImapSettings::setStandardFolder(QMailAccount *account, QMailFolder::StandardFolder folderType, const QString &path) { QMailFolderIdList folders( QMailStore::instance()->queryFolders(QMailFolderKey::path(path) & QMailFolderKey::parentAccountId(account->id())) ); Q_ASSERT(folders.count() <= 1); if (folders.count() == 0) { // remove standard folder account->setStandardFolder(folderType, QMailFolderId()); return; } if (folders.count() != 1) return; QMailFolder folder(folders.first()); if (folderType == QMailFolder::DraftsFolder) folder.setStatus(QMailFolder::Drafts | QMailFolder::OutboxFolder, true); else if (folderType == QMailFolder::SentFolder) folder.setStatus(QMailFolder::Sent | QMailFolder::OutboxFolder, true); else if (folderType == QMailFolder::InboxFolder) folder.setStatus(QMailFolder::Incoming, true); else if (folderType == QMailFolder::JunkFolder) folder.setStatus(QMailFolder::Junk | QMailFolder::Incoming, true); else if (folderType == QMailFolder::TrashFolder) folder.setStatus(QMailFolder::Trash | QMailFolder::Incoming, true); else if (folderType == QMailFolder::OutboxFolder) folder.setStatus(QMailFolder::Outgoing, true); else qWarning() << "Unable to set unsupported folder type"; QMailStore::instance()->updateFolder(&folder); account->setStandardFolder(folderType, folder.id()); } #include "imapsettings.moc"