Skip to content

Commit

Permalink
[qmf] Listen to sync schedule changes from buteo sync framework.
Browse files Browse the repository at this point in the history
This commit introduces d-bus listeners inside IMAP4 service to
react to changes in the account schedule related to always-on mode
and activate/deactivate IMAP IDLE.
  • Loading branch information
Valerio Valerio committed Feb 2, 2015
1 parent 4fb106c commit 91efba9
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 29 deletions.
1 change: 1 addition & 0 deletions qmf/src/plugins/messageservices/imap/imap.pro
Expand Up @@ -23,6 +23,7 @@ QT = core network

contains(DEFINES, USE_KEEPALIVE) {
PKGCONFIG += keepalive
QT += dbus
}

contains(DEFINES,QT_QMF_USE_ALIGNEDTIMER) {
Expand Down
71 changes: 56 additions & 15 deletions qmf/src/plugins/messageservices/imap/imapclient.cpp
Expand Up @@ -586,6 +586,7 @@ ImapClient::ImapClient(QObject* parent)
_rapidClosing(false),
_idleRetryDelay(InitialIdleRetryDelay),
_pushConnectionsReserved(0),
_pushEnabled(0),
_ssoSessionManager(0),
_loginFailed(false),
_sendLogin(false),
Expand Down Expand Up @@ -648,7 +649,8 @@ ImapClient::ImapClient(QObject* parent)
_requestRapidClose(false),
_rapidClosing(false),
_idleRetryDelay(InitialIdleRetryDelay),
_pushConnectionsReserved(0)
_pushConnectionsReserved(0),
_pushEnabled(0)
{
static int count(0);
++count;
Expand Down Expand Up @@ -887,8 +889,7 @@ void ImapClient::commandTransition(ImapCommand command, OperationStatus status)
}
}

// We are now connected
ImapConfiguration imapCfg(_config);
// We are now connected
_waitingForIdleFolderIds = configurationIdleFolderIds();

if (!_idlesEstablished
Expand All @@ -897,9 +898,17 @@ void ImapClient::commandTransition(ImapCommand command, OperationStatus status)
&& _pushConnectionsReserved) {
_waitingForIdle = true;
emit updateStatus( tr("Logging in idle connection" ) );
#ifdef USE_ACCOUNTS_QT
if (_ssoSessionManager) {
ssoProcessLogin();
} else {
monitor(_waitingForIdleFolderIds);
}
#else
monitor(_waitingForIdleFolderIds);
#endif
} else {
if (!imapCfg.pushEnabled()) {
if (!pushEnabled()) {
foreach(const QMailFolderId &id, _monitored.keys()) {
IdleProtocol *protocol = _monitored.take(id);
protocol->close();
Expand Down Expand Up @@ -1874,8 +1883,7 @@ bool ImapClient::loggingIn() const

bool ImapClient::idlesEstablished()
{
ImapConfiguration imapCfg(_config);
if (!imapCfg.pushEnabled())
if (!pushEnabled())
return true;

return _idlesEstablished;
Expand All @@ -1898,8 +1906,9 @@ QMailFolderIdList ImapClient::configurationIdleFolderIds()
{
ImapConfiguration imapCfg(_config);
QMailFolderIdList folderIds;
if (!imapCfg.pushEnabled())
if (!pushEnabled()) {
return folderIds;
}
foreach(QString folderName, imapCfg.pushFolders()) {
QMailFolderId idleFolderId(mailboxId(folderName));
if (idleFolderId.isValid()) {
Expand All @@ -1915,7 +1924,7 @@ void ImapClient::monitor(const QMailFolderIdList &mailboxIds)

ImapConfiguration imapCfg(_config);
if (!_protocol.supportsCapability("IDLE")
|| !imapCfg.pushEnabled()) {
|| !pushEnabled()) {
return;
}

Expand Down Expand Up @@ -2003,6 +2012,26 @@ void ImapClient::removeAllFromBuffer(QMailMessage *message)
}
}

bool ImapClient::pushEnabled()
{
bool pushEnabled;
#ifdef USE_KEEPALIVE
pushEnabled = _pushEnabled;
#else
ImapConfiguration imapCfg(_config);
pushEnabled = imapCfg.pushEnabled();
#endif
return pushEnabled;
}

void ImapClient::setPushEnabled(bool state)
{
if (_pushEnabled != state) {
qMailLog(Messaging) << Q_FUNC_INFO << "Setting push enabled state to " << state;
_pushEnabled = state;
}
}

#ifdef USE_ACCOUNTS_QT
void ImapClient::removeSsoIdentity(const QMailAccountId &accountId)
{
Expand All @@ -2018,7 +2047,7 @@ void ImapClient::removeSsoIdentity(const QMailAccountId &accountId)

void ImapClient::ssoProcessLogin()
{
if (_loginFailed && _recreateIdentity) {
if ((_loginFailed && _recreateIdentity) || _waitingForIdle) {
// if account was updated try to recreate
// identity without asking the user for new
// credentials
Expand Down Expand Up @@ -2060,6 +2089,9 @@ void ImapClient::onSsoSessionResponse(const QMap<QString,QList<QByteArray> > &ss
if (_sendLogin) {
_protocol.sendLogin(_config, _ssoLogin);
}
if (_waitingForIdle) {
monitor(_waitingForIdleFolderIds);
}
}

void ImapClient::onSsoSessionError(const QString &error)
Expand Down Expand Up @@ -2091,40 +2123,49 @@ void ImapClient::onAccountsUpdated(const QMailAccountIdList &list)
}

qMailLog(IMAP) << Q_FUNC_INFO << imapCfg1.mailUserName() ;
#ifdef USE_KEEPALIVE
// compare config modified by the User
const bool& notEqual = (imapCfg1.mailUserName() != imapCfg2.mailUserName()) ||
(imapCfg1.mailPassword() != imapCfg2.mailPassword()) ||
(imapCfg1.mailServer() != imapCfg2.mailServer()) ||
(imapCfg1.mailPort() != imapCfg2.mailPort()) ||
(imapCfg1.mailEncryption() != imapCfg2.mailEncryption());
#else
// compare config modified by the User
const bool& notEqual = (imapCfg1.mailUserName() != imapCfg2.mailUserName()) ||
(imapCfg1.mailPassword() != imapCfg2.mailPassword()) ||
(imapCfg1.mailServer() != imapCfg2.mailServer()) ||
(imapCfg1.mailPort() != imapCfg2.mailPort()) ||
(imapCfg1.mailEncryption() != imapCfg2.mailEncryption()) ||
(imapCfg1.pushEnabled() != imapCfg2.pushEnabled());
#endif
if (notEqual)
closeIdleConnections();

#ifndef USE_KEEPALIVE
if (imapCfg1.pushEnabled() != imapCfg2.pushEnabled()) {
if (imapCfg2.pushEnabled())
emit restartPushEmail();
}
#endif
}
}
#endif

void ImapClient::closeIdleConnections()
{
qMailLog(IMAP) << Q_FUNC_INFO << "Account was modified. Closing connections";

closeConnection();
#ifdef USE_KEEPALIVE
emit stopPushEmail();
#endif
// closing idle connections
foreach(const QMailFolderId &id, _monitored.keys()) {
IdleProtocol *protocol = _monitored.take(id);
protocol->close();
if (protocol->inUse()) {
protocol->close();
}
delete protocol;
}
_idlesEstablished = false;
}

#endif

#include "imapclient.moc"
5 changes: 4 additions & 1 deletion qmf/src/plugins/messageservices/imap/imapclient.h
Expand Up @@ -79,14 +79,14 @@ class ImapClient : public QObject
void setAccount(const QMailAccountId& accountId);
#ifdef USE_ACCOUNTS_QT
void removeSsoIdentity(const QMailAccountId& accountId);
void closeIdleConnections();
#endif
QMailAccountId account() const;
void requestRapidClose() { _requestRapidClose = true; } // Close connection ASAP, unless interactive checking occurred recently

void newConnection();
void cancelTransfer(QMailServiceAction::Status::ErrorCode code, const QString &text);
void closeConnection();
void closeIdleConnections();

ImapStrategyContext *strategyContext();

Expand All @@ -113,6 +113,8 @@ class ImapClient : public QObject
void setPushConnectionsReserved(int reserved) { _pushConnectionsReserved = reserved; }
int idleRetryDelay() const { return _idleRetryDelay; }
void setIdleRetryDelay(int delay) { _idleRetryDelay = delay; }
bool pushEnabled();
void setPushEnabled(bool state);

signals:
void errorOccurred(int, const QString &);
Expand Down Expand Up @@ -208,6 +210,7 @@ protected slots:
QList<QMailMessageBufferFlushCallback*> callbacks;
QVector<QMailMessage*> _bufferedMessages;
int _pushConnectionsReserved;
bool _pushEnabled;

QMap<QMailMessageId,QString> detachedTempFiles;

Expand Down
102 changes: 90 additions & 12 deletions qmf/src/plugins/messageservices/imap/imapservice.cpp
Expand Up @@ -54,6 +54,12 @@
#include <QCoreApplication>
#include <typeinfo>

#ifdef USE_KEEPALIVE
#include <QDBusConnection>
#include <QtDBus>
#include <QDBusArgument>
#endif

namespace {

const QString serviceKey("imap4");
Expand Down Expand Up @@ -1507,11 +1513,6 @@ ImapService::ImapService(const QMailAccountId &accountId)
_accountWasPushEnabled(false),
_initiatePushEmailTimer(new QTimer(this))
{
#ifdef USE_KEEPALIVE
_backgroundActivity = new BackgroundActivity(this);
_backgroundActivity->setWakeupFrequency(BackgroundActivity::ThirtySeconds);
#endif

QMailAccount account(accountId);
if (!(account.status() & QMailAccount::CanSearchOnServer)) {
account.setStatus(QMailAccount::CanSearchOnServer, true);
Expand All @@ -1526,6 +1527,23 @@ ImapService::ImapService(const QMailAccountId &accountId)
connect(QMailStore::instance(), SIGNAL(accountsUpdated(const QMailAccountIdList&)),
this, SLOT(accountsUpdated(const QMailAccountIdList&)));
connect(_initiatePushEmailTimer, SIGNAL(timeout()), this, SLOT(initiatePushEmail()));

#ifdef USE_KEEPALIVE
_backgroundActivity = new BackgroundActivity(this);
_backgroundActivity->setWakeupFrequency(BackgroundActivity::ThirtySeconds);

// Connect to dbus signals emitted by buteo notifying schedule changes
QDBusConnection m_dBusConnection(QDBusConnection::sessionBus());
_accountPushEnabled = false;
_buteoReplyReceived = false;

if(!m_dBusConnection.isConnected()) {
qWarning() << Q_FUNC_INFO << "Cannot connect to Dbus";
}

m_dBusConnection.connect("com.meego.msyncd", "/synchronizer", "com.meego.msyncd", "syncedExternallyStatus",
this, SLOT(pushEnabledStatus(uint,QString,bool)));
#endif
}

void ImapService::enable()
Expand All @@ -1542,21 +1560,37 @@ void ImapService::enable()
connect(_client, SIGNAL(errorOccurred(QMailServiceAction::Status::ErrorCode, QString)), this, SLOT(errorOccurred(QMailServiceAction::Status::ErrorCode, QString)));
connect(_client, SIGNAL(updateStatus(QString)), this, SLOT(updateStatus(QString)));
connect(_client, SIGNAL(restartPushEmail()), this, SLOT(restartPushEmail()));
#ifdef USE_KEEPALIVE
connect(_client, SIGNAL(stopPushEmail()), this, SLOT(stopPushEmail()));
#endif

QMailAccountConfiguration accountCfg(_accountId);
ImapConfiguration imapCfg(accountCfg);
_accountWasPushEnabled = imapCfg.pushEnabled();
bool pushEnabled;
#ifdef USE_KEEPALIVE
_client->setPushEnabled(_accountPushEnabled);
// When account is enabled or account state changes, request push status from buteo scheduler
if (imapCfg.pushCapable() && !_buteoReplyReceived) {
_accountWasPushEnabled = false;
pushEnabled = false;
QDBusMessage message = QDBusMessage::createMethodCall("com.meego.msyncd", "/synchronizer", "com.meego.msyncd",
"isSyncedExternally");
uint acct = _accountId.toULongLong();
message.setArguments(QVariantList() << acct << "syncemail");
QDBusConnection::sessionBus().asyncCall(message);
} else {
_accountWasPushEnabled = _accountPushEnabled;
pushEnabled = _accountPushEnabled;
}
#else
pushEnabled = imapCfg.pushEnabled();
_accountWasPushEnabled = pushEnabled;
#endif
_previousPushFolders = imapCfg.pushFolders();
_previousConnectionSettings = connectionSettings(imapCfg);

if (imapCfg.pushEnabled() && imapCfg.pushFolders().count()) {
if (pushEnabled && imapCfg.pushFolders().count()) {
_client->setPushConnectionsReserved(reservePushConnections(imapCfg.pushFolders().count()));
}

if (imapCfg.pushEnabled() && _client->pushConnectionsReserved()) {
if (pushEnabled && _client->pushConnectionsReserved()) {
if (!_initiatePushDelay.contains(_accountId)) {
_initiatePushDelay.insert(_accountId, 0);
} else if (_initiatePushDelay[_accountId] == 0) {
Expand Down Expand Up @@ -1590,7 +1624,11 @@ void ImapService::disable()
}
}
_accountWasEnabled = false;
#ifdef USE_KEEPALIVE
_accountWasPushEnabled = _accountPushEnabled;
#else
_accountWasPushEnabled = imapCfg.pushEnabled();
#endif
_previousPushFolders = imapCfg.pushFolders();
_previousConnectionSettings = connectionSettings(imapCfg);
_restartPushEmailTimer->stop();
Expand All @@ -1617,7 +1655,12 @@ void ImapService::accountsUpdated(const QMailAccountIdList &ids)
QMailAccountConfiguration accountCfg(_accountId);
ImapConfiguration imapCfg(accountCfg);
bool isEnabled(account.status() & QMailAccount::Enabled);
bool isPushEnabled(imapCfg.pushEnabled());
bool isPushEnabled;
#ifdef USE_KEEPALIVE
isPushEnabled = _accountPushEnabled;
#else
isPushEnabled = imapCfg.pushEnabled();
#endif
QStringList pushFolders(imapCfg.pushFolders());
QString newConnectionSettings(connectionSettings(imapCfg));
bool loggingIn = false;
Expand Down Expand Up @@ -1652,7 +1695,11 @@ void ImapService::accountsUpdated(const QMailAccountIdList &ids)
}
} else {
// Update the settings
#ifdef USE_KEEPALIVE
_accountWasPushEnabled = _accountPushEnabled;
#else
_accountWasPushEnabled = imapCfg.pushEnabled();
#endif
_previousPushFolders = imapCfg.pushFolders();
_previousConnectionSettings = connectionSettings(imapCfg);
}
Expand Down Expand Up @@ -1728,6 +1775,12 @@ void ImapService::initiatePushEmail()
_backgroundActivity->stop();
qMailLog(Messaging) << Q_FUNC_INFO << "Stopping keepalive";
}
#endif
#ifdef USE_KEEPALIVE
QMailAccountConfiguration accountCfg(_accountId);
ImapConfiguration imapCfg(accountCfg);
_accountWasPushEnabled = _accountPushEnabled;
_previousPushFolders = imapCfg.pushFolders();
#endif
QMailFolderIdList ids(_client->configurationIdleFolderIds());
if (ids.count()) {
Expand Down Expand Up @@ -1815,6 +1868,31 @@ void ImapService::stopPushEmail()
_restartPushEmailTimer->stop();
_initiatePushEmailTimer->stop();
}

void ImapService::pushEnabledStatus(uint accountId, const QString &profileType, bool state)
{
qMailLog(Messaging) << "Received new idleState for account: " << accountId << "state: " << state << "profile type: " << profileType;
if (accountId == _accountId.toULongLong() && profileType == QLatin1String("syncemail")) {
_buteoReplyReceived = true;
if (state != _accountPushEnabled) {
qMailLog(Messaging) << Q_FUNC_INFO << "Changing push enabled state to: " << state;
_accountPushEnabled = state;
if (_accountPushEnabled) {
if (_accountWasEnabled) {
disable();
}
enable();
restartPushEmail();
} else {
// When it changes to true, this state is set inside "enable()"
// since a new client is created
_client->closeIdleConnections();
_client->setPushEnabled(state);
stopPushEmail();
}
}
}
}
#endif

class ImapConfigurator : public QMailMessageServiceConfigurator
Expand Down

0 comments on commit 91efba9

Please sign in to comment.