Example #1
0
void ImapAccess::setSslMode(const QString &sslMode)
{
    m_sslMode = sslMode;
    Q_ASSERT(!m_imapModel);

    Imap::Mailbox::SocketFactoryPtr factory;
    Imap::Mailbox::TaskFactoryPtr taskFactory(new Imap::Mailbox::TaskFactory());

    if (m_sslMode == QLatin1String("SSL")) {
        QSettings().setValue(Common::SettingsNames::imapMethodKey, Common::SettingsNames::methodSSL);
        factory.reset(new Imap::Mailbox::SslSocketFactory(server(), port()));
    } else if (m_sslMode == QLatin1String("StartTLS")) {
        QSettings().setValue(Common::SettingsNames::imapMethodKey, Common::SettingsNames::methodTCP);
        QSettings().setValue(Common::SettingsNames::imapStartTlsKey, true);
        factory.reset(new Imap::Mailbox::TlsAbleSocketFactory(server(), port()));
        factory->setStartTlsRequired(true);
    } else {
        QSettings().setValue(Common::SettingsNames::imapMethodKey, Common::SettingsNames::methodTCP);
        QSettings().setValue(Common::SettingsNames::imapStartTlsKey, false);
        factory.reset(new Imap::Mailbox::TlsAbleSocketFactory(server(), port()));
    }

    // FIXME: respect the settings about the cache
    cache = new Imap::Mailbox::MemoryCache(this);

    m_imapModel = new Imap::Mailbox::Model(this, cache, factory, taskFactory, false);
    m_imapModel->setProperty("trojita-imap-enable-id", true);
    connect(m_imapModel, SIGNAL(alertReceived(QString)), this, SLOT(alertReceived(QString)));
    connect(m_imapModel, SIGNAL(connectionError(QString)), this, SLOT(connectionError(QString)));
    connect(m_imapModel, SIGNAL(logged(uint,Common::LogMessage)), this, SLOT(slotLogged(uint,Common::LogMessage)));
    connect(m_imapModel, SIGNAL(needsSslDecision(QList<QSslCertificate>,QList<QSslError>)),
            this, SLOT(slotSslErrors(QList<QSslCertificate>,QList<QSslError>)));

    m_imapModel->setImapUser(username());
    if (!m_password.isNull()) {
        // Really; the idea is to wait before it has been set for the first time
        m_imapModel->setImapPassword(password());
    }

    m_mailboxModel = new Imap::Mailbox::MailboxModel(this, m_imapModel);
    m_mailboxSubtreeModel = new Imap::Mailbox::SubtreeModelOfMailboxModel(this);
    m_mailboxSubtreeModel->setSourceModel(m_mailboxModel);
    m_mailboxSubtreeModel->setOriginalRoot();
    m_msgListModel = new Imap::Mailbox::MsgListModel(this, m_imapModel);
    m_visibleTasksModel = new Imap::Mailbox::VisibleTasksModel(this, m_imapModel->taskModel());
    m_oneMessageModel = new Imap::Mailbox::OneMessageModel(m_imapModel);
    m_msgQNAM = new Imap::Network::MsgPartNetAccessManager(this);
    emit modelsChanged();
}
Example #2
0
void ImapAccess::doConnect()
{
    if (m_netWatcher) {
        // We're temporarily "disabling" this connection. Otherwise this "offline preference"
        // would get saved into the config file, which would be bad.
        disconnect(m_netWatcher, &Mailbox::NetworkWatcher::desiredNetworkPolicyChanged, this, &ImapAccess::desiredNetworkPolicyChanged);
    }

    if (m_imapModel) {
        // Disconnect from network, nuke the models
        Q_ASSERT(m_netWatcher);
        m_netWatcher->setNetworkOffline();
        delete m_threadingMsgListModel;
        m_threadingMsgListModel = 0;
        delete m_msgQNAM;
        m_msgQNAM = 0;
        delete m_oneMessageModel;
        m_oneMessageModel = 0;
        delete m_visibleTasksModel;
        m_visibleTasksModel = 0;
        delete m_msgListModel;
        m_msgListModel = 0;
        delete m_mailboxSubtreeModel;
        m_mailboxSubtreeModel = 0;
        delete m_mailboxModel;
        m_mailboxModel = 0;
        delete m_netWatcher;
        m_netWatcher = 0;
        delete m_imapModel;
        m_imapModel = 0;
    }

    Q_ASSERT(!m_imapModel);

    Imap::Mailbox::SocketFactoryPtr factory;
    Imap::Mailbox::TaskFactoryPtr taskFactory(new Imap::Mailbox::TaskFactory());

    Streams::ProxySettings proxySettings = m_settings->value(Common::SettingsNames::imapUseSystemProxy, true).toBool() ?
                Streams::ProxySettings::RespectSystemProxy : Streams::ProxySettings::DirectConnect;

    switch (m_connectionMethod) {
    case Common::ConnectionMethod::Invalid:
        factory.reset(new Streams::FakeSocketFactory(Imap::CONN_STATE_LOGOUT));
        break;
    case Common::ConnectionMethod::NetCleartext:
    case Common::ConnectionMethod::NetStartTls:
        factory.reset(new Streams::TlsAbleSocketFactory(server(), port()));
        factory->setStartTlsRequired(m_connectionMethod == Common::ConnectionMethod::NetStartTls);
        factory->setProxySettings(proxySettings, QStringLiteral("imap"));
        break;
    case Common::ConnectionMethod::NetDedicatedTls:
        factory.reset(new Streams::SslSocketFactory(server(), port()));
        factory->setProxySettings(proxySettings, QStringLiteral("imap"));
        break;
    case Common::ConnectionMethod::Process:
        QStringList args = m_settings->value(Common::SettingsNames::imapProcessKey).toString().split(QLatin1Char(' '));
        if (args.isEmpty()) {
            // it's going to fail anyway
            args << QLatin1String("");
        }
        QString appName = args.takeFirst();
        factory.reset(new Streams::ProcessSocketFactory(appName, args));
        break;
    }

    bool shouldUsePersistentCache =
            m_settings->value(Common::SettingsNames::cacheOfflineKey).toString() != Common::SettingsNames::cacheOfflineNone;

    if (shouldUsePersistentCache && !QDir().mkpath(m_cacheDir)) {
        onCacheError(tr("Failed to create directory %1").arg(m_cacheDir));
        shouldUsePersistentCache = false;
    }

    if (shouldUsePersistentCache) {
        QFile::Permissions expectedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
        if (QFileInfo(m_cacheDir).permissions() != expectedPerms) {
            if (!QFile::setPermissions(m_cacheDir, expectedPerms)) {
#ifndef Q_OS_WIN32
                onCacheError(tr("Failed to set safe permissions on cache directory %1").arg(m_cacheDir));
                shouldUsePersistentCache = false;
#endif
            }
        }
    }

    std::shared_ptr<Imap::Mailbox::AbstractCache> cache;

    if (!shouldUsePersistentCache) {
        cache.reset(new Imap::Mailbox::MemoryCache());
    } else {
        cache.reset(new Imap::Mailbox::CombinedCache(QStringLiteral("trojita-imap-cache"), m_cacheDir));
        cache->setErrorHandler([this](const QString &e) { this->onCacheError(e); });
        if (! static_cast<Imap::Mailbox::CombinedCache *>(cache.get())->open()) {
            // Error message was already shown by the cacheError() slot
            cache.reset(new Imap::Mailbox::MemoryCache());
        } else {
            if (m_settings->value(Common::SettingsNames::cacheOfflineKey).toString() == Common::SettingsNames::cacheOfflineAll) {
                cache->setRenewalThreshold(0);
            } else {
                const int defaultCacheLifetime = 30;
                bool ok;
                int num = m_settings->value(Common::SettingsNames::cacheOfflineNumberDaysKey, defaultCacheLifetime).toInt(&ok);
                if (!ok)
                    num = defaultCacheLifetime;
                cache->setRenewalThreshold(num);
            }
        }
    }

    m_imapModel = new Imap::Mailbox::Model(this, cache, std::move(factory), std::move(taskFactory));
    m_imapModel->setObjectName(QStringLiteral("imapModel-%1").arg(m_accountName));
    m_imapModel->setCapabilitiesBlacklist(m_settings->value(Common::SettingsNames::imapBlacklistedCapabilities).toStringList());
    m_imapModel->setProperty("trojita-imap-id-no-versions", !m_settings->value(Common::SettingsNames::interopRevealVersions, true).toBool());
    m_imapModel->setProperty("trojita-imap-idle-renewal", m_settings->value(Common::SettingsNames::imapIdleRenewal).toUInt() * 60 * 1000);
    m_imapModel->setNumberRefreshInterval(numberRefreshInterval());
    connect(m_imapModel, &Mailbox::Model::alertReceived, this, &ImapAccess::alertReceived);
    connect(m_imapModel, &Mailbox::Model::imapError, this, &ImapAccess::imapError);
    connect(m_imapModel, &Mailbox::Model::networkError, this, &ImapAccess::networkError);
    //connect(m_imapModel, &Mailbox::Model::logged, this, &ImapAccess::slotLogged);
    connect(m_imapModel, &Mailbox::Model::needsSslDecision, this, &ImapAccess::slotSslErrors);
    connect(m_imapModel, &Mailbox::Model::requireStartTlsInFuture, this, &ImapAccess::onRequireStartTlsInFuture);

    if (m_settings->value(Common::SettingsNames::imapNeedsNetwork, true).toBool()) {
        m_netWatcher = new Imap::Mailbox::SystemNetworkWatcher(this, m_imapModel);
    } else {
        m_netWatcher = new Imap::Mailbox::DummyNetworkWatcher(this, m_imapModel);
    }
    connect(m_netWatcher, &Mailbox::NetworkWatcher::desiredNetworkPolicyChanged, this, &ImapAccess::desiredNetworkPolicyChanged);
    switch (preferredNetworkPolicy()) {
    case Imap::Mailbox::NETWORK_OFFLINE:
        QMetaObject::invokeMethod(m_netWatcher, "setNetworkOffline", Qt::QueuedConnection);
        break;
    case Imap::Mailbox::NETWORK_EXPENSIVE:
        QMetaObject::invokeMethod(m_netWatcher, "setNetworkExpensive", Qt::QueuedConnection);
        break;
    case Imap::Mailbox::NETWORK_ONLINE:
        QMetaObject::invokeMethod(m_netWatcher, "setNetworkOnline", Qt::QueuedConnection);
        break;
    }

    m_imapModel->setImapUser(username());
    if (!m_password.isNull()) {
        // Really; the idea is to wait before it has been set for the first time
        m_imapModel->setImapPassword(password());
    }

    m_mailboxModel = new Imap::Mailbox::MailboxModel(this, m_imapModel);
    m_mailboxModel->setObjectName(QStringLiteral("mailboxModel-%1").arg(m_accountName));
    m_mailboxSubtreeModel = new Imap::Mailbox::SubtreeModelOfMailboxModel(this);
    m_mailboxSubtreeModel->setObjectName(QStringLiteral("mailboxSubtreeModel-%1").arg(m_accountName));
    m_mailboxSubtreeModel->setSourceModel(m_mailboxModel);
    m_mailboxSubtreeModel->setOriginalRoot();
    m_msgListModel = new Imap::Mailbox::MsgListModel(this, m_imapModel);
    m_msgListModel->setObjectName(QStringLiteral("msgListModel-%1").arg(m_accountName));
    m_visibleTasksModel = new Imap::Mailbox::VisibleTasksModel(this, m_imapModel->taskModel());
    m_visibleTasksModel->setObjectName(QStringLiteral("visibleTasksModel-%1").arg(m_accountName));
    m_oneMessageModel = new Imap::Mailbox::OneMessageModel(m_imapModel);
    m_oneMessageModel->setObjectName(QStringLiteral("oneMessageModel-%1").arg(m_accountName));
    m_msgQNAM = new Imap::Network::MsgPartNetAccessManager(this);
    m_msgQNAM->setObjectName(QStringLiteral("m_msgQNAM-%1").arg(m_accountName));
    m_threadingMsgListModel = new Imap::Mailbox::ThreadingMsgListModel(this);
    m_threadingMsgListModel->setObjectName(QStringLiteral("threadingMsgListModel-%1").arg(m_accountName));
    m_threadingMsgListModel->setSourceModel(m_msgListModel);
    emit modelsChanged();
}
Example #3
0
void ImapAccess::doConnect()
{
    Q_ASSERT(!m_imapModel);

    Imap::Mailbox::SocketFactoryPtr factory;
    Imap::Mailbox::TaskFactoryPtr taskFactory(new Imap::Mailbox::TaskFactory());

    Streams::ProxySettings proxySettings = m_settings->value(Common::SettingsNames::imapUseSystemProxy, true).toBool() ?
                Streams::ProxySettings::RespectSystemProxy : Streams::ProxySettings::DirectConnect;

    switch (m_connectionMethod) {
    case Common::ConnectionMethod::Invalid:
        factory.reset(new Streams::FakeSocketFactory(Imap::CONN_STATE_LOGOUT));
        break;
    case Common::ConnectionMethod::NetCleartext:
    case Common::ConnectionMethod::NetStartTls:
        factory.reset(new Streams::TlsAbleSocketFactory(server(), port()));
        factory->setStartTlsRequired(m_connectionMethod == Common::ConnectionMethod::NetStartTls);
        factory->setProxySettings(proxySettings, QLatin1String("imap"));
        break;
    case Common::ConnectionMethod::NetDedicatedTls:
        factory.reset(new Streams::SslSocketFactory(server(), port()));
        factory->setProxySettings(proxySettings, QLatin1String("imap"));
        break;
    case Common::ConnectionMethod::Process:
        QStringList args = m_settings->value(Common::SettingsNames::imapProcessKey).toString().split(QLatin1Char(' '));
        if (args.isEmpty()) {
            // it's going to fail anyway
            args << QLatin1String("");
        }
        QString appName = args.takeFirst();
        factory.reset(new Streams::ProcessSocketFactory(appName, args));
        break;
    }

    bool shouldUsePersistentCache =
            m_settings->value(Common::SettingsNames::cacheOfflineKey).toString() != Common::SettingsNames::cacheOfflineNone;

    if (shouldUsePersistentCache && !QDir().mkpath(m_cacheDir)) {
        onCacheError(tr("Failed to create directory %1").arg(m_cacheDir));
        shouldUsePersistentCache = false;
    }

    if (shouldUsePersistentCache) {
        QFile::Permissions expectedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
        if (QFileInfo(m_cacheDir).permissions() != expectedPerms) {
            if (!QFile::setPermissions(m_cacheDir, expectedPerms)) {
#ifndef Q_OS_WIN32
                onCacheError(tr("Failed to set safe permissions on cache directory %1").arg(m_cacheDir));
                shouldUsePersistentCache = false;
#endif
            }
        }
    }

    Imap::Mailbox::AbstractCache *cache = 0;

    if (!shouldUsePersistentCache) {
        cache = new Imap::Mailbox::MemoryCache(this);
    } else {
        cache = new Imap::Mailbox::CombinedCache(this, QLatin1String("trojita-imap-cache"), m_cacheDir);
        connect(cache, SIGNAL(error(QString)), this, SLOT(onCacheError(QString)));
        if (! static_cast<Imap::Mailbox::CombinedCache *>(cache)->open()) {
            // Error message was already shown by the cacheError() slot
            cache->deleteLater();
            cache = new Imap::Mailbox::MemoryCache(this);
        } else {
            if (m_settings->value(Common::SettingsNames::cacheOfflineKey).toString() == Common::SettingsNames::cacheOfflineAll) {
                cache->setRenewalThreshold(0);
            } else {
                const int defaultCacheLifetime = 30;
                bool ok;
                int num = m_settings->value(Common::SettingsNames::cacheOfflineNumberDaysKey, defaultCacheLifetime).toInt(&ok);
                if (!ok)
                    num = defaultCacheLifetime;
                cache->setRenewalThreshold(num);
            }
        }
    }

    m_imapModel = new Imap::Mailbox::Model(this, cache, std::move(factory), std::move(taskFactory));
    m_imapModel->setObjectName(QString::fromUtf8("imapModel-%1").arg(m_accountName));
    m_imapModel->setCapabilitiesBlacklist(m_settings->value(Common::SettingsNames::imapBlacklistedCapabilities).toStringList());
    m_imapModel->setProperty("trojita-imap-enable-id", m_settings->value(Common::SettingsNames::imapEnableId, true).toBool());
    connect(m_imapModel, SIGNAL(alertReceived(QString)), this, SLOT(alertReceived(QString)));
    connect(m_imapModel, SIGNAL(imapError(QString)), this, SLOT(imapError(QString)));
    connect(m_imapModel, SIGNAL(networkError(QString)), this, SLOT(networkError(QString)));
    //connect(m_imapModel, SIGNAL(logged(uint,Common::LogMessage)), this, SLOT(slotLogged(uint,Common::LogMessage)));
    connect(m_imapModel, SIGNAL(needsSslDecision(QList<QSslCertificate>,QList<QSslError>)),
            this, SLOT(slotSslErrors(QList<QSslCertificate>,QList<QSslError>)));

    if (m_settings->value(Common::SettingsNames::imapNeedsNetwork, true).toBool()) {
        m_netWatcher = new Imap::Mailbox::SystemNetworkWatcher(this, m_imapModel);
    } else {
        m_netWatcher = new Imap::Mailbox::DummyNetworkWatcher(this, m_imapModel);
    }
    QMetaObject::invokeMethod(m_netWatcher,
                              m_settings->value(Common::SettingsNames::imapStartOffline).toBool() ?
                                  "setNetworkOffline" : "setNetworkOnline",
                              Qt::QueuedConnection);

    m_imapModel->setImapUser(username());
    if (!m_password.isNull()) {
        // Really; the idea is to wait before it has been set for the first time
        m_imapModel->setImapPassword(password());
    }

    m_mailboxModel = new Imap::Mailbox::MailboxModel(this, m_imapModel);
    m_mailboxModel->setObjectName(QString::fromUtf8("mailboxModel-%1").arg(m_accountName));
    m_mailboxSubtreeModel = new Imap::Mailbox::SubtreeModelOfMailboxModel(this);
    m_mailboxSubtreeModel->setObjectName(QString::fromUtf8("mailboxSubtreeModel-%1").arg(m_accountName));
    m_mailboxSubtreeModel->setSourceModel(m_mailboxModel);
    m_mailboxSubtreeModel->setOriginalRoot();
    m_msgListModel = new Imap::Mailbox::MsgListModel(this, m_imapModel);
    m_msgListModel->setObjectName(QString::fromUtf8("msgListModel-%1").arg(m_accountName));
    m_visibleTasksModel = new Imap::Mailbox::VisibleTasksModel(this, m_imapModel->taskModel());
    m_visibleTasksModel->setObjectName(QString::fromUtf8("visibleTasksModel-%1").arg(m_accountName));
    m_oneMessageModel = new Imap::Mailbox::OneMessageModel(m_imapModel);
    m_oneMessageModel->setObjectName(QString::fromUtf8("oneMessageModel-%1").arg(m_accountName));
    m_msgQNAM = new Imap::Network::MsgPartNetAccessManager(this);
    m_msgQNAM->setObjectName(QString::fromUtf8("m_msgQNAM-%1").arg(m_accountName));
    m_threadingMsgListModel = new Imap::Mailbox::ThreadingMsgListModel(this);
    m_threadingMsgListModel->setObjectName(QString::fromUtf8("threadingMsgListModel-%1").arg(m_accountName));
    m_threadingMsgListModel->setSourceModel(m_msgListModel);
    emit modelsChanged();
}