summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Nosov <Michael.Nosov@harman.com>2018-08-06 12:21:54 +0300
committerMichael Nosov <Michael.Nosov@harman.com>2018-08-23 08:36:28 +0000
commit0d05972b955178184e520c8d86659cbbc4552606 (patch)
tree25f8804263634e858fc9ed105e084e0a3a292ece
parentc0bb1793fd3dd74ea98c1c1f3c44c219ce6b7dc4 (diff)
[qmf] onlineMoveFolder API + IMAP implementation
API to move folder in the hierarchy. Implementation is mostly based on 'onlineRenameFolder' API implementation Testing: ======== 1) Gmail account: Try to move a folder from one folder to another. Expected result: move success 2) Gmail account: Try to move a folder from one folder to root. Expected: move success 3) Gmail account: Try to move top-level (root) folder to some other folder. Expected result: move success 4) Binary compatibility - Verify that existing 3rd party QMF plugins still work well with new QMF - Try to move folder for 3rd party QMF account (which doesn't have implementation of MoveFolder) Verify that MoveFolder action is failed. Verify in logs that action is completed with "This function is not currently supported" error 5) Gmail account (handling errors): - Delete folder A on Web UI - Try to move folder A to folder B on device - Verify that action is failed - Try to perform some moveFolder operations again - Verify that those operation are completed (e.g. completion is not freezed) Change-Id: Ifd59ad4fe9c41d17963aa64101b203d31dcdfb2d Reviewed-by: Christopher Adams <chris.adams@jollamobile.com>
-rw-r--r--src/libraries/qmfclient/qmailaction.h3
-rw-r--r--src/libraries/qmfclient/qmailmessageserver.cpp33
-rw-r--r--src/libraries/qmfclient/qmailmessageserver.h2
-rw-r--r--src/libraries/qmfclient/qmailserviceaction.cpp23
-rw-r--r--src/libraries/qmfclient/qmailserviceaction.h1
-rw-r--r--src/libraries/qmfclient/qmailserviceaction_p.h1
-rw-r--r--src/libraries/qmfmessageserver/qmailmessageservice.cpp36
-rw-r--r--src/libraries/qmfmessageserver/qmailmessageservice.h2
-rw-r--r--src/plugins/messageservices/imap/imapclient.cpp8
-rw-r--r--src/plugins/messageservices/imap/imapclient.h1
-rw-r--r--src/plugins/messageservices/imap/imapprotocol.cpp94
-rw-r--r--src/plugins/messageservices/imap/imapprotocol.h5
-rw-r--r--src/plugins/messageservices/imap/imapservice.cpp27
-rw-r--r--src/plugins/messageservices/imap/imapstrategy.cpp110
-rw-r--r--src/plugins/messageservices/imap/imapstrategy.h24
-rw-r--r--src/tools/messageserver/mailmessageclient.cpp6
-rw-r--r--src/tools/messageserver/mailmessageclient.h4
-rw-r--r--src/tools/messageserver/messageserver.cpp4
-rw-r--r--src/tools/messageserver/servicehandler.cpp35
-rw-r--r--src/tools/messageserver/servicehandler.h3
20 files changed, 414 insertions, 8 deletions
diff --git a/src/libraries/qmfclient/qmailaction.h b/src/libraries/qmfclient/qmailaction.h
index 909d44df..f048542a 100644
--- a/src/libraries/qmfclient/qmailaction.h
+++ b/src/libraries/qmfclient/qmailaction.h
@@ -65,7 +65,8 @@ enum QMailServerRequestType
SearchMessagesRequestType,
CancelSearchRequestType,
ListActionsRequestType,
- ProtocolRequestRequestType
+ ProtocolRequestRequestType,
+ MoveFolderRequestType
};
typedef quint64 QMailActionId;
diff --git a/src/libraries/qmfclient/qmailmessageserver.cpp b/src/libraries/qmfclient/qmailmessageserver.cpp
index 74512e22..bbb2e354 100644
--- a/src/libraries/qmfclient/qmailmessageserver.cpp
+++ b/src/libraries/qmfclient/qmailmessageserver.cpp
@@ -92,6 +92,7 @@ signals:
void onlineCreateFolder(quint64, const QString &name, const QMailAccountId &accountId, const QMailFolderId &parentId);
void onlineRenameFolder(quint64, const QMailFolderId &folderId, const QString &name);
void onlineDeleteFolder(quint64, const QMailFolderId &folderId);
+ void onlineMoveFolder(quint64, const QMailFolderId &folderId, const QMailFolderId &newParentId);
void cancelTransfer(quint64);
@@ -178,6 +179,8 @@ QMailMessageServerPrivate::QMailMessageServerPrivate(QMailMessageServer* parent)
adaptor, MESSAGE(onlineCreateFolder(quint64, QString, QMailAccountId, QMailFolderId)));
connectIpc(this, SIGNAL(onlineRenameFolder(quint64, QMailFolderId, QString)),
adaptor, MESSAGE(onlineRenameFolder(quint64, QMailFolderId, QString)));
+ connectIpc(this, SIGNAL(onlineMoveFolder(quint64, QMailFolderId, QMailFolderId)),
+ adaptor, MESSAGE(onlineMoveFolder(quint64, QMailFolderId, QMailFolderId)));
connectIpc(this, SIGNAL(onlineDeleteFolder(quint64, QMailFolderId)),
adaptor, MESSAGE(onlineDeleteFolder(quint64, QMailFolderId)));
connectIpc(this, SIGNAL(deleteMessages(quint64, QMailMessageIdList)),
@@ -236,6 +239,8 @@ QMailMessageServerPrivate::QMailMessageServerPrivate(QMailMessageServer* parent)
parent, SIGNAL(folderRenamed(quint64, QMailFolderId)));
connectIpc(adaptor, MESSAGE(folderDeleted(quint64, QMailFolderId)),
parent, SIGNAL(folderDeleted(quint64, QMailFolderId)));
+ connectIpc(adaptor, MESSAGE(folderMoved(quint64, QMailFolderId)),
+ parent, SIGNAL(folderMoved(quint64, QMailFolderId)));
connectIpc(adaptor, MESSAGE(storageActionCompleted(quint64)),
parent, SIGNAL(storageActionCompleted(quint64)));
connectIpc(adaptor, MESSAGE(retrievalCompleted(quint64)),
@@ -450,6 +455,15 @@ QMailMessageServerPrivate::~QMailMessageServerPrivate()
*/
/*!
+ \fn void QMailMessageServer::folderMoved(quint64 action, const QMailFolderId& folderId);
+
+ Emitted when the folder identified by \a folderId has been moved, in response to the request
+ identified by \a action.
+
+ \sa onlineMoveFolder()
+*/
+
+/*!
\fn void QMailMessageServer::storageActionCompleted(quint64 action);
Emitted when the storage operation identified by \a action is completed.
@@ -951,7 +965,7 @@ void QMailMessageServer::onlineRenameFolder(quint64 action, const QMailFolderId
This function requires the device to be online, it may initiate communication
with external servers.
- \sa onlineCreateFolder(), onlineRenameFolder()
+ \sa onlineCreateFolder(), onlineRenameFolder(), onlineMoveFolder()
*/
void QMailMessageServer::onlineDeleteFolder(quint64 action, const QMailFolderId &folderId)
{
@@ -959,6 +973,23 @@ void QMailMessageServer::onlineDeleteFolder(quint64 action, const QMailFolderId
}
/*!
+ Requests that the MessageServer move the folder identified by \a folderId.
+ If \a parentId is a valid folder identifier the new folder will be a child of the parent;
+ otherwise the folder will be have no parent and will be created at the highest level.
+
+ The request has the identifier \a action.
+
+ This function requires the device to be online, it may initiate communication
+ with external servers.
+
+ \sa onlineCreateFolder(), onlineRenameFolder()
+*/
+void QMailMessageServer::onlineMoveFolder(quint64 action, const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ emit d->onlineMoveFolder(action, folderId, newParentId);
+}
+
+/*!
Requests that the MessageServer cancel any pending transfer operations for the request identified by \a action.
\sa transmitMessages(), retrieveMessages()
diff --git a/src/libraries/qmfclient/qmailmessageserver.h b/src/libraries/qmfclient/qmailmessageserver.h
index d62e71e2..238ab02e 100644
--- a/src/libraries/qmfclient/qmailmessageserver.h
+++ b/src/libraries/qmfclient/qmailmessageserver.h
@@ -89,6 +89,7 @@ Q_SIGNALS:
void folderCreated(quint64, const QMailFolderId&);
void folderRenamed(quint64, const QMailFolderId&);
void folderDeleted(quint64, const QMailFolderId&);
+ void folderMoved(quint64, const QMailFolderId&);
void storageActionCompleted(quint64);
@@ -140,6 +141,7 @@ public Q_SLOTS:
void onlineCreateFolder(quint64, const QString &name, const QMailAccountId &accountId, const QMailFolderId &parentId);
void onlineRenameFolder(quint64, const QMailFolderId &folderId, const QString &name);
void onlineDeleteFolder(quint64, const QMailFolderId &folderId);
+ void onlineMoveFolder(quint64, const QMailFolderId &folderId, const QMailFolderId &newParentId);
void deleteMessages(quint64, const QMailMessageIdList &ids);
void rollBackUpdates(quint64, const QMailAccountId &mailAccountId);
diff --git a/src/libraries/qmfclient/qmailserviceaction.cpp b/src/libraries/qmfclient/qmailserviceaction.cpp
index 1ce43d0b..e0c56654 100644
--- a/src/libraries/qmfclient/qmailserviceaction.cpp
+++ b/src/libraries/qmfclient/qmailserviceaction.cpp
@@ -1681,6 +1681,12 @@ void QMailStorageActionPrivate::onlineDeleteFolder(const QMailFolderId &folderId
onlineDeleteFolderHelper(folderId);
}
+void QMailStorageActionPrivate::onlineMoveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ _server->onlineMoveFolder(newAction(), folderId, newParentId);
+ emitChanges();
+}
+
void QMailStorageActionPrivate::init()
{
QMailServiceActionPrivate::init();
@@ -1998,7 +2004,7 @@ void QMailStorageAction::onlineCreateFolder(const QString &name, const QMailAcco
This function requires the device to be online, it may initiate communication with external servers.
- \sa onlineCreateFolder()
+ \sa onlineCreateFolder(), onlineMoveFolder()
*/
void QMailStorageAction::onlineRenameFolder(const QMailFolderId &folderId, const QString &name)
{
@@ -2011,13 +2017,26 @@ void QMailStorageAction::onlineRenameFolder(const QMailFolderId &folderId, const
This function requires the device to be online, it may initiate communication with external servers.
- \sa onlineCreateFolder(), onlineRenameFolder()
+ \sa onlineCreateFolder(), onlineRenameFolder(), onlineMoveFolder()
*/
void QMailStorageAction::onlineDeleteFolder(const QMailFolderId &folderId)
{
impl(this)->onlineDeleteFolder(folderId);
}
+/*!
+ Requests that the message server move the folder identified by \a folderId.
+ If \a newParentId is a valid folder identifier the folder will be a child of the parent;
+ otherwise the folder will be have no parent and will be moved to the highest level.
+
+ This function requires the device to be online, it may initiate communication with external servers.
+
+ \sa onlineCreateFolder(), onlineRenameFolder()
+*/
+void QMailStorageAction::onlineMoveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ impl(this)->onlineMoveFolder(folderId, newParentId);
+}
QMailSearchActionPrivate::QMailSearchActionPrivate(QMailSearchAction *i)
: QMailServiceActionPrivate(this, i)
diff --git a/src/libraries/qmfclient/qmailserviceaction.h b/src/libraries/qmfclient/qmailserviceaction.h
index d9c60042..3f6a1421 100644
--- a/src/libraries/qmfclient/qmailserviceaction.h
+++ b/src/libraries/qmfclient/qmailserviceaction.h
@@ -244,6 +244,7 @@ public Q_SLOTS:
void onlineCreateFolder(const QString &name, const QMailAccountId &accountId, const QMailFolderId &parentId);
void onlineRenameFolder(const QMailFolderId &folderId, const QString &name);
void onlineDeleteFolder(const QMailFolderId &folderId);
+ void onlineMoveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId);
void deleteMessages(const QMailMessageIdList &ids);
void rollBackUpdates(const QMailAccountId &mailAccountId);
diff --git a/src/libraries/qmfclient/qmailserviceaction_p.h b/src/libraries/qmfclient/qmailserviceaction_p.h
index d96247fc..f033211b 100644
--- a/src/libraries/qmfclient/qmailserviceaction_p.h
+++ b/src/libraries/qmfclient/qmailserviceaction_p.h
@@ -270,6 +270,7 @@ public:
void onlineRenameFolder(const QMailFolderId &id, const QString &name);
void onlineDeleteFolder(const QMailFolderId &id);
void onlineDeleteFolderHelper(const QMailFolderId &id);
+ void onlineMoveFolder(const QMailFolderId &id, const QMailFolderId &newParentId);
protected:
virtual void init();
diff --git a/src/libraries/qmfmessageserver/qmailmessageservice.cpp b/src/libraries/qmfmessageserver/qmailmessageservice.cpp
index 8b6574a4..7e0f470d 100644
--- a/src/libraries/qmfmessageserver/qmailmessageservice.cpp
+++ b/src/libraries/qmfmessageserver/qmailmessageservice.cpp
@@ -863,6 +863,25 @@ bool QMailMessageSource::deleteFolder(const QMailFolderId &folderId)
return false;
}
+/*!
+ Invoked by the message server to move a folder.
+
+ Moves the folder identified by \a folderId to a folder identified by \a newParentId.
+ The name of the folder should not change.
+
+ Return true if an operation is initiated.
+
+ \sa deleteFolder(), createFolder(), renameFolder()
+*/
+bool QMailMessageSource::moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ Q_UNUSED(folderId)
+ Q_UNUSED(newParentId)
+
+ notImplemented();
+ return false;
+}
+
/*!
@@ -1916,6 +1935,23 @@ bool QMailMessageSource::deleteFolder(const QMailFolderId &folderId, quint64 act
}
/*!
+ \overload moveFolder()
+
+ Concurrent version of moveFolder().
+
+ The request has the identifier \a action.
+*/
+bool QMailMessageSource::moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId, quint64 action)
+{
+ Q_UNUSED(folderId)
+ Q_UNUSED(newParentId)
+ Q_UNUSED(action)
+
+ notImplemented(action);
+ return false;
+}
+
+/*!
\overload searchMessages()
Concurrent version of searchMessages().
diff --git a/src/libraries/qmfmessageserver/qmailmessageservice.h b/src/libraries/qmfmessageserver/qmailmessageservice.h
index a0deb5b0..e5dd5586 100644
--- a/src/libraries/qmfmessageserver/qmailmessageservice.h
+++ b/src/libraries/qmfmessageserver/qmailmessageservice.h
@@ -164,6 +164,8 @@ public Q_SLOTS:
virtual bool renameFolder(const QMailFolderId &folderId, const QString &name, quint64 action);
virtual bool deleteFolder(const QMailFolderId &folderId);
virtual bool deleteFolder(const QMailFolderId &folderId, quint64 action);
+ virtual bool moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId);
+ virtual bool moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId, quint64 action);
virtual bool searchMessages(const QMailMessageKey &filter, const QString& bodyText, quint64 limit, const QMailMessageSortKey &sort);
virtual bool searchMessages(const QMailMessageKey &filter, const QString& bodyText, quint64 limit, const QMailMessageSortKey &sort, quint64 action);
diff --git a/src/plugins/messageservices/imap/imapclient.cpp b/src/plugins/messageservices/imap/imapclient.cpp
index 0ff17f82..95bf0eec 100644
--- a/src/plugins/messageservices/imap/imapclient.cpp
+++ b/src/plugins/messageservices/imap/imapclient.cpp
@@ -430,6 +430,8 @@ ImapClient::ImapClient(QObject* parent)
this, SLOT(folderDeleted(QMailFolder, bool)));
connect(&_protocol, SIGNAL(folderRenamed(QMailFolder, QString, bool)),
this, SLOT(folderRenamed(QMailFolder, QString, bool)));
+ connect(&_protocol, SIGNAL(folderMoved(QMailFolder, QString, QMailFolderId, bool)),
+ this, SLOT(folderMoved(QMailFolder, QString, QMailFolderId, bool)));
connect(&_protocol, SIGNAL(updateStatus(QString)),
this, SLOT(transportStatus(QString)) );
connect(&_protocol, SIGNAL(connectionError(int,QString)),
@@ -982,6 +984,12 @@ void ImapClient::folderRenamed(const QMailFolder &folder, const QString &newPath
_strategyContext->folderRenamed(folder, newPath, success);
}
+void ImapClient::folderMoved(const QMailFolder &folder, const QString &newPath,
+ const QMailFolderId &newParentId, bool success)
+{
+ _strategyContext->folderMoved(folder, newPath, newParentId, success);
+}
+
static bool updateParts(QMailMessagePart &part, const QByteArray &bodyData)
{
static const QByteArray newLine(QMailMessage::CRLF);
diff --git a/src/plugins/messageservices/imap/imapclient.h b/src/plugins/messageservices/imap/imapclient.h
index c3e5c1fd..e60c64a9 100644
--- a/src/plugins/messageservices/imap/imapclient.h
+++ b/src/plugins/messageservices/imap/imapclient.h
@@ -131,6 +131,7 @@ public slots:
void folderDeleted(const QMailFolder &folder, bool success);
void folderCreated(const QString &folder, bool success);
void folderRenamed(const QMailFolder &folder, const QString &newName, bool success);
+ void folderMoved(const QMailFolder &folder, const QString &newName, const QMailFolderId &newParentId, bool success);
protected slots:
void connectionInactive();
diff --git a/src/plugins/messageservices/imap/imapprotocol.cpp b/src/plugins/messageservices/imap/imapprotocol.cpp
index 573019a9..44836fb5 100644
--- a/src/plugins/messageservices/imap/imapprotocol.cpp
+++ b/src/plugins/messageservices/imap/imapprotocol.cpp
@@ -876,6 +876,88 @@ QString RenameState::buildNewPath(ImapContext *c , const QMailFolder &folder, QS
return path;
}
+class MoveState : public ImapState
+{
+ Q_OBJECT
+
+public:
+ MoveState() : ImapState(IMAP_Move, "Move") {}
+
+ void setNewMailboxParent(const QMailFolder &mailbox, const QMailFolderId &newParentId);
+
+ virtual bool permitsPipelining() const { return true; }
+ virtual void init();
+ virtual QString transmit(ImapContext *c);
+ virtual void leave(ImapContext *c);
+ virtual void taggedResponse(ImapContext *c, const QString &line);
+ virtual QString error(const QString &line);
+signals:
+ void folderMoved(const QMailFolder &folder, const QString &newPath,
+ const QMailFolderId &newParentId, bool success);
+
+private:
+ QString buildNewPath(ImapContext *c, const QMailFolder &folder, const QMailFolderId &newParentId);
+ QList<QPair<QMailFolder, QMailFolderId> > _mailboxParents;
+};
+
+void MoveState::setNewMailboxParent(const QMailFolder &mailbox, const QMailFolderId &newParentId)
+{
+ _mailboxParents.append(qMakePair(mailbox, newParentId));
+}
+
+void MoveState::init()
+{
+ _mailboxParents.clear();
+ ImapState::init();
+}
+
+QString MoveState::transmit(ImapContext *c)
+{
+ if (c->protocol()->delimiterUnknown()) {
+ // We are waiting on delim to move
+ return QString();
+ }
+
+ QString from = _mailboxParents.last().first.path();
+ QString to = buildNewPath(c, _mailboxParents.last().first, _mailboxParents.last().second);
+ QString cmd(QString("RENAME %1 %2").arg(ImapProtocol::quoteString(from)).arg( ImapProtocol::quoteString(to)));
+ return c->sendCommand(cmd);
+}
+
+void MoveState::leave(ImapContext *)
+{
+ ImapState::init();
+ _mailboxParents.removeFirst();
+}
+
+void MoveState::taggedResponse(ImapContext *c, const QString &line)
+{
+ QString path = buildNewPath(c, _mailboxParents.first().first, _mailboxParents.first().second);
+ emit folderMoved(_mailboxParents.first().first, path, _mailboxParents.first().second, status() == OpOk);
+ ImapState::taggedResponse(c, line);
+}
+
+QString MoveState::error(const QString &line)
+{
+ qWarning() << "MoveState::error:" << line;
+ emit folderMoved(_mailboxParents.first().first, QString(), _mailboxParents.first().second, false);
+ return ImapState::error(line);
+}
+
+QString MoveState::buildNewPath(ImapContext *c, const QMailFolder &folder, const QMailFolderId &newParentId)
+{
+ QString path;
+ if (c->protocol()->flatHierarchy() || c->protocol()->delimiter() == 0) {
+ path = folder.path();
+ } else if (newParentId.isValid()) {
+ QMailFolder parentFolder(newParentId);
+ path = parentFolder.path() + c->protocol()->delimiter() + folder.path().section(c->protocol()->delimiter(), -1);
+ } else {
+ path = folder.path().section(c->protocol()->delimiter(), -1);
+ }
+ return path;
+}
+
class ListState : public ImapState
{
Q_OBJECT
@@ -2754,6 +2836,7 @@ public:
EnableState enableState;
NoopState noopState;
RenameState renameState;
+ MoveState moveState;
SearchMessageState searchMessageState;
SearchState searchState;
UidSearchState uidSearchState;
@@ -2906,6 +2989,8 @@ ImapProtocol::ImapProtocol()
this, SIGNAL(folderDeleted(QMailFolder, bool)));
connect(&_fsm->renameState, SIGNAL(folderRenamed(QMailFolder, QString, bool)),
this, SIGNAL(folderRenamed(QMailFolder, QString, bool)));
+ connect(&_fsm->moveState, SIGNAL(folderMoved(QMailFolder, QString, QMailFolderId, bool)),
+ this, SIGNAL(folderMoved(QMailFolder, QString, QMailFolderId, bool)));
}
ImapProtocol::~ImapProtocol()
@@ -3192,6 +3277,15 @@ void ImapProtocol::sendRename(const QMailFolder &mailbox, const QString &newName
_fsm->setState(&_fsm->renameState);
}
+void ImapProtocol::sendMove(const QMailFolder &mailbox, const QMailFolderId &newParentId)
+{
+ if (delimiterUnknown()) {
+ sendDiscoverDelimiter();
+ }
+ _fsm->moveState.setNewMailboxParent(mailbox, newParentId);
+ _fsm->setState(&_fsm->moveState);
+}
+
void ImapProtocol::sendSearchMessages(const QMailMessageKey &key, const QString &body, const QMailMessageSortKey &sort, bool count)
{
_fsm->searchMessageState.setParameters(key, body, sort, count);
diff --git a/src/plugins/messageservices/imap/imapprotocol.h b/src/plugins/messageservices/imap/imapprotocol.h
index 5cb46523..4077c0e2 100644
--- a/src/plugins/messageservices/imap/imapprotocol.h
+++ b/src/plugins/messageservices/imap/imapprotocol.h
@@ -83,7 +83,8 @@ enum ImapCommand
IMAP_QResync,
IMAP_FetchFlags,
IMAP_Noop,
- IMAP_Compress
+ IMAP_Compress,
+ IMAP_Move
};
enum MessageFlag
@@ -186,6 +187,7 @@ public:
void sendCreate(const QMailFolderId &parentFolderId, const QString &name);
void sendDelete(const QMailFolder &mailbox);
void sendRename(const QMailFolder &mailbox, const QString &newname);
+ void sendMove(const QMailFolder &mailbox, const QMailFolderId &newParentId);
/* Valid in Selected state only */
void sendSearchMessages(const QMailMessageKey &key, const QString &body, const QMailMessageSortKey &sort, bool count);
@@ -229,6 +231,7 @@ signals:
void folderCreated(const QString &folder, bool success);
void folderDeleted(const QMailFolder &name, bool success);
void folderRenamed(const QMailFolder &folder, const QString &newPath, bool success);
+ void folderMoved(const QMailFolder &folder, const QString &newPath, const QMailFolderId &newParentId, bool success);
void continuationRequired(ImapCommand, const QString &);
void completed(ImapCommand, OperationStatus);
diff --git a/src/plugins/messageservices/imap/imapservice.cpp b/src/plugins/messageservices/imap/imapservice.cpp
index ce5d3102..a5adeb04 100644
--- a/src/plugins/messageservices/imap/imapservice.cpp
+++ b/src/plugins/messageservices/imap/imapservice.cpp
@@ -145,6 +145,7 @@ public slots:
virtual bool createStandardFolders(const QMailAccountId &accountId);
virtual bool deleteFolder(const QMailFolderId &folderId);
virtual bool renameFolder(const QMailFolderId &folderId, const QString &name);
+ virtual bool moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId);
virtual bool searchMessages(const QMailMessageKey &searchCriteria, const QString &bodyText, const QMailMessageSortKey &sort);
virtual bool searchMessages(const QMailMessageKey &searchCriteria, const QString &bodyText, quint64 limit, const QMailMessageSortKey &sort);
@@ -1088,6 +1089,32 @@ bool ImapService::Source::renameFolder(const QMailFolderId &folderId, const QStr
return true;
}
+bool ImapService::Source::moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ Q_ASSERT(!_unavailable);
+ if (!_service)
+ return false;
+
+ if (!_service->_client) {
+ _service->errorOccurred(QMailServiceAction::Status::ErrFrameworkFault, tr("Account disabled"));
+ return false;
+ }
+
+ if (!folderId.isValid()) {
+ _service->errorOccurred(QMailServiceAction::Status::ErrInvalidData, tr("Cannot move an invalid folder"));
+ return false;
+ }
+
+ _service->_client->strategyContext()->moveFolderStrategy.moveFolder(folderId, newParentId);
+
+ appendStrategy(&_service->_client->strategyContext()->moveFolderStrategy);
+
+ if (!_unavailable)
+ return initiateStrategy();
+
+ return true;
+}
+
bool ImapService::Source::searchMessages(const QMailMessageKey &searchCriteria, const QString &bodyText, const QMailMessageSortKey &sort)
{
QMailAccountConfiguration accountCfg(_service->accountId());
diff --git a/src/plugins/messageservices/imap/imapstrategy.cpp b/src/plugins/messageservices/imap/imapstrategy.cpp
index e0d4ec73..5842e56c 100644
--- a/src/plugins/messageservices/imap/imapstrategy.cpp
+++ b/src/plugins/messageservices/imap/imapstrategy.cpp
@@ -658,6 +658,16 @@ void ImapStrategy::folderRenamed(ImapStrategyContextBase *context, const QMailFo
Q_UNUSED(success)
}
+void ImapStrategy::folderMoved(ImapStrategyContextBase *context, const QMailFolder &folder,
+ const QString &newPath, const QMailFolderId &newParentId, bool success)
+{
+ Q_UNUSED(context)
+ Q_UNUSED(folder)
+ Q_UNUSED(newPath)
+ Q_UNUSED(newParentId)
+ Q_UNUSED(success)
+}
+
void ImapStrategy::selectFolder(ImapStrategyContextBase *context, const QMailFolder &folder)
{
context->protocol().sendSelect(folder);
@@ -890,6 +900,93 @@ void ImapRenameFolderStrategy::folderRenamed(ImapStrategyContextBase *context, c
context->operationCompleted();
}
+/* A strategy to move a folder */
+void ImapMoveFolderStrategy::transition(ImapStrategyContextBase* context, const ImapCommand cmd, const OperationStatus op)
+{
+ if (op != OpOk)
+ qWarning() << "IMAP Response to cmd:" << cmd << " is not ok: " << op;
+
+ switch (cmd)
+ {
+ case IMAP_Login:
+ handleLogin(context);
+ break;
+ case IMAP_Move:
+ handleMove(context);
+ break;
+ default:
+ qWarning() << "Unhandled IMAP response:" << cmd;
+ }
+}
+
+void ImapMoveFolderStrategy::moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ _folderNewParents.append(qMakePair(folderId, newParentId));
+}
+
+void ImapMoveFolderStrategy::handleLogin(ImapStrategyContextBase *context)
+{
+ process(context);
+}
+
+void ImapMoveFolderStrategy::handleMove(ImapStrategyContextBase *context)
+{
+ process(context);
+}
+
+void ImapMoveFolderStrategy::process(ImapStrategyContextBase *context)
+{
+ while (_folderNewParents.count() > 0) {
+ const QPair<QMailFolderId, QMailFolderId> &folderId_parent = _folderNewParents.takeFirst();
+ _inProgress++;
+ context->protocol().sendMove(QMailFolder(folderId_parent.first), folderId_parent.second);
+ }
+}
+
+void ImapMoveFolderStrategy::folderMoved(ImapStrategyContextBase *context, const QMailFolder &folder,
+ const QString &newPath, const QMailFolderId &newParentId, bool success)
+{
+ if (_inProgress > 0) {
+ _inProgress--;
+ }
+ if (!success) {
+ _inProgress = 0; // in case of error, subsequent responses may not be received
+ return;
+ }
+ QString name;
+ if (!context->protocol().delimiter().isNull()) {
+ //only update if we're dealing with a hierarchical system
+ QChar delimiter = context->protocol().delimiter();
+ if (folder.path().count(delimiter) == 0) {
+ name = newPath;
+ } else {
+ name = newPath.section(delimiter, -1, -1);
+ }
+ QMailFolderKey affectedFolderKey(QMailFolderKey::ancestorFolderIds(folder.id()));
+ QMailFolderIdList affectedFolders = QMailStore::instance()->queryFolders(affectedFolderKey);
+
+ while (!affectedFolders.isEmpty()) {
+ QMailFolder childFolder(affectedFolders.takeFirst());
+ QString path = childFolder.path();
+ path.replace(0, folder.path().length(), newPath);
+ childFolder.setPath(path);
+ if (!QMailStore::instance()->updateFolder(&childFolder))
+ qWarning() << "Unable to locally change path of a subfolder";
+ }
+ } else {
+ name = newPath;
+ }
+
+ QMailFolder newFolder = folder;
+ newFolder.setPath(newPath);
+ newFolder.setParentFolderId(newParentId);
+
+ if (!QMailStore::instance()->updateFolder(&newFolder))
+ qWarning() << "Unable to locally move folder";
+ if (_inProgress == 0)
+ context->operationCompleted();
+}
+
/* A strategy to traverse a list of messages, preparing each one for transmission
by generating a URLAUTH token.
*/
@@ -1162,7 +1259,13 @@ void ImapMessageListStrategy::transition(ImapStrategyContextBase *context, ImapC
handleRename(context);
break;
}
-
+
+ case IMAP_Move:
+ {
+ handleMove(context);
+ break;
+ }
+
case IMAP_Close:
{
handleClose(context);
@@ -1209,6 +1312,11 @@ void ImapMessageListStrategy::handleRename(ImapStrategyContextBase *context)
messageListMessageAction(context);
}
+void ImapMessageListStrategy::handleMove(ImapStrategyContextBase *context)
+{
+ messageListMessageAction(context);
+}
+
void ImapMessageListStrategy::handleClose(ImapStrategyContextBase *context)
{
diff --git a/src/plugins/messageservices/imap/imapstrategy.h b/src/plugins/messageservices/imap/imapstrategy.h
index 83a21efb..26c63e35 100644
--- a/src/plugins/messageservices/imap/imapstrategy.h
+++ b/src/plugins/messageservices/imap/imapstrategy.h
@@ -144,6 +144,7 @@ public:
virtual void folderCreated(ImapStrategyContextBase *context, const QString &folder, bool success);
virtual void folderDeleted(ImapStrategyContextBase *context, const QMailFolder &folder, bool success);
virtual void folderRenamed(ImapStrategyContextBase *context, const QMailFolder &folder, const QString &newName, bool success);
+ virtual void folderMoved(ImapStrategyContextBase *context, const QMailFolder &folder, const QString &newName, const QMailFolderId &newParentId, bool success);
virtual void selectFolder(ImapStrategyContextBase *context, const QMailFolder &folder);
void clearError() { _error = false; }
@@ -219,6 +220,24 @@ protected:
int _inProgress;
};
+class ImapMoveFolderStrategy : public ImapStrategy
+{
+public:
+ ImapMoveFolderStrategy() : _inProgress(0) { }
+ virtual ~ImapMoveFolderStrategy() {}
+
+ virtual void transition(ImapStrategyContextBase *, const ImapCommand, const OperationStatus);
+ virtual void moveFolder(const QMailFolderId &folderId, const QMailFolderId &newParentId);
+ virtual void folderMoved(ImapStrategyContextBase *context, const QMailFolder &folder,
+ const QString &newPath, const QMailFolderId &newParentId, bool success);
+protected:
+ virtual void handleLogin(ImapStrategyContextBase *context);
+ virtual void handleMove(ImapStrategyContextBase *context);
+ virtual void process(ImapStrategyContextBase *context);
+ QList<QPair<QMailFolderId, QMailFolderId> > _folderNewParents;
+ int _inProgress;
+};
+
class ImapPrepareMessagesStrategy : public ImapStrategy
{
public:
@@ -268,6 +287,7 @@ protected:
virtual void handleCreate(ImapStrategyContextBase *context);
virtual void handleDelete(ImapStrategyContextBase *context);
virtual void handleRename(ImapStrategyContextBase *context);
+ virtual void handleMove(ImapStrategyContextBase *context);
virtual void handleClose(ImapStrategyContextBase *context);
virtual void messageListFolderAction(ImapStrategyContextBase *context);
@@ -837,6 +857,7 @@ public:
ImapCreateFolderStrategy createFolderStrategy;
ImapDeleteFolderStrategy deleteFolderStrategy;
ImapRenameFolderStrategy renameFolderStrategy;
+ ImapMoveFolderStrategy moveFolderStrategy;
ImapSearchMessageStrategy searchMessageStrategy;
void newConnection() { _strategy->clearError(); _strategy->newConnection(this); }
@@ -858,6 +879,9 @@ public:
void folderRenamed(const QMailFolder &folder, const QString &name, bool success) {
_strategy->folderRenamed(this, folder, name, success);
}
+ void folderMoved(const QMailFolder &folder, const QString &name, const QMailFolderId &newParentId, bool success) {
+ _strategy->folderMoved(this, folder, name, newParentId, success);
+ }
QString baseFolder() { return _strategy->baseFolder(); }
ImapStrategy *strategy() const { return _strategy; }
diff --git a/src/tools/messageserver/mailmessageclient.cpp b/src/tools/messageserver/mailmessageclient.cpp
index 37aaeb33..ef0d90ed 100644
--- a/src/tools/messageserver/mailmessageclient.cpp
+++ b/src/tools/messageserver/mailmessageclient.cpp
@@ -81,7 +81,9 @@ MailMessageClient::MailMessageClient(QObject* parent)
adaptor, MESSAGE(folderRenamed(quint64, QMailFolderId)));
connectIpc(this, SIGNAL(folderDeleted(quint64, QMailFolderId)),
adaptor, MESSAGE(folderDeleted(quint64, QMailFolderId)));
- connectIpc(this, SIGNAL(storageActionCompleted(quint64)),
+ connectIpc(this, SIGNAL(folderMoved(quint64, QMailFolderId)),
+ adaptor, MESSAGE(folderMoved(quint64, QMailFolderId)));
+ connectIpc(this, SIGNAL(storageActionCompleted(quint64)),
adaptor, MESSAGE(storageActionCompleted(quint64)));
connectIpc(this, SIGNAL(matchingMessageIds(quint64, QMailMessageIdList)),
adaptor, MESSAGE(matchingMessageIds(quint64, QMailMessageIdList)));
@@ -160,6 +162,8 @@ MailMessageClient::MailMessageClient(QObject* parent)
this, SIGNAL(onlineRenameFolder(quint64,QMailFolderId,QString)));
connectIpc(adaptor, MESSAGE(onlineDeleteFolder(quint64, QMailFolderId)),
this, SIGNAL(onlineDeleteFolder(quint64,QMailFolderId)));
+ connectIpc(adaptor, MESSAGE(onlineMoveFolder(quint64, QMailFolderId, QMailFolderId)),
+ this, SIGNAL(onlineMoveFolder(quint64,QMailFolderId,QMailFolderId)));
connectIpc(adaptor, MESSAGE(cancelTransfer(quint64)),
this, SIGNAL(cancelTransfer(quint64)));
connectIpc(adaptor, MESSAGE(cancelSearch(quint64)),
diff --git a/src/tools/messageserver/mailmessageclient.h b/src/tools/messageserver/mailmessageclient.h
index 7630c188..4437b4dc 100644
--- a/src/tools/messageserver/mailmessageclient.h
+++ b/src/tools/messageserver/mailmessageclient.h
@@ -99,6 +99,7 @@ signals:
void onlineCreateFolder(quint64, const QString &name, const QMailAccountId &accountId, const QMailFolderId &parentId);
void onlineRenameFolder(quint64, const QMailFolderId &folderId, const QString &name);
void onlineDeleteFolder(quint64, const QMailFolderId &folderId);
+ void onlineMoveFolder(quint64, const QMailFolderId &folderId, const QMailFolderId &newParentId);
void cancelTransfer(quint64);
@@ -135,7 +136,8 @@ signals:
void folderCreated(quint64, const QMailFolderId&);
void folderRenamed(quint64, const QMailFolderId&);
void folderDeleted(quint64, const QMailFolderId&);
-
+ void folderMoved(quint64, const QMailFolderId&);
+
void storageActionCompleted(quint64);
void matchingMessageIds(quint64, const QMailMessageIdList&);
diff --git a/src/tools/messageserver/messageserver.cpp b/src/tools/messageserver/messageserver.cpp
index 02d1e0b7..e6adea2e 100644
--- a/src/tools/messageserver/messageserver.cpp
+++ b/src/tools/messageserver/messageserver.cpp
@@ -130,6 +130,8 @@ MessageServer::MessageServer(QObject *parent)
client, SIGNAL(folderRenamed(quint64, QMailFolderId)));
connect(handler, SIGNAL(folderDeleted(quint64, QMailFolderId)),
client, SIGNAL(folderDeleted(quint64, QMailFolderId)));
+ connect(handler, SIGNAL(folderMoved(quint64, QMailFolderId)),
+ client, SIGNAL(folderMoved(quint64, QMailFolderId)));
connect(handler, SIGNAL(storageActionCompleted(quint64)),
client, SIGNAL(storageActionCompleted(quint64)));
connect(handler, SIGNAL(matchingMessageIds(quint64, QMailMessageIdList)),
@@ -219,6 +221,8 @@ MessageServer::MessageServer(QObject *parent)
handler, SLOT(onlineRenameFolder(quint64, QMailFolderId, QString)));
connect(client, SIGNAL(onlineDeleteFolder(quint64, QMailFolderId)),
handler, SLOT(onlineDeleteFolder(quint64, QMailFolderId)));
+ connect(client, SIGNAL(onlineMoveFolder(quint64, QMailFolderId, QMailFolderId)),
+ handler, SLOT(onlineMoveFolder(quint64, QMailFolderId, QMailFolderId)));
connect(client, SIGNAL(cancelTransfer(quint64)),
handler, SLOT(cancelTransfer(quint64)));
connect(client, SIGNAL(protocolRequest(quint64, QMailAccountId, QString, QVariant)),
diff --git a/src/tools/messageserver/servicehandler.cpp b/src/tools/messageserver/servicehandler.cpp
index 8c813091..86cc5810 100644
--- a/src/tools/messageserver/servicehandler.cpp
+++ b/src/tools/messageserver/servicehandler.cpp
@@ -2561,6 +2561,41 @@ bool ServiceHandler::dispatchOnlineDeleteFolder(quint64 action, const QByteArray
}
}
+void ServiceHandler::onlineMoveFolder(quint64 action, const QMailFolderId &folderId, const QMailFolderId &newParentId)
+{
+ if (folderId.isValid()) {
+ QSet<QMailAccountId> accounts = folderAccount(folderId);
+ QSet<QMailMessageService *> sources(sourceServiceSet(accounts));
+ enqueueRequest(action, serialize(folderId, newParentId), sources, &ServiceHandler::dispatchOnlineMoveFolder, &ServiceHandler::storageActionCompleted, MoveFolderRequestType);
+ } else {
+ reportFailure(action, QMailServiceAction::Status::ErrInvalidData, tr("Unable to move invalid folder"));
+ }
+}
+
+bool ServiceHandler::dispatchOnlineMoveFolder(quint64 action, const QByteArray &data)
+{
+ QMailFolderId folderId;
+ QMailFolderId newParentId;
+
+ deserialize(data, folderId, newParentId);
+
+ if (QMailMessageSource *source = accountSource(QMailFolder(folderId).parentAccountId())) {
+ bool success(sourceService.value(source)->usesConcurrentActions()
+ ? source->moveFolder(folderId, newParentId, action)
+ : source->moveFolder(folderId, newParentId));
+ if (success) {
+ return true;
+ } else {
+ qWarning() << "Unable to service request to move folder id:" << folderId;
+ return false;
+ }
+
+ } else {
+ reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), QMailFolder(folderId).parentAccountId());
+ return false;
+ }
+}
+
void ServiceHandler::searchMessages(quint64 action, const QMailMessageKey& filter, const QString& bodyText, QMailSearchAction::SearchSpecification spec, const QMailMessageSortKey &sort)
{
searchMessages(action, filter, bodyText, spec, 0, sort, NoLimit);
diff --git a/src/tools/messageserver/servicehandler.h b/src/tools/messageserver/servicehandler.h
index 77534443..b2c67dca 100644
--- a/src/tools/messageserver/servicehandler.h
+++ b/src/tools/messageserver/servicehandler.h
@@ -91,6 +91,7 @@ public slots:
void onlineCreateFolder(quint64 action, const QString &name, const QMailAccountId &accountId, const QMailFolderId &parentId);
void onlineRenameFolder(quint64 action, const QMailFolderId &folderId, const QString &name);
void onlineDeleteFolder(quint64 action, const QMailFolderId &folderId);
+ void onlineMoveFolder(quint64 action, const QMailFolderId &folderId, const QMailFolderId &newParentId);
void cancelTransfer(quint64 action);
void searchMessages(quint64 action, const QMailMessageKey &filter, const QString &bodyText, QMailSearchAction::SearchSpecification spec, const QMailMessageSortKey &sort);
void searchMessages(quint64 action, const QMailMessageKey &filter, const QString &bodyText, QMailSearchAction::SearchSpecification spec, quint64 limit, const QMailMessageSortKey &sort);
@@ -126,6 +127,7 @@ signals:
void folderCreated(quint64 action, const QMailFolderId&);
void folderRenamed(quint64 action, const QMailFolderId&);
void folderDeleted(quint64 action, const QMailFolderId&);
+ void folderMoved(quint64 action, const QMailFolderId&);
void storageActionCompleted(quint64 action);
@@ -265,6 +267,7 @@ private:
bool dispatchOnlineCreateFolder(quint64 action, const QByteArray &data);
bool dispatchOnlineDeleteFolder(quint64 action, const QByteArray &data);
bool dispatchOnlineRenameFolder(quint64 action, const QByteArray &data);
+ bool dispatchOnlineMoveFolder(quint64 action, const QByteArray &data);
bool dispatchSearchMessages(quint64 action, const QByteArray &data);
bool dispatchProtocolRequest(quint64 action, const QByteArray &data);