diff options
| author | Gareth Pethig <gareth.pethig@nokia.com> | 2009-05-15 20:34:20 +1000 |
|---|---|---|
| committer | Gareth Pethig <gareth.pethig@nokia.com> | 2009-05-15 20:34:20 +1000 |
| commit | 1c9dea79bee0fca57a037858b15db7418bc7cade (patch) | |
| tree | 2884f94a4eb875dd9e2cbe46586dc649015867da | |
| parent | 38206e96976cbed50359d915c5266eb1254c1c94 (diff) | |
| parent | 9dfb47145caf4b82bda7235d8cac2c711b083159 (diff) | |
Merge branch 'qmf-1.0' into pkg
66 files changed, 1496 insertions, 776 deletions
diff --git a/src/applications/qtmail/emailclient.cpp b/src/applications/qtmail/emailclient.cpp index b341ae38..575a2bee 100644 --- a/src/applications/qtmail/emailclient.cpp +++ b/src/applications/qtmail/emailclient.cpp @@ -44,6 +44,7 @@ #include <qmailnamespace.h> #include <QSplitter> #include <QListView> +#include <QToolBar> static const int defaultWidth = 1024; static const int defaultHeight = 768; @@ -282,7 +283,7 @@ void MessageUiBase::presentMessage(const QMailMessageId &id, QMailViewerFactory: WriteMail* MessageUiBase::createWriteMailWidget() { WriteMail* writeMail = new WriteMail(this); - writeMail->setGeometry(0,0,400,400); + writeMail->setGeometry(0,0,500,400); writeMail->setObjectName("write-mail"); connect(writeMail, SIGNAL(enqueueMail(QMailMessage)), this, SLOT(enqueueMail(QMailMessage))); @@ -650,6 +651,14 @@ void EmailClient::initActions() this,SLOT(quit())); connect(fileMenu, SIGNAL(aboutToShow()), this, SLOT(updateActions())); + QToolBar* toolBar = mw->toolBar(); + toolBar->addAction( composeButton ); + toolBar->addAction( getMailButton ); + toolBar->addAction( cancelButton ); + toolBar->addAction( searchButton ); + toolBar->addSeparator(); + toolBar->addAction( settingsAction ); + updateGetMailButton(); folderView()->addAction( synchronizeAction ); @@ -702,7 +711,9 @@ void EmailClient::delayedInit() // Whenever these actions occur, we need to reload accounts that may have changed connect(store, SIGNAL(accountsAdded(QMailAccountIdList)), this, SLOT(accountsAdded(QMailAccountIdList))); + connect(store, SIGNAL(accountsAdded(QMailAccountIdList)), this, SLOT(updateActions())); connect(store, SIGNAL(accountsRemoved(QMailAccountIdList)), this, SLOT(accountsRemoved(QMailAccountIdList))); + connect(store, SIGNAL(accountsRemoved(QMailAccountIdList)), this, SLOT(updateActions())); connect(store, SIGNAL(accountsUpdated(QMailAccountIdList)), this, SLOT(accountsUpdated(QMailAccountIdList))); // We need to detect when messages are marked as deleted during downloading @@ -713,6 +724,7 @@ void EmailClient::delayedInit() // Ideally would make actions functions methods and delay their // creation until context menu is shown. initActions(); + updateActions(); QTimer::singleShot(0, this, SLOT(openFiles()) ); } @@ -787,6 +799,10 @@ void EmailClient::cancelOperation() retrievalAction->cancelOperation(); setRetrievalInProgress( false ); } + + if (flagRetrievalAction->activity() == QMailServiceAction::InProgress) { + flagRetrievalAction->cancelOperation(); + } } /* Enqueue mail must always store the mail in the outbox */ @@ -1819,7 +1835,11 @@ void EmailClient::composeActivated() { delayedInit(); if(writeMailWidget()->prepareComposer()) + { writeMailWidget()->show(); + writeMailWidget()->raise(); + writeMailWidget()->activateWindow(); + } } void EmailClient::sendMessageTo(const QMailAddress &address, QMailMessage::MessageType type) @@ -1993,6 +2013,7 @@ void EmailClient::transferStatusUpdate(int status) // UI updates setActionVisible(cancelButton, transferStatus != Inactive); updateGetMailButton(); + updateActions(); } } diff --git a/src/applications/qtmail/qtmailwindow.cpp b/src/applications/qtmail/qtmailwindow.cpp index 53a0b6c0..a634e3b8 100644 --- a/src/applications/qtmail/qtmailwindow.cpp +++ b/src/applications/qtmail/qtmailwindow.cpp @@ -21,6 +21,8 @@ #include <QStatusBar> #include <QMenuBar> #include <QApplication> +#include <QToolBar> +#include <QDesktopWidget> QTMailWindow *QTMailWindow::self = 0; @@ -53,6 +55,9 @@ void QTMailWindow::init() m_contextMenu = file; + m_toolBar = new QToolBar(this); + addToolBar(m_toolBar); + // Add the email client to our central widget stack emailClient = new EmailClient(views); @@ -98,6 +103,58 @@ void QTMailWindow::setVisible(bool visible) if (noShow && visible) return; + QPoint p(0, 0); + int extraw = 0, extrah = 0, scrn = 0; + QWidget* w = 0; + if (w) + w = w->window(); + QRect desk; + if (w) { + scrn = QApplication::desktop()->screenNumber(w); + } else if (QApplication::desktop()->isVirtualDesktop()) { + scrn = QApplication::desktop()->screenNumber(QCursor::pos()); + } else { + scrn = QApplication::desktop()->screenNumber(this); + } + desk = QApplication::desktop()->availableGeometry(scrn); + + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) { + QWidget * current = list.at(i); + if (current->isVisible()) { + int framew = current->geometry().x() - current->x(); + int frameh = current->geometry().y() - current->y(); + + extraw = qMax(extraw, framew); + extrah = qMax(extrah, frameh); + } + } + + // sanity check for decoration frames. With embedding, we + // might get extraordinary values + if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) { + extrah = 40; + extraw = 10; + } + + p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2); + + // p = origin of this + p = QPoint(p.x()-width()/2 - extraw, + p.y()-height()/2 - extrah); + + + if (p.x() + extraw + width() > desk.x() + desk.width()) + p.setX(desk.x() + desk.width() - width() - extraw); + if (p.x() < desk.x()) + p.setX(desk.x()); + + if (p.y() + extrah + height() > desk.y() + desk.height()) + p.setY(desk.y() + desk.height() - height() - extrah); + if (p.y() < desk.y()) + p.setY(desk.y()); + + move(p); QWidget::setVisible(visible); } @@ -111,6 +168,11 @@ QMenu* QTMailWindow::contextMenu() const return m_contextMenu; } +QToolBar* QTMailWindow::toolBar() const +{ + return m_toolBar; +} + QTMailWindow* QTMailWindow::singleton() { return self; diff --git a/src/applications/qtmail/qtmailwindow.h b/src/applications/qtmail/qtmailwindow.h index d68f4b1a..7841c359 100644 --- a/src/applications/qtmail/qtmailwindow.h +++ b/src/applications/qtmail/qtmailwindow.h @@ -21,6 +21,7 @@ class StatusDisplay; class QStackedWidget; class EmailClient; class QMenu; +class QToolBar; class QTMailWindow : public QMainWindow { @@ -36,8 +37,8 @@ public: void setVisible(bool visible); QWidget* currentWidget() const; - QMenu* contextMenu() const; + QToolBar* toolBar() const; public slots: void closeEvent(QCloseEvent *e); @@ -54,6 +55,7 @@ protected: private: QMenu* m_contextMenu; + QToolBar* m_toolBar; }; #endif diff --git a/src/applications/qtmail/writemail.cpp b/src/applications/qtmail/writemail.cpp index f37e9b4c..ad326057 100644 --- a/src/applications/qtmail/writemail.cpp +++ b/src/applications/qtmail/writemail.cpp @@ -118,7 +118,7 @@ void WriteMail::init() m_toolbar->addAction(m_draftAction); m_toolbar->addSeparator(); - setWindowTitle(tr("Composer")); + setWindowTitle(tr("Compose")); } bool WriteMail::sendStage() @@ -589,6 +589,31 @@ bool WriteMail::forcedClosure() return false; } +void WriteMail::setVisible(bool visible) +{ + if (visible) { + + //center the window on the parent + QWidget* w = qobject_cast<QWidget*>(parent()); + + QPoint p; + + if (w) { + // Use mapToGlobal rather than geometry() in case w might + // be embedded in another application + QPoint pp = w->mapToGlobal(QPoint(0,0)); + p = QPoint(pp.x() + w->width()/2, + pp.y() + w->height()/ 2); + } + + p = QPoint(p.x()-width()/2, + p.y()-height()/2); + + move(p); + } + QWidget::setVisible(visible); +} + bool WriteMail::largeAttachments() { static int limit = 0; diff --git a/src/applications/qtmail/writemail.h b/src/applications/qtmail/writemail.h index ad68a360..ccb22892 100644 --- a/src/applications/qtmail/writemail.h +++ b/src/applications/qtmail/writemail.h @@ -40,6 +40,8 @@ public: QString composer() const; bool forcedClosure(); + void setVisible(bool visible); + public slots: bool saveChangesOnRequest(); bool prepareComposer( QMailMessage::MessageType = QMailMessage::AnyType); diff --git a/src/libraries/messageserver/qmailauthenticator.cpp b/src/libraries/messageserver/qmailauthenticator.cpp index e0354069..4499c3a9 100644 --- a/src/libraries/messageserver/qmailauthenticator.cpp +++ b/src/libraries/messageserver/qmailauthenticator.cpp @@ -13,7 +13,6 @@ /*! \class QMailAuthenticator - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary diff --git a/src/libraries/messageserver/qmailmessageclassifier.cpp b/src/libraries/messageserver/qmailmessageclassifier.cpp index 5e41839e..9b7ccabf 100644 --- a/src/libraries/messageserver/qmailmessageclassifier.cpp +++ b/src/libraries/messageserver/qmailmessageclassifier.cpp @@ -15,7 +15,6 @@ /*! \class QMailMessageClassifier - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary diff --git a/src/libraries/messageserver/qmailmessageservice.cpp b/src/libraries/messageserver/qmailmessageservice.cpp index 47e604f0..81244442 100644 --- a/src/libraries/messageserver/qmailmessageservice.cpp +++ b/src/libraries/messageserver/qmailmessageservice.cpp @@ -62,7 +62,6 @@ QMailMessageServicePlugin *mapping(const QString &key) /*! \class QMailMessageServiceFactory - \inpublicgroup QtMessagingModule \ingroup libmessageserver \brief The QMailMessageServiceFactory class creates objects implementing the QMailMessageService interface. @@ -153,7 +152,6 @@ QMailMessageServiceConfigurator *QMailMessageServiceFactory::createServiceConfig /*! \class QMailMessageServicePluginInterface - \inpublicgroup QtMessagingModule \ingroup libmessageserver \brief The QMailMessageServicePluginInterface class defines the interface to plugins that provide messaging services. @@ -199,7 +197,6 @@ QMailMessageServiceConfigurator *QMailMessageServicePluginInterface::createServi /*! \class QMailMessageServicePlugin - \inpublicgroup QtMessagingModule \ingroup libmessageserver \brief The QMailMessageServicePlugin class defines a base class for implementing messaging service plugins. @@ -361,7 +358,6 @@ QMailMessageSourcePrivate::QMailMessageSourcePrivate(QMailMessageService *servic /*! \class QMailMessageSource - \inpublicgroup QtMessagingModule \ingroup libmessageserver \brief The QMailMessageSource class defines the interface to objects that provide access to externally sourced @@ -403,9 +399,16 @@ QMailStore::MessageRemovalOption QMailMessageSource::messageRemovalOption() cons /*! Invoked by the message server to initiate a folder listing operation. - Retrieve folders available for the account \a accountId; if \a folderId is valid, folders - within that folder should be retieved, otherwise in the root folder of the account. - If \a descending is true, also retrieve folders located by descending the folder hierarchy. + Retrieve the set of folders available for the account \a accountId. + If \a folderId is valid, only the identified folder is searched for child folders; + otherwise the search begins at the root of the account. If \a descending is true, + the search should also recursively search for child folders within folders + discovered during the search. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for each + folder that is searched for child folders; these properties need not be updated + for folders that are merely discovered by searching. Return true if an operation is initiated. @@ -424,17 +427,26 @@ bool QMailMessageSource::retrieveFolderList(const QMailAccountId &accountId, con /*! Invoked by the message server to initiate a message listing operation. - Retrieve messages available for the account \a accountId; - if \a folderId is valid, then only messages within that folder should be retrieved; otherwise - messages within all folders in the account should be retrieved. If a folder messages are being - retrieved from contains at least \a minimum messages then the messageserver should ensure that at - least \a minimum messages are available from the mail store for that folder; otherwise if the - folder contains less than \a minimum messages the messageserver should ensure all the messages for - that folder are available from the mail store. + Retrieve the list of messages available for the account \a accountId. + If \a folderId is valid, then only messages within that folder should be retrieved; otherwise + messages within all folders in the account should be retrieved. If \a minimum is non-zero, + then that value will be used to restrict the number of messages to be retrieved from + each folder; otherwise, all messages will be retrieved. + + If \a sort is not empty, reported the discovered messages in the ordering indicated by the + sort criterion, if possible. Message sources are not required to support this facility. + + If a folder messages are being retrieved from contains at least \a minimum messages then the + messageserver should ensure that at least \a minimum messages are available from the mail + store for that folder; otherwise if the folder contains less than \a minimum messages the + messageserver should ensure all the messages for that folder are available from the mail store. + If a folder has messages locally available, then all previously undiscovered messages should be + retrieved for that folder, even if that number exceeds \a minimum. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for each folder + from which messages are retrieved. - If \a sort is not empty, messages should be discovered by locating messages in the - ordering indicated by the sort criterion, if possible. - New messages should be added to the mail store in meta data form as they are discovered, and marked with the \l QMailMessage::New status flag. Messages that are present in the mail store but found to be no longer available should be marked with the @@ -470,6 +482,10 @@ bool QMailMessageSource::retrieveMessageList(const QMailAccountId &accountId, co If \a spec is \l QMailRetrievalAction::Content, then the message server should retrieve the entirety of each message listed in \a ids. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for each folder + from which messages are retrieved. Return true if an operation is initiated. */ @@ -486,6 +502,10 @@ bool QMailMessageSource::retrieveMessages(const QMailMessageIdList &ids, QMailRe Invoked by the message server to initiate a message part retrieval operation. Retrieve the content of the message part indicated by the location \a partLocation. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for the folder + from which the part is retrieved. Return true if an operation is initiated. */ @@ -503,6 +523,10 @@ bool QMailMessageSource::retrieveMessagePart(const QMailMessagePart::Location &p Retrieve a portion of the content of the message identified by \a messageId, ensuring that at least \a minimum bytes are available in the mail store. + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for the folder + from which the message is retrieved. + Return true if an operation is initiated. */ bool QMailMessageSource::retrieveMessageRange(const QMailMessageId &messageId, uint minimum) @@ -520,6 +544,10 @@ bool QMailMessageSource::retrieveMessageRange(const QMailMessageId &messageId, u Retrieve a portion of the content of the message part indicated by the location \a partLocation, ensuring that at least \a minimum bytes are available in the mail store. + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for the folder + from which the part is retrieved. + Return true if an operation is initiated. */ bool QMailMessageSource::retrieveMessagePartRange(const QMailMessagePart::Location &partLocation, uint minimum) @@ -536,6 +564,16 @@ bool QMailMessageSource::retrieveMessagePartRange(const QMailMessagePart::Locati Retrieve all folders and meta data for all messages available for the account \a accountId. + All folders within the account should be discovered and searched for child folders. + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for each folder + in the account. + + New messages should be added to the mail store in meta data form as they are discovered, + and marked with the \l QMailMessage::New status flag. Messages that are present + in the mail store but found to be no longer available should be marked with the + \l QMailMessage::Removed status flag. + Return true if an operation is initiated. \sa retrieveFolderList(), retrieveMessageList(), synchronize() @@ -574,6 +612,15 @@ bool QMailMessageSource::exportUpdates(const QMailAccountId &accountId) Newly discovered messages should have their meta data retrieved, and local changes to message status should be exported to the external server. + New messages should be added to the mail store in meta data form as they are discovered, + and marked with the \l QMailMessage::New status flag. Messages that are present + in the mail store but found to be no longer available should be marked with the + \l QMailMessage::Removed status flag. + + The folder structure of the account should be synchronized with that available from + the external service. The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties should be updated for each folder. + Return true if an operation is initiated. \sa retrieveAll(), exportUpdates() @@ -878,7 +925,6 @@ QMailMessageSinkPrivate::QMailMessageSinkPrivate(QMailMessageService *service) /*! \class QMailMessageSink - \inpublicgroup QtMessagingModule \ingroup libmessageserver \brief The QMailMessageSink class defines the interface to objects that provide external message transmission @@ -939,7 +985,6 @@ void QMailMessageSink::notImplemented() /*! \class QMailMessageService - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary @@ -955,6 +1000,12 @@ void QMailMessageSink::notImplemented() information about the actions of messaging service components. It also provides the \l{QMailMessageService::source()}{source} and \l{QMailMessageService::sink()}{sink} functions that the message server uses to acquire access to the functionality that the service may implement. + + Subclasses of QMailMessageService are instantiated by the message server process, one for each + enabled account that is configured to use that service. The QMailMessageService interface does + not cater for concurrent actions; each instance may only service a single request at any given + time. The message server process provides request queueing so that QMailMessageService objects + see only a sequential series of requests. */ /*! @@ -1114,6 +1165,9 @@ void QMailMessageService::updateStatus(int code, const QString &text, const QMai } else { static ErrorMap socketErrorMap(socketErrorInit()); + // Code has been offset by +2 on transmit to normalise range + code -= 2; + // See if we can convert the error code into a system error message QString message(text); decorate(&message, code, (ErrorSet() << socketErrorMap)); @@ -1125,7 +1179,6 @@ void QMailMessageService::updateStatus(int code, const QString &text, const QMai /*! \class QMailMessageServiceEditor - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary @@ -1159,7 +1212,6 @@ QMailMessageServiceEditor::~QMailMessageServiceEditor() /*! \class QMailMessageServiceConfigurator - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary diff --git a/src/libraries/messageserver/qmailserviceconfiguration.cpp b/src/libraries/messageserver/qmailserviceconfiguration.cpp index 8058090f..a8a5f1c4 100644 --- a/src/libraries/messageserver/qmailserviceconfiguration.cpp +++ b/src/libraries/messageserver/qmailserviceconfiguration.cpp @@ -14,7 +14,6 @@ /*! \class QMailServiceConfiguration - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary diff --git a/src/libraries/messageserver/qmailstoreaccountfilter.cpp b/src/libraries/messageserver/qmailstoreaccountfilter.cpp index 1a574ea4..01bdeb1c 100644 --- a/src/libraries/messageserver/qmailstoreaccountfilter.cpp +++ b/src/libraries/messageserver/qmailstoreaccountfilter.cpp @@ -366,7 +366,6 @@ void QMailStoreAccountFilterPrivate::incrementConnectionCount(const char *signal /*! \class QMailStoreAccountFilter - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary diff --git a/src/libraries/messageserver/qmailtransport.cpp b/src/libraries/messageserver/qmailtransport.cpp index 44ca4592..9aa41100 100644 --- a/src/libraries/messageserver/qmailtransport.cpp +++ b/src/libraries/messageserver/qmailtransport.cpp @@ -90,7 +90,6 @@ qint64 QMailTransport::Socket::bytesSinceMark() const /*! \class QMailTransport - \inpublicgroup QtMessagingModule \ingroup libmessageserver \preliminary @@ -410,8 +409,11 @@ void QMailTransport::errorHandling(int status, QString msg) mConnected = false; mInUse = false; mSocket->abort(); + emit updateStatus(tr("Error occurred")); - emit errorOccurred(status, msg); + + // Socket errors run from -1; offset this value by +2 + emit errorOccurred(status + 2, msg); } /*! \internal */ diff --git a/src/libraries/qmfutil/qmailcomposer.cpp b/src/libraries/qmfutil/qmailcomposer.cpp index 4d49da2a..dd4c3a0c 100644 --- a/src/libraries/qmfutil/qmailcomposer.cpp +++ b/src/libraries/qmfutil/qmailcomposer.cpp @@ -57,7 +57,6 @@ static QMailComposerInterface* mapping(const QString& key) /*! \class QMailComposerInterface - \inpublicgroup QtMessagingModule \ingroup qmfutil \brief The QMailComposerInterface class defines the interface to objects that can compose a mail message. @@ -280,7 +279,6 @@ QString QMailComposerInterface::status() const /*! \class QMailComposerFactory - \inpublicgroup QtMessagingModule \ingroup qmfutil \brief The QMailComposerFactory class creates objects implementing the QMailComposerInterface interface. diff --git a/src/libraries/qmfutil/qmailmessagedelegate.cpp b/src/libraries/qmfutil/qmailmessagedelegate.cpp index c3d72665..1baabd97 100644 --- a/src/libraries/qmfutil/qmailmessagedelegate.cpp +++ b/src/libraries/qmfutil/qmailmessagedelegate.cpp @@ -109,7 +109,6 @@ public: /*! \class QMailMessageDelegate - \inpublicgroup QtMessagingModule \ingroup qmfutil \preliminary @@ -387,7 +386,6 @@ public: /*! \class QtopiaHomeMailMessageDelegate - \inpublicgroup QtMessagingModule \ingroup qmfutil \preliminary diff --git a/src/libraries/qmfutil/qmailviewer.cpp b/src/libraries/qmfutil/qmailviewer.cpp index e4d1cc8d..222fc96c 100644 --- a/src/libraries/qmfutil/qmailviewer.cpp +++ b/src/libraries/qmfutil/qmailviewer.cpp @@ -54,7 +54,6 @@ static QMailViewerInterface* mapping(const QString& key) /*! \class QMailViewerInterface - \inpublicgroup QtMessagingModule \ingroup qmfutil \brief The QMailViewerInterface class defines the interface to objects that can display a mail message. @@ -275,7 +274,6 @@ void QMailViewerInterface::setResource(const QUrl& name, QVariant value) /*! \class QMailViewerFactory - \inpublicgroup QtMessagingModule \ingroup qmfutil \brief The QMailViewerFactory class creates objects implementing the QMailViewerInterface interface. diff --git a/src/libraries/qtopiamail/CHANGES.qdoc b/src/libraries/qtopiamail/CHANGES.qdoc index 25cc0356..1d975061 100644 --- a/src/libraries/qtopiamail/CHANGES.qdoc +++ b/src/libraries/qtopiamail/CHANGES.qdoc @@ -13,6 +13,19 @@ Changes since the development preview release on 03/04/09: 1. Added 'QMailFolder::serverUndiscoveredCount() const' and 'QMailFolder::setServerUndiscoveredCount()'. +2. Added 'QMailStore::retrievalInProgress()', + 'QMailStore::setRetrievalInProgress()', + 'QMailStore::transmissionInProgress()' and + 'QMailStore::setTransmissionInProgress()'. + +3. Replaced 'QMailStore::initialized() const' and + 'QMailStore::storeInitialized()' with + 'QMailStore::InitializationState QMailStore::initializationState()'. + +4. Changed 'QMailMessageKey::status(...)', + 'QMailFolderKey::status(...)' and + 'QMailMessageKey::status(...)' so that the overload taking a QMailDataComparator::InclusionComparator has the default argument. + ***************************************************************************** diff --git a/src/libraries/qtopiamail/qmailaccount.cpp b/src/libraries/qtopiamail/qmailaccount.cpp index d784070a..22696965 100644 --- a/src/libraries/qtopiamail/qmailaccount.cpp +++ b/src/libraries/qtopiamail/qmailaccount.cpp @@ -132,7 +132,6 @@ private: /*! \class QMailAccount - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmailaccountconfiguration.cpp b/src/libraries/qtopiamail/qmailaccountconfiguration.cpp index d8894be2..ad903fce 100644 --- a/src/libraries/qtopiamail/qmailaccountconfiguration.cpp +++ b/src/libraries/qtopiamail/qmailaccountconfiguration.cpp @@ -74,7 +74,6 @@ private: /*! \class QMailAccountConfiguration::ServiceConfiguration - \inpublicgroup QtMessagingModule \preliminary \brief The ServiceConfiguration class provides access to the configuration parameters @@ -227,7 +226,6 @@ QMailAccountConfiguration::ServiceConfiguration &QMailAccountConfigurationPrivat /*! \class QMailAccountConfiguration - \inpublicgroup QtMessagingModule \preliminary \brief The QMailAccountConfiguration class contains the configuration parameters of an account. diff --git a/src/libraries/qtopiamail/qmailaccountkey.cpp b/src/libraries/qtopiamail/qmailaccountkey.cpp index c309e830..29310c54 100644 --- a/src/libraries/qtopiamail/qmailaccountkey.cpp +++ b/src/libraries/qtopiamail/qmailaccountkey.cpp @@ -17,7 +17,6 @@ using namespace QMailDataComparator; /*! \class QMailAccountKey - \inpublicgroup QtMessagingModule \preliminary \brief The QMailAccountKey class defines the parameters used for querying a subset of diff --git a/src/libraries/qtopiamail/qmailaccountkey.h b/src/libraries/qtopiamail/qmailaccountkey.h index 8ea46771..208188fa 100644 --- a/src/libraries/qtopiamail/qmailaccountkey.h +++ b/src/libraries/qtopiamail/qmailaccountkey.h @@ -89,8 +89,8 @@ public: static QMailAccountKey fromAddress(const QString &value, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); static QMailAccountKey fromAddress(const QString &value, QMailDataComparator::InclusionComparator cmp); - static QMailAccountKey status(quint64 mask, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); - static QMailAccountKey status(quint64 mask, QMailDataComparator::InclusionComparator cmp); + static QMailAccountKey status(quint64 mask, QMailDataComparator::InclusionComparator cmp = QMailDataComparator::Includes); + static QMailAccountKey status(quint64 mask, QMailDataComparator::EqualityComparator cmp); static QMailAccountKey customField(const QString &name, QMailDataComparator::PresenceComparator cmp = QMailDataComparator::Present); static QMailAccountKey customField(const QString &name, const QString &value, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); diff --git a/src/libraries/qtopiamail/qmailaccountlistmodel.cpp b/src/libraries/qtopiamail/qmailaccountlistmodel.cpp index 9fe8bc5a..ca8fbfe3 100644 --- a/src/libraries/qtopiamail/qmailaccountlistmodel.cpp +++ b/src/libraries/qtopiamail/qmailaccountlistmodel.cpp @@ -124,7 +124,6 @@ QMailAccountIdList::iterator QMailAccountListModelPrivate::lowerBound(const QMai /*! \class QMailAccountListModel - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmailaccountsortkey.cpp b/src/libraries/qtopiamail/qmailaccountsortkey.cpp index 4c836050..900f01c7 100644 --- a/src/libraries/qtopiamail/qmailaccountsortkey.cpp +++ b/src/libraries/qtopiamail/qmailaccountsortkey.cpp @@ -13,7 +13,6 @@ /*! \class QMailAccountSortKey - \inpublicgroup QtMessagingModule \preliminary \brief The QMailAccountSortKey class defines the parameters used for sorting a subset of diff --git a/src/libraries/qtopiamail/qmailaddress.cpp b/src/libraries/qtopiamail/qmailaddress.cpp index 83db7913..3fdaf0ae 100644 --- a/src/libraries/qtopiamail/qmailaddress.cpp +++ b/src/libraries/qtopiamail/qmailaddress.cpp @@ -764,7 +764,6 @@ void QMailAddressPrivate::deserialize(Stream &stream) /*! \class QMailAddress - \inpublicgroup QtMessagingModule \brief The QMailAddress class provides an interface for manipulating message address strings. \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmailcodec.cpp b/src/libraries/qtopiamail/qmailcodec.cpp index 7ce84e24..2066a08d 100644 --- a/src/libraries/qtopiamail/qmailcodec.cpp +++ b/src/libraries/qtopiamail/qmailcodec.cpp @@ -25,7 +25,6 @@ int QTOPIAMAIL_EXPORT QuotedPrintableMaxLineLength = 74; /*! \class QMailCodec - \inpublicgroup QtMessagingModule \preliminary \brief The QMailCodec class provides mechanisms for encoding and decoding between 7-bit ASCII strings @@ -363,7 +362,6 @@ static inline unsigned char base64Index(const char ascii) /*! \class QMailBase64Codec - \inpublicgroup QtMessagingModule \preliminary \brief The QMailBase64Codec class encodes or decodes between 8-bit data and 7-bit ASCII, using the Base64 @@ -663,7 +661,6 @@ static inline unsigned char decodeCharacter(unsigned char value) /*! \class QMailQuotedPrintableCodec - \inpublicgroup QtMessagingModule \preliminary \brief The QMailQuotedPrintableCodec class encodes or decodes between 8-bit data and 7-bit ASCII, @@ -935,7 +932,6 @@ static void writeStream(QDataStream& out, const char* it, int length) /*! \class QMailPassThroughCodec - \inpublicgroup QtMessagingModule \preliminary \brief The QMailPassThroughCodec class uses the QMailCodec interface to move data between streams @@ -989,7 +985,6 @@ void QMailPassThroughCodec::decodeChunk(QDataStream& out, const char* it, int le /*! \class QMailLineEndingCodec - \inpublicgroup QtMessagingModule \preliminary \brief The QMailLineEndingCodec class encodes textual data to use CR/LF line endings required for SMTP transmission. diff --git a/src/libraries/qtopiamail/qmailcontentmanager.cpp b/src/libraries/qtopiamail/qmailcontentmanager.cpp index 3bd453f8..0e44b0af 100644 --- a/src/libraries/qtopiamail/qmailcontentmanager.cpp +++ b/src/libraries/qtopiamail/qmailcontentmanager.cpp @@ -53,7 +53,6 @@ QMailContentManager *mapping(const QString &scheme) /*! \class QMailContentManagerFactory - \inpublicgroup QtMessagingModule \brief The QMailContentManagerFactory class creates objects implementing the QMailContentManager interface. \ingroup messaginglibrary @@ -125,7 +124,6 @@ void QMailContentManagerFactory::clearContent() /*! \class QMailContentManagerPluginInterface - \inpublicgroup QtMessagingModule \brief The QMailContentManagerPluginInterface class defines the interface to plugins that provide message content management facilities. \ingroup messaginglibrary @@ -151,7 +149,6 @@ void QMailContentManagerFactory::clearContent() /*! \class QMailContentManagerPlugin - \inpublicgroup QtMessagingModule \brief The QMailContentManagerPlugin class defines a base class for implementing message content manager plugins. \ingroup messaginglibrary @@ -188,7 +185,6 @@ QStringList QMailContentManagerPlugin::keys() const /*! \class QMailContentManager - \inpublicgroup QtMessagingModule \brief The QMailContentManager class defines the interface to objects that provide a storage facility for message content. \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmaildatacomparator.cpp b/src/libraries/qtopiamail/qmaildatacomparator.cpp index 10825958..4cf3fc7d 100644 --- a/src/libraries/qtopiamail/qmaildatacomparator.cpp +++ b/src/libraries/qtopiamail/qmaildatacomparator.cpp @@ -10,7 +10,6 @@ /*! \namespace QMailDataComparator - \inpublicgroup QtMessagingModule \ingroup messaginglibrary \brief The QMailDataComparator namespace contains types used in specifying the comparison diff --git a/src/libraries/qtopiamail/qmailfolder.cpp b/src/libraries/qtopiamail/qmailfolder.cpp index 9c386e00..3cda844f 100644 --- a/src/libraries/qtopiamail/qmailfolder.cpp +++ b/src/libraries/qtopiamail/qmailfolder.cpp @@ -107,7 +107,6 @@ private: /*! \class QMailFolder - \inpublicgroup QtMessagingModule \preliminary \brief The QMailFolder class represents a folder for mail messages in the mail store. diff --git a/src/libraries/qtopiamail/qmailfolderkey.cpp b/src/libraries/qtopiamail/qmailfolderkey.cpp index c60df4b3..a60c506e 100644 --- a/src/libraries/qtopiamail/qmailfolderkey.cpp +++ b/src/libraries/qtopiamail/qmailfolderkey.cpp @@ -18,7 +18,6 @@ using namespace QMailKey; /*! \class QMailFolderKey - \inpublicgroup QtMessagingModule \preliminary \brief The QMailFolderKey class defines the parameters used for querying a subset of diff --git a/src/libraries/qtopiamail/qmailfolderkey.h b/src/libraries/qtopiamail/qmailfolderkey.h index 6993ca05..79e38d53 100644 --- a/src/libraries/qtopiamail/qmailfolderkey.h +++ b/src/libraries/qtopiamail/qmailfolderkey.h @@ -100,8 +100,8 @@ public: static QMailFolderKey displayName(const QString &value, QMailDataComparator::InclusionComparator cmp); static QMailFolderKey displayName(const QStringList &values, QMailDataComparator::InclusionComparator cmp = QMailDataComparator::Includes); - static QMailFolderKey status(quint64 mask, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); - static QMailFolderKey status(quint64 mask, QMailDataComparator::InclusionComparator cmp); + static QMailFolderKey status(quint64 mask, QMailDataComparator::InclusionComparator cmp = QMailDataComparator::Includes); + static QMailFolderKey status(quint64 mask, QMailDataComparator::EqualityComparator cmp); static QMailFolderKey ancestorFolderIds(const QMailFolderId &id, QMailDataComparator::InclusionComparator cmp = QMailDataComparator::Includes); static QMailFolderKey ancestorFolderIds(const QMailFolderIdList &ids, QMailDataComparator::InclusionComparator cmp = QMailDataComparator::Includes); diff --git a/src/libraries/qtopiamail/qmailfoldersortkey.cpp b/src/libraries/qtopiamail/qmailfoldersortkey.cpp index a38d5730..7dcc03c2 100644 --- a/src/libraries/qtopiamail/qmailfoldersortkey.cpp +++ b/src/libraries/qtopiamail/qmailfoldersortkey.cpp @@ -14,7 +14,6 @@ /*! \class QMailFolderSortKey - \inpublicgroup QtMessagingModule \preliminary \brief The QMailFolderSortKey class defines the parameters used for sorting a subset of diff --git a/src/libraries/qtopiamail/qmailid.cpp b/src/libraries/qtopiamail/qmailid.cpp index 201ca86d..ce5f6013 100644 --- a/src/libraries/qtopiamail/qmailid.cpp +++ b/src/libraries/qtopiamail/qmailid.cpp @@ -95,7 +95,6 @@ QTextStream& operator<< (QTextStream& s, const MailId &id) /*! \class QMailAccountId - \inpublicgroup QtMessagingModule \ingroup messaginglibrary \preliminary @@ -234,7 +233,6 @@ Q_IMPLEMENT_USER_METATYPE_TYPEDEF(QMailAccountIdList, QMailAccountIdList) /*! \class QMailFolderId - \inpublicgroup QtMessagingModule \ingroup messaginglibrary \preliminary @@ -373,7 +371,6 @@ Q_IMPLEMENT_USER_METATYPE_TYPEDEF(QMailFolderIdList, QMailFolderIdList) /*! \class QMailMessageId - \inpublicgroup QtMessagingModule \ingroup messaginglibrary \preliminary diff --git a/src/libraries/qtopiamail/qmailkeyargument.cpp b/src/libraries/qtopiamail/qmailkeyargument.cpp index b0666d76..a8a975da 100644 --- a/src/libraries/qtopiamail/qmailkeyargument.cpp +++ b/src/libraries/qtopiamail/qmailkeyargument.cpp @@ -10,7 +10,6 @@ /*! \class QMailKeyArgument - \inpublicgroup QtMessagingModule \preliminary \brief The QMailKeyArgument class template defines a class representing a single criterion @@ -63,7 +62,6 @@ /*! \class QMailKeyArgument::ValueList - \inpublicgroup QtMessagingModule \ingroup messaginglibrary \brief The ValueList class provides a list of variant values that can be serialized to a stream, and compared. diff --git a/src/libraries/qtopiamail/qmailmessage.cpp b/src/libraries/qtopiamail/qmailmessage.cpp index 97545589..cbabce7c 100644 --- a/src/libraries/qtopiamail/qmailmessage.cpp +++ b/src/libraries/qtopiamail/qmailmessage.cpp @@ -1456,7 +1456,6 @@ template class QPrivatelyImplemented<QMailMessageHeaderFieldPrivate>; /*! \class QMailMessageHeaderField - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageHeaderField class encapsulates the parsing of message header fields. @@ -1772,7 +1771,6 @@ void QMailMessageHeaderField::deserialize(Stream &stream) /*! \class QMailMessageContentType - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageContentType class encapsulates the parsing of the RFC 2822 @@ -1966,7 +1964,6 @@ void QMailMessageContentType::setCharset(const QByteArray& charset) /*! \class QMailMessageContentDisposition - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageContentDisposition class encapsulates the parsing of the RFC 2822 @@ -2366,7 +2363,6 @@ template class QPrivatelyImplemented<QMailMessageHeaderPrivate>; /*! \class QMailMessageHeader - \inpublicgroup QtMessagingModule \internal */ @@ -2821,7 +2817,6 @@ template class QPrivatelyImplemented<QMailMessageBodyPrivate>; /*! \class QMailMessageBody - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageBody class contains the body element of a message or message part. @@ -3853,7 +3848,6 @@ template class QPrivatelyImplemented<QMailMessagePartContainerPrivate>; /*! \class QMailMessagePartContainer - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessagePartContainer class provides access to a collection of message parts. @@ -4398,7 +4392,6 @@ QMailMessagePartContainerPrivate* QMailMessagePartContainerPrivate::privatePoint /*! \class QMailMessagePart - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessagePart class provides a convenient interface for working @@ -4425,7 +4418,6 @@ QMailMessagePartContainerPrivate* QMailMessagePartContainerPrivate::privatePoint /*! \class QMailMessagePart::Location - \inpublicgroup QtMessagingModule \preliminary \brief The Location class contains a specification of the location of a message part @@ -5459,7 +5451,6 @@ template class QPrivatelyImplemented<QMailMessageMetaDataPrivate>; /*! \class QMailMessageMetaData - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageMetaData class provides information about a message stored by Qtopia. @@ -6451,7 +6442,6 @@ void QMailMessagePrivate::deserialize(Stream &stream) /*! \class QMailMessage - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessage class provides a convenient interface for working with messages. diff --git a/src/libraries/qtopiamail/qmailmessagefwd.cpp b/src/libraries/qtopiamail/qmailmessagefwd.cpp index 9c5cdd1c..f9f2aa9e 100644 --- a/src/libraries/qtopiamail/qmailmessagefwd.cpp +++ b/src/libraries/qtopiamail/qmailmessagefwd.cpp @@ -8,12 +8,6 @@ ** ****************************************************************************/ -/* - TODO: Do we need these? - \inpublicgroup QtMessagingModule - \ingroup messaginglibrary -*/ - /*! \class QMailMessageHeaderFieldFwd \preliminary diff --git a/src/libraries/qtopiamail/qmailmessagekey.cpp b/src/libraries/qtopiamail/qmailmessagekey.cpp index b9a771a2..6137a5b3 100644 --- a/src/libraries/qtopiamail/qmailmessagekey.cpp +++ b/src/libraries/qtopiamail/qmailmessagekey.cpp @@ -25,7 +25,6 @@ using namespace QMailKey; /*! \class QMailMessageKey - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageKey class defines the parameters used for querying a subset of @@ -593,6 +592,14 @@ QMailMessageKey QMailMessageKey::serverUid(const QString &uid, QMailDataComparat */ QMailMessageKey QMailMessageKey::serverUid(const QStringList &uids, QMailDataComparator::InclusionComparator cmp) { +#ifndef USE_ALTERNATE_MAILSTORE_IMPLEMENTATION + if (uids.count() >= IdLookupThreshold) { + // If there are a large number of UIDs, they will be inserted into a temporary table + // with a uniqueness constraint; ensure only unique values are supplied + return QMailMessageKey(uids.toSet().toList(), ServerUid, QMailKey::comparator(cmp)); + } +#endif + return QMailMessageKey(uids, ServerUid, QMailKey::comparator(cmp)); } diff --git a/src/libraries/qtopiamail/qmailmessagekey.h b/src/libraries/qtopiamail/qmailmessagekey.h index 600a0fd0..85c13b2e 100644 --- a/src/libraries/qtopiamail/qmailmessagekey.h +++ b/src/libraries/qtopiamail/qmailmessagekey.h @@ -122,8 +122,8 @@ public: static QMailMessageKey receptionTimeStamp(const QDateTime &value, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); static QMailMessageKey receptionTimeStamp(const QDateTime &value, QMailDataComparator::RelationComparator cmp); - static QMailMessageKey status(quint64 mask, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); - static QMailMessageKey status(quint64 mask, QMailDataComparator::InclusionComparator cmp); + static QMailMessageKey status(quint64 mask, QMailDataComparator::InclusionComparator cmp = QMailDataComparator::Includes); + static QMailMessageKey status(quint64 mask, QMailDataComparator::EqualityComparator cmp); static QMailMessageKey serverUid(const QString &uid, QMailDataComparator::EqualityComparator cmp = QMailDataComparator::Equal); static QMailMessageKey serverUid(const QString &uid, QMailDataComparator::InclusionComparator cmp); diff --git a/src/libraries/qtopiamail/qmailmessagelistmodel.cpp b/src/libraries/qtopiamail/qmailmessagelistmodel.cpp index f5929678..1b0c8e55 100644 --- a/src/libraries/qtopiamail/qmailmessagelistmodel.cpp +++ b/src/libraries/qtopiamail/qmailmessagelistmodel.cpp @@ -498,7 +498,6 @@ QList<QMailMessageListModelPrivate::LocationSequence> QMailMessageListModelPriva /*! \class QMailMessageListModel - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmailmessageremovalrecord.cpp b/src/libraries/qtopiamail/qmailmessageremovalrecord.cpp index 087770b3..d2749efe 100644 --- a/src/libraries/qtopiamail/qmailmessageremovalrecord.cpp +++ b/src/libraries/qtopiamail/qmailmessageremovalrecord.cpp @@ -34,7 +34,6 @@ public: /*! \class QMailMessageRemovalRecord - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmailmessageserver.cpp b/src/libraries/qtopiamail/qmailmessageserver.cpp index 6498976d..20c56c57 100644 --- a/src/libraries/qtopiamail/qmailmessageserver.cpp +++ b/src/libraries/qtopiamail/qmailmessageserver.cpp @@ -154,7 +154,6 @@ QMailMessageServerPrivate::~QMailMessageServerPrivate() /*! \class QMailMessageServer - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageServer class provides signals and slots which implement a convenient @@ -174,10 +173,6 @@ QMailMessageServerPrivate::~QMailMessageServerPrivate() For most messaging client applications, the QMailServiceAction objects offer a simpler interface for requesting actions from the messageserver, and assessing their results. - Note: the functions performed by the message server and the interface to them provided - by the QMailMessageServer class are expected to change in a future release of Qt Extended, - to provide a finer-grained interface for communicating with external services. - \section1 New Messages When a client initiates communication with the MessageServer, the server informs the @@ -192,44 +187,22 @@ QMailMessageServerPrivate::~QMailMessageServerPrivate() To send messages, the client should construct instances of the QMailMessage class formulated to contain the desired content. These messages should be stored to the - mail store, then submitted for transmission by their QMailMessageId values, via the send() - slot. The MessageServer will determine how to transmit each message by inspecting - the account associated with the message. - - If the MessageServer application succeeds in sending a message, the messageSent() - signal is emitted to notify the client. After transmission has been attempted for - each message in the list, the sendCompleted() signal is emitted; any messages - for which a messageSent() signal was not emitted were not successfully transmitted. + mail store, within the Outbox folder configured for the parent account. - After a send operation is initiated, the MessageServer emits the sendTotal() signal - to indicate the approximate extent of the transmission effort. As progress is made - in performing the transmission operation, the sendProgress() signal is repeatedly - emitted to report the progress toward completion of the operation. + An instance of QMailTransmitAction should be used to request transmission of the + outgoing messages. \section1 Retrieving Messages - TODO - - \section2 Folder Retrieval - - It is possible to retrieve only the folder structure of an account rather than the - messages contained by the folders, by invoking retrieve() retrieve slot with the - \c foldersOnly option set to true. When the folder retrieval operation is complete, - it is not necessary to invoke the completeRetrieval() operation. - - \section1 Cancellation - - In order to cancel an operation previously initiated, the client can invoke the - cancelTransfer() slot. - - \section1 Server Status + There are a variety of mechanisms for retrieving messages, at various levels of + granularity. In all cases, retrieved messages are added directly to the mail + store by the message server, from where clients can retrieve their meta data or + content. - As the MessageServer application performs the operations requested of it, it indicates - the tasks it is performing by emitting the statusChanged() signal. If it encounters - an error that prevents an operation from being performed, the actionCompleted(bool) signal - is emitted with the parameter \c false. + An instance of QMailRetrievalAction should be used to request retrievel of + folders and messages. - \sa QMailServiceAction, QMailMessage + \sa QMailServiceAction, QMailStore */ /*! diff --git a/src/libraries/qtopiamail/qmailmessageset.cpp b/src/libraries/qtopiamail/qmailmessageset.cpp index b3451848..c9ca9d7f 100644 --- a/src/libraries/qtopiamail/qmailmessageset.cpp +++ b/src/libraries/qtopiamail/qmailmessageset.cpp @@ -41,7 +41,6 @@ template class QPrivatelyNoncopyable<QMailMessageSetContainerPrivate>; /*! \class QMailMessageSetContainer - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -218,7 +217,6 @@ public: /*! \class QMailMessageSet - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -376,7 +374,6 @@ public: /*! \class QMailFolderMessageSet - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -605,7 +602,6 @@ public: /*! \class QMailAccountMessageSet - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -844,7 +840,6 @@ public: /*! \class QMailFilterMessageSet - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -1085,7 +1080,6 @@ public: /*! \class QMailMessageSetModel - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -1098,7 +1092,7 @@ public: to construct a hierarchical tree of message folders, or other, more flexible ways of partitioning the set of messages into hierarchical groups. - QMailMessageListModel inherits from QAbstractListModel, so it is suitable for use + QMailMessageSetModel inherits from QAbstractItemModel, so it is suitable for use with the Qt View classes such as QTreeView, to visually represent the hierachical structure. @@ -1107,9 +1101,9 @@ public: function is used to disable this feature. To customize the display of QMailMessageSets, create a delegate that paints the - object as desired, using data elements accessed via the QMailMessageSetModel - data() method. The data() function should be overridden to support additional roles, - or to customize the display of existing roles. + object as desired, using data elements accessed via the data() function. + The data() function should be overridden by subclasses to support additional roles, + or to customize the data displayed for existing roles. To define the content of a QMailMessageSetModel, derive classes from QMailMessageSet which select your desired message sets, and add them to the model in the init() diff --git a/src/libraries/qtopiamail/qmailmessagesortkey.cpp b/src/libraries/qtopiamail/qmailmessagesortkey.cpp index 67559048..4b70f06f 100644 --- a/src/libraries/qtopiamail/qmailmessagesortkey.cpp +++ b/src/libraries/qtopiamail/qmailmessagesortkey.cpp @@ -13,7 +13,6 @@ /*! \class QMailMessageSortKey - \inpublicgroup QtMessagingModule \preliminary \brief The QMailMessageSortKey class defines the parameters used for sorting a subset of diff --git a/src/libraries/qtopiamail/qmailserviceaction.cpp b/src/libraries/qtopiamail/qmailserviceaction.cpp index 221feded..296e65b0 100644 --- a/src/libraries/qtopiamail/qmailserviceaction.cpp +++ b/src/libraries/qtopiamail/qmailserviceaction.cpp @@ -310,7 +310,6 @@ template class QPrivatelyNoncopyable<QMailServiceActionPrivate>; /*! \class QMailServiceAction::Status - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -450,7 +449,6 @@ void QMailServiceAction::Status::deserialize(Stream &stream) /*! \class QMailServiceAction - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -472,6 +470,15 @@ void QMailServiceAction::Status::deserialize(Stream &stream) A user may attempt to cancel an operation after it has been initiated. The cancelOperation() slot is provided for this purpose. + + A QMailServiceAction instance supports only a single request at any time. An application + may, however, use multiple QMailServiceAction instances to send independent requests concurrently. + Each QMailServiceAction instance will report only the changes pertaining to the request + that instance delivered. Whether or not concurrent requests are concurrently serviced by + the message server depends on whether those requests must be serviced by the same + QMailMessageService instance. + + \sa QMailMessageService */ /*! @@ -720,7 +727,6 @@ template class QPrivatelyNoncopyable<QMailRetrievalActionPrivate>; /*! \class QMailRetrievalAction - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -783,10 +789,17 @@ QMailRetrievalAction::~QMailRetrievalAction() } /*! - Requests that the message server retrieve the list of folders available for the account \a accountId. - If \a folderId is valid, the folders within that folder should be retrieved. If \a descending is true, - the search should also recursively retrieve the folders available within the previously retrieved folders. - + Requests that the message server retrieve the list of folders available for the + account \a accountId. If \a folderId is valid, only the identified folder is + searched for child folders; otherwise the search begins at the root of the + account. If \a descending is true, the search should also recursively search + for child folders within folders discovered during the search. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for each + folder that is searched for child folders; these properties are not updated + for folders that are merely discovered by searching. + \sa retrieveAll() */ void QMailRetrievalAction::retrieveFolderList(const QMailAccountId &accountId, const QMailFolderId &folderId, bool descending) @@ -797,23 +810,28 @@ void QMailRetrievalAction::retrieveFolderList(const QMailAccountId &accountId, c /*! Requests that the message server retrieve the list of messages available for the account \a accountId. If \a folderId is valid, then only messages within that folder should be retrieved; otherwise - messages within all folders in the account should be retrieved. + messages within all folders in the account should be retrieved. If \a minimum is non-zero, + then that value will be used to restrict the number of messages to be retrieved from + each folder; otherwise, all messages will be retrieved. + If \a sort is not empty, the external service will report the discovered messages in the + ordering indicated by the sort criterion, if possible. Services are not required to support + this facility. + If a folder messages are being retrieved from contains at least \a minimum messages then the messageserver should ensure that at least \a minimum messages are available from the mail - store for that folder; otherwise if the folder contains less than \a minimum messages the messageserver - should ensure all the messages for that folder are available from the mail store. + store for that folder; otherwise if the folder contains less than \a minimum messages the + messageserver should ensure all the messages for that folder are available from the mail store. + If a folder has messages locally available, then all previously undiscovered messages will be + retrieved for that folder, even if that number exceeds \a minimum. - Even if minimum is zero for each folder operated on \link QMailFolder::serverCount() - QMailFolder::serverCount() \endlink and \link QMailFolder::serverUnreadCount() - QMailFolder::serverUnreadCount() \endlink will be updated. + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for each folder + from which messages are retrieved. - If \a sort is not empty, the external service will - discover the listed messages in the ordering indicated by the sort criterion, if possible. - New messages will be added to the mail store as they are discovered, and marked with the \l QMailMessage::New status flag. Messages that are present - in the mail store but found to be no longer available should be marked with the + in the mail store but found to be no longer available are marked with the \l QMailMessage::Removed status flag. \sa retrieveAll() @@ -836,6 +854,10 @@ void QMailRetrievalAction::retrieveMessageList(const QMailAccountId &accountId, If \a spec is \l QMailRetrievalAction::Content, then the message server should retrieve the entirety of each message listed in \a messageIds. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for each folder + from which messages are retrieved. */ void QMailRetrievalAction::retrieveMessages(const QMailMessageIdList &messageIds, RetrievalSpecification spec) { @@ -845,6 +867,10 @@ void QMailRetrievalAction::retrieveMessages(const QMailMessageIdList &messageIds /*! Requests that the message server retrieve the message part that is indicated by the location \a partLocation. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for the folder + from which the part is retrieved. */ void QMailRetrievalAction::retrieveMessagePart(const QMailMessagePart::Location &partLocation) { @@ -854,6 +880,10 @@ void QMailRetrievalAction::retrieveMessagePart(const QMailMessagePart::Location /*! Requests that the message server retrieve a subset of the message \a messageId, such that at least \a minimum bytes are available from the mail store. + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for the folder + from which the message is retrieved. */ void QMailRetrievalAction::retrieveMessageRange(const QMailMessageId &messageId, uint minimum) { @@ -867,6 +897,10 @@ void QMailRetrievalAction::retrieveMessageRange(const QMailMessageId &messageId, The total size of the part on the server is given by QMailMessagePart::contentDisposition().size(), the amount of the part available locally is given by QMailMessagePart::body().length(). + + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for the folder + from which the part is retrieved. */ void QMailRetrievalAction::retrieveMessagePartRange(const QMailMessagePart::Location &partLocation, uint minimum) { @@ -876,6 +910,16 @@ void QMailRetrievalAction::retrieveMessagePartRange(const QMailMessagePart::Loca /*! Requests that the message server retrieve all folders and meta data for messages available for the account \a accountId. + + All folders within the account will be discovered and searched for child folders. + The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for each folder + in the account. + + Meta data will be retrieved for every message found in the account. + New messages will be added to the mail store as they are retrieved, and + marked with the \l QMailMessage::New status flag. Messages that are no longer + available will be marked with the \l QMailMessage::Removed status flag. \sa retrieveFolderList(), retrieveMessageList(), synchronize() */ @@ -904,8 +948,10 @@ void QMailRetrievalAction::exportUpdates(const QMailAccountId &accountId) New messages will be added to the mail store as they are discovered, and marked with the \l QMailMessage::New status flag. Messages that are no longer available will be marked with the \l QMailMessage::Removed status flag. - The folder structure of the account will also be synchronized with that - available from the external service. + + The folder structure of the account will be synchronized with that available from + the external service. The QMailFolder::serverCount(), QMailFolder::serverUnreadCount() and + QMailFolder::serverUndiscoveredCount() properties will be updated for each folder. \sa retrieveAll(), exportUpdates() */ @@ -952,8 +998,9 @@ void QMailTransmitActionPrivate::transmitMessages(const QMailAccountId &accountI { _server->transmitMessages(newAction(), accountId); + QMailAccount account(accountId); _ids = QMailStore::instance()->queryMessages(QMailMessageKey::parentAccountId(accountId) & - QMailMessageKey::parentFolderId(QMailFolderId(QMailFolder::OutboxFolder))); + QMailMessageKey::parentFolderId(account.standardFolder(QMailFolder::OutboxFolder))); emitChanges(); } @@ -987,7 +1034,6 @@ template class QPrivatelyNoncopyable<QMailTransmitActionPrivate>; /*! \class QMailTransmitAction - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -1134,7 +1180,6 @@ template class QPrivatelyNoncopyable<QMailStorageActionPrivate>; /*! \class QMailStorageAction - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -1304,7 +1349,6 @@ template class QPrivatelyNoncopyable<QMailSearchActionPrivate>; /*! \class QMailSearchAction - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary @@ -1446,7 +1490,6 @@ template class QPrivatelyNoncopyable<QMailProtocolActionPrivate>; /*! \class QMailProtocolAction - \inpublicgroup QtMessagingModule \preliminary \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qmailstore.cpp b/src/libraries/qtopiamail/qmailstore.cpp index bc5fecca..d0a8cdbe 100644 --- a/src/libraries/qtopiamail/qmailstore.cpp +++ b/src/libraries/qtopiamail/qmailstore.cpp @@ -15,7 +15,6 @@ /*! \class QMailStore - \inpublicgroup QtMessagingModule \preliminary \brief The QMailStore class represents the main interface for storage and retrieval @@ -29,7 +28,58 @@ QMailStore also provides functions for querying and counting of QMailFolders, QMailAccounts and QMailMessages when used in conjunction with QMailMessageKey, QMailFolderKey and QMailAccountKey classes. - \sa QMailMessage, QMailFolder, QMailMessageKey, QMailFolderKey, QMailAccountKey + If a QMailStore operation fails, the lastError() function will return an error code + value indicating the failure mode encountered. A successful operation will set the + lastError() result to QMailStore::NoError. + + Messaging accounts are represented by QMailAccountId objects. The data associated with + accounts is separated into two components: QMailAccount objects hold account properties + exported to mail store client applications, and QMailAccountConfiguration objects hold + data used only by the messageserver and the protocol plugins it loads. + + Account objects are accessed via the account(), accountConfiguration(), countAccounts() + and queryAccounts() functions. Accounts in the mail store can be manipulated via the + addAccount(), updateAccount() and removeAccount() functions. Mail store manipulations + affecting accounts are reported via the accountsAdded(), accountsUpdated(), + accountContentsModified() and accountsRemoved() signals. + + Fixed logical groupings of message are modelled as folders, represented by QMailFolderId objects. + The data associated with folders is held by instances of the QMailFolder class. + + Folder objects are accessed via the folder(), countFolders() and queryFolders() functions. + Folders in the mail store can be manipulated via the addFolder(), updateFolder() and + removeFolder() functions. Mail store manipulations affecting folders are reported via + the foldersAdded(), foldersUpdated(), folderContentsModified() and foldersRemoved() signals. + + Messages in the mail store are represented by QMailMessageId objects. The data associated + with a message can be retrieved in two forms: QMailMessageMetaData objects contain only + the meta data fields associated with a message, and QMailMessage objects contain both + the meta data fields and the message content proper. + + Message objects are accessed via the message(), messageMetaData(), countMessages() + and queryMessages() functions. Additionally, the messagesMetaData() function can be + used to retrieve subsets of meta data pertaining to a set of messages. Messages in + the mail store can be manipulated via the addMessage(), updateMessage() and removeMessage() + functions. Multiple messages can have their meta data fields updated together via + the updateMessagesMetaData() function. Mail store manipulations affecting messages are + reported via the messagesAdded(), messagesUpdated(), messageContentsModified() and + messagesRemoved() signals. + + Messages that have been removed can be represented by removal records, which persist + only to assist in keeping mail store content synchronized with the content of + an external message source. QMailMessageRemovalRecord objects can be accessed + via the messageRemovalRecords() function. + + \sa QMailAccount, QMailFolder, QMailMessage +*/ + +/*! + \enum QMailStore::InitializationState + This enum defines the initialization states that the mail store can assume. + + \value Uninitialized The mail store has not yet been instantiated and initialized. + \value InitializationFailed The mail store has been instantiated and initization was unsuccessful. + \value Initialized The mail store has been instantiated and successfully initialized. */ /*! @@ -90,19 +140,11 @@ QMailStore::~QMailStore() } /*! - Returns true if the QMailStore object was correctly initialized. + Returns the initialization state of the QMailStore. */ -bool QMailStore::initialized() const +QMailStore::InitializationState QMailStore::initializationState() { - return QMailStore::storeInitialized(); -} - -/*! - Returns true if the QMailStore was correctly initialized. -*/ -bool QMailStore::storeInitialized() -{ - return QMailStorePrivate::initialized(); + return QMailStorePrivate::initializationState(); } /*! @@ -758,6 +800,30 @@ quint64 QMailStore::messageStatusMask(const QString& name) const } /*! + Sets the list of accounts currently retrieving from external sources to be \a ids. + + \sa retrievalInProgress() +*/ +void QMailStore::setRetrievalInProgress(const QMailAccountIdList &ids) +{ + if (d->setRetrievalInProgress(ids)) { + emitRetrievalInProgress(ids); + } +} + +/*! + Sets the list of accounts currently transmitting to external sources to be \a ids. + + \sa transmissionInProgress() +*/ +void QMailStore::setTransmissionInProgress(const QMailAccountIdList &ids) +{ + if (d->setTransmissionInProgress(ids)) { + emitTransmissionInProgress(ids); + } +} + +/*! Forces any queued event notifications to immediately be synchronously emitted, and processed synchronously by recipient processes. @@ -891,18 +957,37 @@ void QMailStore::emitRemovalRecordNotification(ChangeType type, const QMailAccou } } +/*! \internal */ +void QMailStore::emitRetrievalInProgress(const QMailAccountIdList &ids) +{ + d->notifyRetrievalInProgress(ids); + + emit retrievalInProgress(ids); +} + +/*! \internal */ +void QMailStore::emitTransmissionInProgress(const QMailAccountIdList &ids) +{ + d->notifyTransmissionInProgress(ids); + + emit transmissionInProgress(ids); +} + Q_GLOBAL_STATIC(QMailStore,QMailStoreInstance); /*! - Returns an instance of the QMailStore object. -*/ + Returns the single instance of the QMailStore class. + + If necessary, the store will be instantiated and initialized. + \sa initializationState() +*/ QMailStore* QMailStore::instance() { static bool init = false; if (!init) { init = true; - QMailStoreInstance()->d->initStore(); + QMailStoreInstance()->d->initialize(); } return QMailStoreInstance(); } @@ -1015,6 +1100,15 @@ QMailStore* QMailStore::instance() */ /*! + \fn void QMailStore::folderContentsModified(const QMailFolderIdList& ids) + + Signal that is emitted when changes to messages in the mail store + affect the content of the folders in the list \a ids. + + \sa messagesAdded(), messagesUpdated(), messagesRemoved() +*/ + +/*! \fn void QMailStore::messageRemovalRecordsAdded(const QMailAccountIdList& ids) Signal that is emitted when QMailMessageRemovalRecords are added to the store, @@ -1033,12 +1127,25 @@ QMailStore* QMailStore::instance() */ /*! - \fn void QMailStore::folderContentsModified(const QMailFolderIdList& ids) + \fn void QMailStore::retrievalInProgress(const QMailAccountIdList& ids) - Signal that is emitted when changes to messages in the mail store - affect the content of the folders in the list \a ids. + Signal that is emitted when the set of accounts currently retrieving from + external sources is modified to \a ids. Accounts listed in \a ids are likely + to be the source of numerous mail store signals; some clients may wish to + ignore updates associated with these accounts whilst they are engaged in retrieving. - \sa messagesAdded(), messagesUpdated(), messagesRemoved() + \sa transmissionInProgress() +*/ + +/*! + \fn void QMailStore::transmissionInProgress(const QMailAccountIdList& ids) + + Signal that is emitted when the set of accounts currently transmitting to + external sources is modified to \a ids. Accounts listed in \a ids are likely + to be the source of numerous mail store signals; some clients may wish to + ignore updates associated with these accounts whilst they are engaged in transmitting. + + \sa retrievalInProgress() */ Q_IMPLEMENT_USER_METATYPE_ENUM(QMailStore::MessageRemovalOption) diff --git a/src/libraries/qtopiamail/qmailstore.h b/src/libraries/qtopiamail/qmailstore.h index 55ef22dc..0356ac3a 100644 --- a/src/libraries/qtopiamail/qmailstore.h +++ b/src/libraries/qtopiamail/qmailstore.h @@ -36,6 +36,13 @@ class QTOPIAMAIL_EXPORT QMailStore : public QObject Q_OBJECT public: + enum InitializationState + { + Uninitialized = 0, + InitializationFailed, + Initialized + }; + enum ReturnOption { ReturnAll = 0, @@ -69,8 +76,7 @@ public: public: virtual ~QMailStore(); - bool initialized() const; - static bool storeInitialized(); + static InitializationState initializationState(); QMailStore::ErrorCode lastError() const; @@ -134,6 +140,9 @@ public: bool registerMessageStatusFlag(const QString& name); quint64 messageStatusMask(const QString& name) const; + void setRetrievalInProgress(const QMailAccountIdList &ids); + void setTransmissionInProgress(const QMailAccountIdList &ids); + bool asynchronousEmission() const; void flushIpcNotifications(); @@ -164,10 +173,14 @@ signals: void messageRemovalRecordsAdded(const QMailAccountIdList& ids); void messageRemovalRecordsRemoved(const QMailAccountIdList& ids); + void retrievalInProgress(const QMailAccountIdList &ids); + void transmissionInProgress(const QMailAccountIdList &ids); + private: friend class QMailStoreImplementationBase; friend class QMailStorePrivate; friend class tst_QMailStore; + friend class tst_QMailStoreKeys; QMailStore(); @@ -180,6 +193,8 @@ private: void emitFolderNotification(ChangeType type, const QMailFolderIdList &ids); void emitMessageNotification(ChangeType type, const QMailMessageIdList &ids); void emitRemovalRecordNotification(ChangeType type, const QMailAccountIdList &ids); + void emitRetrievalInProgress(const QMailAccountIdList &ids); + void emitTransmissionInProgress(const QMailAccountIdList &ids); QMailStorePrivate* d; }; diff --git a/src/libraries/qtopiamail/qmailstore_p.cpp b/src/libraries/qtopiamail/qmailstore_p.cpp index 4d6840c3..016f2185 100644 --- a/src/libraries/qtopiamail/qmailstore_p.cpp +++ b/src/libraries/qtopiamail/qmailstore_p.cpp @@ -948,7 +948,11 @@ void appendWhereValues<QMailMessageKey::ArgumentType>(const QMailMessageKey::Arg break; case QMailMessageKey::ServerUid: - values += extractor.serverUid(); + if (a.valueList.count() < IdLookupThreshold) { + values += extractor.serverUid(); + } else { + // This value match has been replaced by a table lookup + } break; case QMailMessageKey::Size: @@ -1526,6 +1530,14 @@ QString whereClauseItem<QMailMessageKey>(const QMailMessageKey &, const QMailMes } break; + case QMailMessageKey::ServerUid: + if (a.valueList.count() >= IdLookupThreshold) { + q << baseExpression(columnName, a.op, true) << "( SELECT id FROM " << QMailStorePrivate::temporaryTableName(a) << ")"; + } else { + q << expression; + } + break; + case QMailMessageKey::Type: case QMailMessageKey::Status: case QMailMessageKey::Sender: @@ -1533,7 +1545,6 @@ QString whereClauseItem<QMailMessageKey>(const QMailMessageKey &, const QMailMes case QMailMessageKey::Subject: case QMailMessageKey::TimeStamp: case QMailMessageKey::ReceptionTimeStamp: - case QMailMessageKey::ServerUid: case QMailMessageKey::Size: case QMailMessageKey::ContentType: case QMailMessageKey::ContentScheme: @@ -1988,7 +1999,7 @@ bool QMailStorePrivate::initStore() ProcessMutex creationMutex(pathIdentifier(QDir::rootPath())); MutexGuard guard(creationMutex); if (!guard.lock(1000)) { - return init; + return false; } if (database.isOpenError()) { @@ -2042,7 +2053,6 @@ bool QMailStorePrivate::initStore() } // We are now correctly initialized - init = true; return true; } @@ -2054,6 +2064,8 @@ void QMailStorePrivate::clearContent() messageCache.clear(); uidCache.clear(); + Transaction t(this); + // Drop all data foreach (const QString &table, database.tables()) { if (table != "versioninfo") { @@ -2064,6 +2076,10 @@ void QMailStorePrivate::clearContent() } } } + + if (!t.commit()) { + qMailLog(Messaging) << "Could not commit clearContent operation to database"; + } // Remove all content QMailContentManagerFactory::clearContent(); @@ -2128,22 +2144,27 @@ QSqlQuery QMailStorePrivate::prepare(const QString& sql) clearQueryError(); - QSqlQuery query(database); - // Create any temporary tables needed for this query while (!requiredTableKeys.isEmpty()) { - const QMailMessageKey::ArgumentType *arg = requiredTableKeys.takeFirst(); + QPair<const QMailMessageKey::ArgumentType *, QString> key(requiredTableKeys.takeFirst()); + const QMailMessageKey::ArgumentType *arg = key.first; if (!temporaryTableKeys.contains(arg)) { QString tableName = temporaryTableName(*arg); - QSqlQuery tableQuery(database); - if (!tableQuery.exec(QString("CREATE TEMP TABLE %1 ( id INTEGER PRIMARY KEY )").arg(tableName))) { - setQueryError(tableQuery.lastError(), "Failed to create temporary table", queryText(tableQuery)); - qMailLog(Messaging) << "Unable to prepare query:" << sql; - return query; - } else { - temporaryTableKeys.append(arg); + { + QSqlQuery createQuery(database); + if (!createQuery.exec(QString("CREATE TEMP TABLE %1 ( id %2 PRIMARY KEY )").arg(tableName).arg(key.second))) { + setQueryError(createQuery.lastError(), "Failed to create temporary table", queryText(createQuery)); + qMailLog(Messaging) << "Unable to prepare query:" << sql; + return QSqlQuery(); + } + } + temporaryTableKeys.append(arg); + + QVariantList idValues; + + if (key.second == "INTEGER") { int type = 0; if (qVariantCanConvert<QMailMessageId>(arg->valueList.first())) { type = 1; @@ -2153,7 +2174,7 @@ QSqlQuery QMailStorePrivate::prepare(const QString& sql) type = 3; } - // Add the ID values to the temp table + // Extract the ID values to INTEGER variants foreach (const QVariant &var, arg->valueList) { quint64 id = 0; @@ -2170,20 +2191,43 @@ QSqlQuery QMailStorePrivate::prepare(const QString& sql) default: qMailLog(Messaging) << "Unable to extract ID value from valuelist!"; qMailLog(Messaging) << "Unable to prepare query:" << sql; - return query; + return QSqlQuery(); + } + + idValues.append(QVariant(id)); + } + + // Add the ID values to the temp table + { + QSqlQuery insertQuery(database); + insertQuery.prepare(QString("INSERT INTO %1 VALUES (?)").arg(tableName)); + insertQuery.addBindValue(idValues); + if (!insertQuery.execBatch()) { + setQueryError(insertQuery.lastError(), "Failed to populate integer temporary table", queryText(insertQuery)); + qMailLog(Messaging) << "Unable to prepare query:" << sql; + return QSqlQuery(); } + } + } else if (key.second == "VARCHAR") { + foreach (const QVariant &var, arg->valueList) { + idValues.append(QVariant(var.value<QString>())); + } - tableQuery = QSqlQuery(database); - if (!tableQuery.exec(QString("INSERT INTO %1 VALUES (%2)").arg(tableName).arg(id))) { - setQueryError(tableQuery.lastError(), "Failed to populate temporary table", queryText(tableQuery)); + { + QSqlQuery insertQuery(database); + insertQuery.prepare(QString("INSERT INTO %1 VALUES (?)").arg(tableName)); + insertQuery.addBindValue(idValues); + if (!insertQuery.execBatch()) { + setQueryError(insertQuery.lastError(), "Failed to populate varchar temporary table", queryText(insertQuery)); qMailLog(Messaging) << "Unable to prepare query:" << sql; - return query; + return QSqlQuery(); } } } } } + QSqlQuery query(database); query.setForwardOnly(true); if (!query.prepare(sql)) { setQueryError(query.lastError(), "Failed to prepare query", queryText(query)); @@ -2270,7 +2314,7 @@ void QMailStorePrivate::setQueryError(const QSqlError &error, const QString &des void QMailStorePrivate::clearQueryError(void) { - lastQueryError = 0; + lastQueryError = QSqlError::NoError; } template<bool PtrSizeExceedsLongSize> @@ -2291,9 +2335,9 @@ QString QMailStorePrivate::temporaryTableName(const QMailMessageKey::ArgumentTyp return QString("qtopiamail_idmatch_%1").arg(numericPtrValue<(sizeof(void*) > sizeof(unsigned long))>(ptr)); } -void QMailStorePrivate::createTemporaryTable(const QMailMessageKey::ArgumentType& arg) const +void QMailStorePrivate::createTemporaryTable(const QMailMessageKey::ArgumentType& arg, const QString &dataType) const { - requiredTableKeys.append(&arg); + requiredTableKeys.append(qMakePair(&arg, dataType)); } void QMailStorePrivate::destroyTemporaryTables() @@ -2574,7 +2618,9 @@ QString QMailStorePrivate::buildWhereClause(const Key& key, bool nested, bool fi // See if we need to create any temporary tables to use in this query foreach (const QMailMessageKey::ArgumentType &a, messageKey.arguments()) { if (a.property == QMailMessageKey::Id && a.valueList.count() >= IdLookupThreshold) { - createTemporaryTable(a); + createTemporaryTable(a, "INTEGER"); + } else if (a.property == QMailMessageKey::ServerUid && a.valueList.count() >= IdLookupThreshold) { + createTemporaryTable(a, "VARCHAR"); } } @@ -5964,7 +6010,7 @@ QSqlQuery QMailStorePrivate::performQuery(const QString& statement, bool batch, } QSqlQuery query(prepare(statement + keyStatements)); - if (query.lastError().type() != QSqlError::NoError) { + if (queryError() != QSqlError::NoError) { qMailLog(Messaging) << "Could not prepare query" << descriptor; } else { foreach (const QVariant& value, bindValues) diff --git a/src/libraries/qtopiamail/qmailstore_p.h b/src/libraries/qtopiamail/qmailstore_p.h index 81cb3346..4b011d77 100644 --- a/src/libraries/qtopiamail/qmailstore_p.h +++ b/src/libraries/qtopiamail/qmailstore_p.h @@ -187,7 +187,7 @@ private: typedef QPair<quint64, QString> FolderInfo; bool setupFolders(const QList<FolderInfo> &folderList); - void createTemporaryTable(const QMailMessageKey::ArgumentType &arg) const; + void createTemporaryTable(const QMailMessageKey::ArgumentType &arg, const QString &dataType) const; void destroyTemporaryTables(void); bool transaction(void); @@ -480,7 +480,7 @@ private: mutable IdCache<QMailFolder, QMailFolderId> folderCache; mutable IdCache<QMailAccount, QMailAccountId> accountCache; - mutable QList<const QMailMessageKey::ArgumentType*> requiredTableKeys; + mutable QList<QPair<const QMailMessageKey::ArgumentType*, QString> > requiredTableKeys; mutable QList<const QMailMessageKey::ArgumentType*> temporaryTableKeys; QList<const QMailMessageKey::ArgumentType*> expiredTableKeys; diff --git a/src/libraries/qtopiamail/qmailstoreimplementation_p.cpp b/src/libraries/qtopiamail/qmailstoreimplementation_p.cpp index 097b7ec2..afc2c2f7 100644 --- a/src/libraries/qtopiamail/qmailstoreimplementation_p.cpp +++ b/src/libraries/qtopiamail/qmailstoreimplementation_p.cpp @@ -84,13 +84,15 @@ void dispatchNotifications(IDSetType &ids, const QString &sig) } -bool QMailStoreImplementationBase::init = false; +QMailStore::InitializationState QMailStoreImplementationBase::initState = QMailStore::Uninitialized; QMailStoreImplementationBase::QMailStoreImplementationBase(QMailStore* parent) : QObject(parent), q(parent), errorCode(QMailStore::NoError), - asyncEmission(false) + asyncEmission(false), + retrievalSetInitialized(false), + transmissionSetInitialized(false) { Q_ASSERT(q); @@ -119,14 +121,14 @@ QMailStoreImplementationBase::QMailStoreImplementationBase(QMailStore* parent) SLOT(aboutToQuit())); } -bool QMailStoreImplementationBase::initStore() +void QMailStoreImplementationBase::initialize() { - return false; + initState = (initStore() ? QMailStore::Initialized : QMailStore::InitializationFailed); } -bool QMailStoreImplementationBase::initialized() +QMailStore::InitializationState QMailStoreImplementationBase::initializationState() { - return init; + return initState; } QMailStore::ErrorCode QMailStoreImplementationBase::lastError() const @@ -159,6 +161,11 @@ void QMailStoreImplementationBase::flushIpcNotifications() QCopAdaptor a("QPE/Qtopiamail"); QCopAdaptorEnvelope e = a.send("forceIpcFlush"); e << ::getpid(); + + if (flushTimer.isActive()) { + // We interrupted a batching period - reset the flush timer to its full period + flushTimer.start(flushTimeout); + } } void QMailStoreImplementationBase::processIpcMessageQueue() @@ -249,7 +256,6 @@ void QMailStoreImplementationBase::notifyAccountsChange(QMailStore::ChangeType c break; } } else { - flushNotifications(); emitIpcUpdates(ids, sig[changeType]); preFlushTimer.start(preFlushTimeout); @@ -287,7 +293,6 @@ void QMailStoreImplementationBase::notifyMessagesChange(QMailStore::ChangeType c break; } } else { - flushNotifications(); emitIpcUpdates(ids, sig[changeType]); preFlushTimer.start(preFlushTimeout); @@ -325,7 +330,6 @@ void QMailStoreImplementationBase::notifyFoldersChange(QMailStore::ChangeType ch break; } } else { - flushNotifications(); emitIpcUpdates(ids, sig[changeType]); preFlushTimer.start(preFlushTimeout); @@ -357,13 +361,52 @@ void QMailStoreImplementationBase::notifyMessageRemovalRecordsChange(QMailStore: break; } } else { - flushNotifications(); emitIpcUpdates(ids, sig[changeType]); preFlushTimer.start(preFlushTimeout); } } +void QMailStoreImplementationBase::notifyRetrievalInProgress(const QMailAccountIdList& ids) +{ + // Clients may want to enable or disable event handling based on this event, therefore + // we must ensure that all previous events are actually delivered before this one is. + flushIpcNotifications(); + + emitIpcUpdates(ids, retrievalInProgressSig()); +} + +void QMailStoreImplementationBase::notifyTransmissionInProgress(const QMailAccountIdList& ids) +{ + flushIpcNotifications(); + + emitIpcUpdates(ids, transmissionInProgressSig()); +} + +bool QMailStoreImplementationBase::setRetrievalInProgress(const QMailAccountIdList& ids) +{ + QSet<QMailAccountId> idSet(ids.toSet()); + if ((idSet != retrievalInProgressIds) || !retrievalSetInitialized) { + retrievalInProgressIds = idSet; + retrievalSetInitialized = true; + return true; + } + + return false; +} + +bool QMailStoreImplementationBase::setTransmissionInProgress(const QMailAccountIdList& ids) +{ + QSet<QMailAccountId> idSet(ids.toSet()); + if ((idSet != transmissionInProgressIds) || !transmissionSetInitialized) { + transmissionInProgressIds = idSet; + transmissionSetInitialized = true; + return true; + } + + return false; +} + QString QMailStoreImplementationBase::accountAddedSig() { static QString s("accountAdded(int,QList<quint64>)"); @@ -448,6 +491,18 @@ QString QMailStoreImplementationBase::messageRemovalRecordsRemovedSig() return s; } +QString QMailStoreImplementationBase::retrievalInProgressSig() +{ + static QString s("retrievalInProgress(QList<quint64>)"); + return s; +} + +QString QMailStoreImplementationBase::transmissionInProgressSig() +{ + static QString s("transmissionInProgress(QList<quint64>)"); + return s; +} + QMailStoreImplementationBase::AccountUpdateSignalMap QMailStoreImplementationBase::initAccountUpdateSignals() { AccountUpdateSignalMap sig; @@ -525,7 +580,18 @@ void QMailStoreImplementationBase::ipcMessage(const QString& message, const QByt // We have been told to flush any pending ipc notifications queueTimer.stop(); while (emitIpcNotification()) {} + } else if ((message == retrievalInProgressSig()) || (message == transmissionInProgressSig())) { + // Emit this message immediately + QMailAccountIdList ids; + ds >> ids; + + if (message == retrievalInProgressSig()) { + emitIpcNotification(&QMailStore::retrievalInProgress, ids); + } else { + emitIpcNotification(&QMailStore::transmissionInProgress, ids); + } } else { + // Queue this message for batched delivery messageQueue.append(qMakePair(message, data)); queueTimer.start(0); } diff --git a/src/libraries/qtopiamail/qmailstoreimplementation_p.h b/src/libraries/qtopiamail/qmailstoreimplementation_p.h index 405683e1..cbeaa8df 100644 --- a/src/libraries/qtopiamail/qmailstoreimplementation_p.h +++ b/src/libraries/qtopiamail/qmailstoreimplementation_p.h @@ -37,8 +37,8 @@ class QMailStoreImplementationBase : public QObject public: QMailStoreImplementationBase(QMailStore* parent); - virtual bool initStore(); - static bool initialized(); + void initialize(); + static QMailStore::InitializationState initializationState(); QMailStore::ErrorCode lastError() const; void setLastError(QMailStore::ErrorCode code) const; @@ -51,6 +51,11 @@ public: void notifyMessagesChange(QMailStore::ChangeType changeType, const QMailMessageIdList& ids); void notifyFoldersChange(QMailStore::ChangeType changeType, const QMailFolderIdList& ids); void notifyMessageRemovalRecordsChange(QMailStore::ChangeType changeType, const QMailAccountIdList& ids); + void notifyRetrievalInProgress(const QMailAccountIdList& ids); + void notifyTransmissionInProgress(const QMailAccountIdList& ids); + + bool setRetrievalInProgress(const QMailAccountIdList &ids); + bool setTransmissionInProgress(const QMailAccountIdList &ids); static QString accountAddedSig(); static QString accountRemovedSig(); @@ -70,6 +75,9 @@ public: static QString messageRemovalRecordsAddedSig(); static QString messageRemovalRecordsRemovedSig(); + static QString retrievalInProgressSig(); + static QString transmissionInProgressSig(); + static const int maxNotifySegmentSize = 0; public slots: @@ -91,13 +99,15 @@ protected: typedef QMap<QString, MessageUpdateSignal> MessageUpdateSignalMap; static MessageUpdateSignalMap initMessageUpdateSignals(); - static bool init; + static QMailStore::InitializationState initState; virtual void emitIpcNotification(AccountUpdateSignal signal, const QMailAccountIdList &ids); virtual void emitIpcNotification(FolderUpdateSignal signal, const QMailFolderIdList &ids); virtual void emitIpcNotification(MessageUpdateSignal signal, const QMailMessageIdList &ids); private: + virtual bool initStore() = 0; + bool emitIpcNotification(); QMailStore* q; @@ -127,6 +137,12 @@ private: QSet<QMailAccountId> accountContentsModifiedBuffer; QSet<QMailMessageId> messageContentsModifiedBuffer; + bool retrievalSetInitialized; + bool transmissionSetInitialized; + + QSet<QMailAccountId> retrievalInProgressIds; + QSet<QMailAccountId> transmissionInProgressIds; + QTimer queueTimer; QList<QPair<QString, QByteArray> > messageQueue; }; @@ -137,7 +153,6 @@ class QMailStoreImplementation : public QMailStoreImplementationBase public: QMailStoreImplementation(QMailStore* parent); - virtual bool initStore() = 0; virtual void clearContent() = 0; virtual bool addAccount(QMailAccount *account, QMailAccountConfiguration *config, diff --git a/src/libraries/qtopiamail/qmailtimestamp.cpp b/src/libraries/qtopiamail/qmailtimestamp.cpp index cc0431fb..63053d12 100644 --- a/src/libraries/qtopiamail/qmailtimestamp.cpp +++ b/src/libraries/qtopiamail/qmailtimestamp.cpp @@ -292,7 +292,6 @@ bool QMailTimeStampPrivate::operator>= (const QMailTimeStampPrivate& other) cons /*! \class QMailTimeStamp - \inpublicgroup QtMessagingModule \brief The QMailTimeStamp class manages message time stamps. \ingroup messaginglibrary diff --git a/src/libraries/qtopiamail/qprivateimplementation.cpp b/src/libraries/qtopiamail/qprivateimplementation.cpp index ab13a48d..f6e9f1d1 100644 --- a/src/libraries/qtopiamail/qprivateimplementation.cpp +++ b/src/libraries/qtopiamail/qprivateimplementation.cpp @@ -10,7 +10,6 @@ /*! \class QPrivateImplementationBase - \inpublicgroup QtMessagingModule \brief The QPrivateImplementationBase provides a base class for implicitly shared implementation classes. @@ -21,7 +20,6 @@ /*! \class QPrivateImplementationPointer - \inpublicgroup QtMessagingModule \brief The QPrivateImplementationPointer is a smart pointer which manages implicit sharing of classes derived from QPrivateImplementationBase. @@ -32,7 +30,6 @@ /*! \class QPrivatelyImplemented - \inpublicgroup QtMessagingModule \brief The QPrivatelyImplemented class template allows a class to delegate its implementation to an incomplete template parameter class. diff --git a/src/libraries/qtopiamail/support/qcopchannel.cpp b/src/libraries/qtopiamail/support/qcopchannel.cpp index 3f8a19ba..e3f0f763 100644 --- a/src/libraries/qtopiamail/support/qcopchannel.cpp +++ b/src/libraries/qtopiamail/support/qcopchannel.cpp @@ -165,11 +165,15 @@ QCopChannel::QCopChannel(const QString& channel, QObject *parent) /* ! \internal - Resend all channel registrations This function is obsolete. + Resend all channel registrations. */ void QCopChannel::reregisterAll() { - // Exists for backwards-compatibility only. Not needed any more. + QCopThreadData *td = qcopThreadData(); + + foreach (const QString &channel, td->clientMap.keys()) { + td->clientConnection()->registerChannel(channel); + } } /* ! @@ -632,22 +636,13 @@ struct QCopPacketHeader int forwardToLength; }; -QCopClient::QCopClient() - : QObject() -{ - socket = new QCopLocalSocket(this); - device = socket; - server = false; - init(); - connectToServer(); -} - QCopClient::QCopClient(QIODevice *device, QCopLocalSocket *socket) : QObject() { this->device = device; this->socket = socket; server = true; + disconnectHandler = 0; init(); } @@ -657,6 +652,7 @@ QCopClient::QCopClient(QIODevice *device, bool isServer) this->device = device; this->socket = 0; server = isServer; + disconnectHandler = 0; init(); } @@ -676,6 +672,7 @@ void QCopClient::init() retryCount = 0; connecting = false; + reconnecting = false; channelCount = 0; @@ -686,8 +683,14 @@ void QCopClient::init() QCopClient::~QCopClient() { - if (socket) + if (disconnectHandler) { + delete disconnectHandler; + disconnectHandler = 0; + } + if (socket) { delete socket; + socket = 0; + } } void QCopClient::registerChannel(const QString& ch) @@ -986,12 +989,21 @@ void QCopClient::disconnected() if (!finished) { finished = true; if (server) { - detachAll(); + detachAll(); deleteLater(); + } else if (disconnectHandler) { + (*disconnectHandler)(); } } } +void QCopClient::reconnect() +{ + // Attempt to reconnect after a pause + reconnecting = true; + QTimer::singleShot(1000, this, SLOT(connectToServer())); +} + #ifndef QT_NO_QCOP_LOCAL_SOCKET QString QCopThreadData::socketPath() @@ -1023,7 +1035,14 @@ void QCopClient::connectToServer() socket->connectToHost(QHostAddress::LocalHost, QCopThreadData::listenPort()); #endif if (socket->waitForConnected()) { + if (reconnecting) { + reconnecting = false; + foreach (const QString &channel, qcopThreadData()->clientMap.keys()) { + registerChannel(channel); + } + } connecting = false; + retryCount = 0; device = socket; connectSignals(); if (pendingData.size() > 0) { @@ -1035,10 +1054,17 @@ void QCopClient::connectToServer() delete socket; socket = 0; device = 0; - if (++retryCount < 30) - QTimer::singleShot(200, this, SLOT(connectToServer())); - else - qWarning() << "Could not connect to QCop server; probably not running."; + + if ((++retryCount % 30) == 0) { + if (reconnecting) { + qWarning() << "Cannot connect to QCop server; retrying..."; + } else { + qWarning() << "Could not connect to QCop server; probably not running."; + return; + } + } + + QTimer::singleShot(retryCount <= 30 ? 200 : 1000, this, SLOT(connectToServer())); } } diff --git a/src/libraries/qtopiamail/support/qcopchannel_p.h b/src/libraries/qtopiamail/support/qcopchannel_p.h index 1d657371..b1ba7ae1 100644 --- a/src/libraries/qtopiamail/support/qcopchannel_p.h +++ b/src/libraries/qtopiamail/support/qcopchannel_p.h @@ -62,8 +62,42 @@ class QCopLoopbackDevice; class QCopClient : public QObject { Q_OBJECT + + struct MemberInvokerBase + { + virtual ~MemberInvokerBase() {} + + virtual void operator()() = 0; + }; + + template<typename T> + struct MemberInvoker : public MemberInvokerBase + { + T* instance; + void (T::*function)(); + + MemberInvoker(T* inst, void (T::*func)()) + : instance(inst), function(func) {} + + virtual void operator()() { (instance->*function)(); } + }; + public: - QCopClient(); + template<typename T> + QCopClient(bool connectImmediately, T *instance = 0, void (T::*func)() = 0) + : QObject(), + server(false), + socket(new QCopLocalSocket(this)), + device(socket), + disconnectHandler(instance ? new MemberInvoker<T>(instance, func) : 0) + { + init(); + + if (connectImmediately) { + connectToServer(); + } + } + QCopClient(QIODevice *device, QCopLocalSocket *socket); QCopClient(QIODevice *device, bool isServer); ~QCopClient(); @@ -88,6 +122,8 @@ public: bool isStartupComplete; + void reconnect(); + signals: void startupComplete(); @@ -100,9 +136,10 @@ private slots: private: bool server; bool finished; - QIODevice *device; QCopLoopbackDevice *loopback; QCopLocalSocket *socket; + QIODevice *device; + MemberInvokerBase *disconnectHandler; void init(); @@ -116,6 +153,7 @@ private: QByteArray pendingData; int retryCount; bool connecting; + bool reconnecting; int channelCount; void detachAll(); @@ -316,8 +354,9 @@ public: // Get the client connection object for this thread. inline QCopClient *clientConnection() { - if (!conn) - conn = new QCopClient(); + if (!conn) { + conn = new QCopClient(true, this, &QCopThreadData::disconnected); + } return conn; } @@ -346,6 +385,17 @@ public: QCopServer *server; QCopClient *conn; + +private: + void disconnected() + { + if (conn) { + conn->deleteLater(); + + conn = new QCopClient(false, this, &QCopThreadData::disconnected); + conn->reconnect(); + } + } }; #endif diff --git a/src/plugins/composers/email/attachmentlistwidget.cpp b/src/plugins/composers/email/attachmentlistwidget.cpp index a245f710..3613bff7 100644 --- a/src/plugins/composers/email/attachmentlistwidget.cpp +++ b/src/plugins/composers/email/attachmentlistwidget.cpp @@ -1,3 +1,13 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + #include "attachmentlistwidget.h" #include <QStringListModel> #include <QListView> @@ -47,6 +57,7 @@ protected: void mousePressEvent(QMouseEvent* e); bool overRemoveLink(QMouseEvent* e); + private: AttachmentListWidget* m_parent; mutable QRect m_removeButtonRect; @@ -108,11 +119,15 @@ bool AttachmentListHeader::overRemoveLink(QMouseEvent* e) class AttachmentListDelegate : public QItemDelegate { + Q_OBJECT public: AttachmentListDelegate(AttachmentListWidget* parent = 0); void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; bool isOverRemoveLink(const QRect& parentRect, const QPoint& pos) const; +protected slots: + bool helpEvent(QHelpEvent * event, QAbstractItemView * view, const QStyleOptionViewItem & option, const QModelIndex & index); + private: QPointer<AttachmentListWidget> m_parent; }; @@ -150,6 +165,16 @@ bool AttachmentListDelegate::isOverRemoveLink(const QRect& parentRect, const QPo return textRect.contains(pos); } +bool AttachmentListDelegate::helpEvent(QHelpEvent * event, QAbstractItemView * view, const QStyleOptionViewItem & option, const QModelIndex & index ) +{ + if(!index.isValid()) + view->setToolTip(QString()); + + QString attachment = m_parent->attachmentAt(index.row()); + view->setToolTip(attachment); + return false; +} + class AttachmentListView : public QTreeView { Q_OBJECT @@ -344,6 +369,16 @@ QStringList AttachmentListWidget::attachments() const return m_attachments; } +QString AttachmentListWidget::attachmentAt(int index) const +{ + return m_attachments.at(index); +} + +int AttachmentListWidget::count() const +{ + return m_attachments.count(); +} + bool AttachmentListWidget::isEmpty() const { return m_attachments.isEmpty(); diff --git a/src/plugins/composers/email/attachmentlistwidget.h b/src/plugins/composers/email/attachmentlistwidget.h index 7c72e167..5166c9b3 100644 --- a/src/plugins/composers/email/attachmentlistwidget.h +++ b/src/plugins/composers/email/attachmentlistwidget.h @@ -1,3 +1,13 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + #ifndef ATTACHMENTLISTWIDGET_H #define ATTACHMENTLISTWIDGET_H @@ -19,6 +29,8 @@ class AttachmentListWidget : public QWidget public: AttachmentListWidget(QWidget* parent = 0); QStringList attachments() const; + QString attachmentAt(int index) const; + int count() const; bool isEmpty() const; public slots: diff --git a/src/plugins/composers/email/emailcomposer.cpp b/src/plugins/composers/email/emailcomposer.cpp index 7cffbcfa..da2e931c 100644 --- a/src/plugins/composers/email/emailcomposer.cpp +++ b/src/plugins/composers/email/emailcomposer.cpp @@ -39,6 +39,7 @@ #include <QFileDialog> #include "attachmentlistwidget.h" #include <support/qmailnamespace.h> +#include <QUrl> static int minimumLeftWidth = 65; static const QString placeholder("(no subject)"); @@ -313,16 +314,6 @@ void RecipientListWidget::removeRecipientWidget() return; int index = m_widgetList.indexOf(r); - /* - bool isEmptySlot = (r->isEmpty() && emptyRecipientSlots() == 1); - if(r->isEmpty()) - { - //just move focus back to previous slot - if(index > 0) - m_widgetList.at(index-1)->setFocus(); - return; - } -*/ r->deleteLater(); m_widgetList.removeAll(r); @@ -458,49 +449,10 @@ void EmailComposerInterface::setCursorPosition() } } -void EmailComposerInterface::updateAttachmentsLabel() -{ - /* - int count = 0; - int sizeKB = 0; - - foreach (const AttachmentItem* item, m_addAttDialog->attachedFiles()) { - ++count; - sizeKB += item->sizeKB(); - } - - if (count == 0) { - m_attachmentsLabel->hide(); - } else { - m_attachmentsLabel->setText(QString("<center><small>") + tr("%n Attachment(s): %1KB","", count).arg(sizeKB)+"</small></center>"); - m_attachmentsLabel->show(); - } - */ -} - void EmailComposerInterface::selectAttachment() { QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select attachments")); m_attachmentListWidget->addAttachments(fileNames); - - /* - if (m_attachments.isEmpty() && m_addAttDialog->documentSelector()->documents().isEmpty()) { - QMessageBox::warning(this, - tr("No documents"), - tr("There are no existing documents to attach"), - tr("OK") ); - } else { - if (QtopiaApplication::execDialog(m_addAttDialog) == QDialog::Accepted) { - m_attachments.clear(); - foreach (const AttachmentItem *item, m_addAttDialog->attachedFiles()) - m_attachments.append(qMakePair(item->document(), item->action())); - } else { - m_addAttDialog->clear(); - foreach (const AttachmentDetail &att, m_attachments) - m_addAttDialog->attach(att.first, att.second); - } - } - */ } EmailComposerInterface::EmailComposerInterface( QWidget *parent ) @@ -521,14 +473,6 @@ EmailComposerInterface::EmailComposerInterface( QWidget *parent ) EmailComposerInterface::~EmailComposerInterface() { - /* - // Delete any temporary files we don't need - foreach (const AttachmentDetail &att, m_attachments) { - if (att.second == QMailMessage::CopyAndDeleteAttachments) { - const_cast<QContent&>(att.first).removeFiles(); - } - } - */ } void EmailComposerInterface::init() @@ -570,11 +514,6 @@ void EmailComposerInterface::init() m_attachmentsLabel->hide(); layout->addWidget(m_attachmentListWidget = new AttachmentListWidget(this)); -// m_addAttDialog = new AddAttDialog(this, "attachmentDialog"); -// connect(m_addAttDialog,SIGNAL(attachmentsChanged()),this,SLOT(updateAttachmentsLabel())); -// connect(m_addAttDialog,SIGNAL(attachmentsChanged()),this,SLOT(updateLabel())); -// connect(m_addAttDialog,SIGNAL(attachmentsChanged()),this,SIGNAL(changed())); - //menus m_attachmentAction = new QAction( QIcon( ":icon/attach" ), tr("Attachments") + "...", this); connect( m_attachmentAction, SIGNAL(triggered()), this, SLOT(selectAttachment()) ); @@ -665,6 +604,7 @@ QMailMessage EmailComposerInterface::message() const disposition.setFilename(partName.toLatin1()); QMailMessagePart part = QMailMessagePart::fromFile(filePath, disposition, type, QMailMessageBody::Base64, QMailMessageBody::RequiresEncoding); + part.setContentLocation(QUrl::fromLocalFile(filePath).toString()); mail.appendPart(part); } } @@ -682,27 +622,7 @@ void EmailComposerInterface::clear() m_bodyEdit->clear(); m_attachmentListWidget->clear(); - //m_addAttDialog->clear(); - - // Delete any temporary files we don't need - /* - foreach (const AttachmentDetail &att, m_attachments) { - if (att.second == QMailMessage::CopyAndDeleteAttachments) { - const_cast<QContent&>(att.first).removeFiles(); - } - } - - m_attachments.clear(); - */ -} - -/* -void EmailComposerInterface::attach( const QContent &lnk, QMailMessage::AttachmentsAction action ) -{ - m_attachments.append(qMakePair(lnk, action)); - m_addAttDialog->attach(lnk, action); } -*/ void EmailComposerInterface::setSignature( const QString &sig ) { @@ -760,42 +680,16 @@ void EmailComposerInterface::create(const QMailMessage& sourceMail) int textPart = -1; for ( uint i = 0; i < sourceMail.partCount(); ++i ) { QMailMessagePart &part = const_cast<QMailMessagePart&>(sourceMail.partAt(i)); + QString contentLocation = part.contentLocation().remove(QRegExp("\\s")); + bool isLocalAttachment = part.hasBody() && QFile::exists(QUrl(contentLocation).toLocalFile()); - if (textPart == -1 && part.hasBody() && (part.contentType().type().toLower() == "text")) { + if (textPart == -1 && part.hasBody() && (part.contentType().type().toLower() == "text") && !isLocalAttachment) { // This is the first text part, we will use as the forwarded text body textPart = i; - } else { - // Save the existing part data to a temporary file - QString fileName(part.writeBodyTo(QMail::tempPath())); - if (fileName.isEmpty()) { - qWarning() << "Unable to save part to temporary file!"; - } else { - /* - // Create a content object for the file - QContent doc(fileName); - - if (part.referenceType() == QMailMessagePart::None) { - QMailMessageContentType type(part.contentType()); - - if (doc.drmState() == QContent::Unprotected) - doc.setType(type.content()); - } else { - QString partLocation = part.location().toString(true); - if (!partLocation.isEmpty()) { - doc.setProperty("qtopiamail/partLocation", partLocation); - } - } - - doc.setName(part.displayName()); - doc.setRole(QContent::Data); - doc.commit(); - - attach(doc, QMailMessage::CopyAndDeleteAttachments); - */ + } else if(isLocalAttachment) { + m_attachmentListWidget->addAttachment(QUrl(contentLocation).toLocalFile()); } } - } - if (textPart != -1) { const QMailMessagePart& part = sourceMail.partAt(textPart); setPlainText( part.body().data(), m_signature ); diff --git a/src/plugins/composers/email/emailcomposer.h b/src/plugins/composers/email/emailcomposer.h index aae3a7e1..b04b0cf9 100644 --- a/src/plugins/composers/email/emailcomposer.h +++ b/src/plugins/composers/email/emailcomposer.h @@ -50,14 +50,12 @@ public: public slots: void clear(); - //void attach( const QContent &lnk, QMailMessage::AttachmentsAction = QMailMessage::LinkToAttachments ); void setSignature( const QString &sig ); protected slots: void selectAttachment(); void updateLabel(); void setCursorPosition(); - void updateAttachmentsLabel(); private: void create(const QMailMessage& source); diff --git a/src/plugins/contentmanagers/qtopiamailfile/qtopiamailfilemanager.cpp b/src/plugins/contentmanagers/qtopiamailfile/qtopiamailfilemanager.cpp index c53478ff..9a8b0a66 100644 --- a/src/plugins/contentmanagers/qtopiamailfile/qtopiamailfilemanager.cpp +++ b/src/plugins/contentmanagers/qtopiamailfile/qtopiamailfilemanager.cpp @@ -20,6 +20,7 @@ #include <unistd.h> #include <time.h> #include <QtPlugin> +#include <QUrl> namespace { @@ -62,7 +63,7 @@ QString generateUniqueFileName(const QMailAccountId &accountId, const QString &n // Format: seconds_epoch.pid.randomchars bool exists = true; const qint64 pid = ::getpid(); - + QString filename; QString path; @@ -209,10 +210,11 @@ QMailStore::ErrorCode QtopiamailfileManager::addOrRename(QMailMessage *message, // Write the message to file (not including sub-part contents) QDataStream out(&file); - message->toRfc2822(out, QMailMessage::StorageFormat); + message->toRfc2822(out, QMailMessage::StorageFormat); + bool isOk = out.status() != QDataStream::Ok; if ((out.status() != QDataStream::Ok) || // Write each part to file - ((message->multipartType() != QMailMessagePartContainer::MultipartNone) && + ((message->multipartType() != QMailMessagePartContainer::MultipartNone) && !addOrRenameParts(message, *message, message->contentIdentifier(), existingIdentifier))) { // Remove the file qMailLog(Messaging) << "Unable to save message content, removing temporary file:" << filePath; @@ -416,6 +418,12 @@ QString QtopiamailfileManager::messagePartDirectory(const QString &fileName) return fileName + "-parts"; } +static bool isLocalAttachment(const QMailMessagePart& part) +{ + QString contentLocation = part.contentLocation().remove(QRegExp("\\s")); + return QFile::exists(QUrl(contentLocation).toLocalFile()) && !part.hasBody(); +} + bool QtopiamailfileManager::addOrRenameParts(QMailMessage *message, const QMailMessagePartContainer &container, const QString &fileName, const QString &existing) { // Ensure that the part directory exists @@ -445,7 +453,7 @@ bool QtopiamailfileManager::addOrRenameParts(QMailMessage *message, const QMailM additionRequired = true; } - if (additionRequired) { + if (additionRequired && !isLocalAttachment(part)) { // We can only write the content in decoded form if it is complete QMailMessageBody::EncodingFormat outputFormat(part.contentAvailable() ? QMailMessageBody::Decoded : QMailMessageBody::Encoded); @@ -463,7 +471,7 @@ bool QtopiamailfileManager::addOrRenameParts(QMailMessage *message, const QMailM } } } - + QFile file(partFilePath); if (!file.open(QIODevice::WriteOnly)) { qMailLog(Messaging) << "Unable to open new message part content file:" << partFilePath; @@ -533,7 +541,13 @@ bool QtopiamailfileManager::loadParts(QMailMessage *message, QMailMessagePartCon } } else { if (part.multipartType() == QMailMessagePartContainer::MultipartNone) { - QString partFilePath(messagePartFilePath(part, fileName)); + QString partFilePath; + bool localAttachment = QFile::exists(QUrl(part.contentLocation()).toLocalFile()) && !part.hasBody(); + if(localAttachment) + partFilePath = QUrl(part.contentLocation()).toLocalFile(); + else + partFilePath = (messagePartFilePath(part, fileName)); + if (QFile::exists(partFilePath)) { // Is the file content in encoded or decoded form? Since we're delivering // server-side data, the parameter seems reversed... diff --git a/src/plugins/messageservices/imap/imapclient.cpp b/src/plugins/messageservices/imap/imapclient.cpp index 8a9c7b6e..af239b1a 100644 --- a/src/plugins/messageservices/imap/imapclient.cpp +++ b/src/plugins/messageservices/imap/imapclient.cpp @@ -639,8 +639,8 @@ void ImapClient::mailboxListed(QString &flags, QString &delimiter, QString &path if (boxId.isValid()) { // This element already exists if (mailboxPath == path) { - QMailFolder folder(boxId); - _strategyContext->mailboxListed(folder, flags); + QMailFolder folder(boxId); + _strategyContext->mailboxListed(folder, flags, delimiter); } parentId = boxId; @@ -650,9 +650,16 @@ void ImapClient::mailboxListed(QString &flags, QString &delimiter, QString &path folder.setDisplayName(decodeFolderName(*it)); folder.setStatus(QMailFolder::SynchronizationEnabled, true); - _strategyContext->mailboxListed(folder, flags); + // The reported flags pertain to the listed folder only + QString folderFlags; + if (mailboxPath == path) { + folderFlags = flags; + } + + _strategyContext->mailboxListed(folder, folderFlags, delimiter); boxId = mailboxId(mailboxPath); + parentId = boxId; } } } @@ -1021,13 +1028,13 @@ void ImapClient::cancelTransfer() void ImapClient::retrieveOperationCompleted() { + deactivateConnection(); + // This retrieval may have been asynchronous emit allMessagesReceived(); // Or it may have been requested by a waiting client emit retrievalCompleted(); - - deactivateConnection(); } void ImapClient::deactivateConnection() diff --git a/src/plugins/messageservices/imap/imapprotocol.cpp b/src/plugins/messageservices/imap/imapprotocol.cpp index 52a2ada6..97409ce1 100644 --- a/src/plugins/messageservices/imap/imapprotocol.cpp +++ b/src/plugins/messageservices/imap/imapprotocol.cpp @@ -1091,6 +1091,12 @@ void UidFetchState::untaggedResponse(ImapContext *c, const QString &line) parseFlags(str, fp.mNewMsgFlags); } + if (fp.mNewMsgFlags & MFlag_Deleted) { + // This message has been deleted - there is no more information to process + emit nonexistentUid(fp.mNewMsgUid); + return; + } + if (fp.mDataItems & F_Date) { fp.mDate = extractDate(str); } diff --git a/src/plugins/messageservices/imap/imapservice.cpp b/src/plugins/messageservices/imap/imapservice.cpp index 96849e04..ded9fbc4 100644 --- a/src/plugins/messageservices/imap/imapservice.cpp +++ b/src/plugins/messageservices/imap/imapservice.cpp @@ -30,6 +30,7 @@ public: _service(service), _flagsCheckQueued(false), _queuedMailCheckInProgress(false), + _mailCheckPhase(RetrieveFolders), _unavailable(false), _synchronizing(false), _actionCompletedSignal(0) @@ -81,9 +82,13 @@ public slots: private: virtual bool setStrategy(ImapStrategy *strategy, void (ImapService::Source::*signal)(const QMailMessageIdList&) = 0); + enum MailCheckPhase { RetrieveFolders = 0, RetrieveMessages, CheckFlags }; + ImapService *_service; bool _flagsCheckQueued; bool _queuedMailCheckInProgress; + MailCheckPhase _mailCheckPhase; + QMailFolderId _mailCheckFolderId; bool _unavailable; bool _synchronizing; QTimer _intervalTimer; @@ -101,6 +106,7 @@ bool ImapService::Source::retrieveFolderList(const QMailAccountId &accountId, co _service->_client.strategyContext()->foldersOnlyStrategy.setBase(folderId); _service->_client.strategyContext()->foldersOnlyStrategy.setDescending(descending); + _service->_client.strategyContext()->foldersOnlyStrategy.clearSelection(); return setStrategy(&_service->_client.strategyContext()->foldersOnlyStrategy); } @@ -119,11 +125,15 @@ bool ImapService::Source::retrieveMessageList(const QMailAccountId &accountId, c if (folderId.isValid()) { folderIds.append(folderId); } else { - // Retrieve messages for all folders in the account - folderIds = QMailStore::instance()->queryFolders(QMailFolderKey::parentAccountId(accountId), QMailFolderSortKey::id(Qt::AscendingOrder)); + // Retrieve messages for all folders in the account that have undiscovered messages + QMailFolderKey accountKey(QMailFolderKey::parentAccountId(accountId)); + QMailFolderKey undiscoveredKey(QMailFolderKey::serverUndiscoveredCount(0, QMailDataComparator::GreaterThan)); + + folderIds = QMailStore::instance()->queryFolders(accountKey & undiscoveredKey, QMailFolderSortKey::id(Qt::AscendingOrder)); } _service->_client.strategyContext()->retrieveMessageListStrategy.setMinimum(minimum); + _service->_client.strategyContext()->retrieveMessageListStrategy.clearSelection(); _service->_client.strategyContext()->retrieveMessageListStrategy.selectedFoldersAppend(folderIds); return setStrategy(&_service->_client.strategyContext()->retrieveMessageListStrategy); } @@ -227,6 +237,7 @@ bool ImapService::Source::retrieveAll(const QMailAccountId &accountId) _service->_client.strategyContext()->retrieveAllStrategy.setBase(QMailFolderId()); _service->_client.strategyContext()->retrieveAllStrategy.setDescending(true); + _service->_client.strategyContext()->retrieveAllStrategy.clearSelection(); _service->_client.strategyContext()->retrieveAllStrategy.setOperation(QMailRetrievalAction::MetaData); return setStrategy(&_service->_client.strategyContext()->retrieveAllStrategy); } @@ -237,11 +248,8 @@ bool ImapService::Source::exportUpdates(const QMailAccountId &accountId) _service->errorOccurred(QMailServiceAction::Status::ErrInvalidData, tr("No account specified")); return false; } - _service->_client.strategyContext()->exportUpdatesStrategy.setBase(QMailFolderId()); - _service->_client.strategyContext()->exportUpdatesStrategy.setDescending(true); - _service->_client.strategyContext()->exportUpdatesStrategy.setOperation(QMailRetrievalAction::Content); + _service->_client.strategyContext()->exportUpdatesStrategy.clearSelection(); - _service->_client.strategyContext()->exportUpdatesStrategy.selectedMailsAppend(QMailMessageIdList()); return setStrategy(&_service->_client.strategyContext()->exportUpdatesStrategy); } @@ -254,6 +262,7 @@ bool ImapService::Source::synchronize(const QMailAccountId &accountId) _service->_client.strategyContext()->synchronizeAccountStrategy.setBase(QMailFolderId()); _service->_client.strategyContext()->synchronizeAccountStrategy.setDescending(true); + _service->_client.strategyContext()->synchronizeAccountStrategy.clearSelection(); _service->_client.strategyContext()->synchronizeAccountStrategy.setOperation(QMailRetrievalAction::MetaData); return setStrategy(&_service->_client.strategyContext()->synchronizeAccountStrategy); } @@ -388,8 +397,13 @@ void ImapService::Source::retrievalCompleted() _unavailable = false; if (_queuedMailCheckInProgress) { - _queuedMailCheckInProgress = false; - emit _service->availabilityChanged(true); + if (_mailCheckPhase == RetrieveFolders) { + _mailCheckPhase = RetrieveMessages; + retrieveMessageList(_service->accountId(), _mailCheckFolderId, 1, QMailMessageSortKey()); + } else { + _queuedMailCheckInProgress = false; + emit _service->availabilityChanged(true); + } } emit _service->activityChanged(QMailServiceAction::Successful); @@ -431,9 +445,11 @@ void ImapService::Source::queueMailCheck(QMailFolderId folderId) _queuedFolders.removeAll(folderId); _queuedMailCheckInProgress = true; + _mailCheckPhase = RetrieveFolders; + _mailCheckFolderId = folderId; emit _service->availabilityChanged(false); - retrieveMessageList(_service->accountId(), folderId, 1, QMailMessageSortKey()); + retrieveFolderList(_service->accountId(), folderId, true); } void ImapService::Source::queueFlagsChangedCheck() @@ -445,6 +461,7 @@ void ImapService::Source::queueFlagsChangedCheck() _flagsCheckQueued = false; _queuedMailCheckInProgress = true; + _mailCheckPhase = CheckFlags; emit _service->availabilityChanged(false); diff --git a/src/plugins/messageservices/imap/imapstrategy.cpp b/src/plugins/messageservices/imap/imapstrategy.cpp index 5dc1fce8..7d3add87 100644 --- a/src/plugins/messageservices/imap/imapstrategy.cpp +++ b/src/plugins/messageservices/imap/imapstrategy.cpp @@ -92,21 +92,12 @@ static void updateMessagesMetaData(ImapStrategyContextBase *context, context->completedMessageAction(uid); } - // Compensate for MS exchange temporarily failing to report existence of messages - QMailMessageKey existentUidKey(storedKey & reportedKey); - QMailMessageKey removedUidKey(QMailMessageKey::status(QMailMessage::Removed, QMailDataComparator::Includes)); - QMailMessageKey onServerButRemovedInStore(removedUidKey & existentUidKey); - if (!QMailStore::instance()->updateMessagesMetaData(onServerButRemovedInStore, QMailMessage::Removed, false)) { - qWarning() << "Unable to update unremoved message metadata for account:" << context->config().id(); - } - // Update any messages that are reported as read elsewhere, that previously were not if (!QMailStore::instance()->updateMessagesMetaData(seenKey & unreadElsewhereKey, QMailMessage::ReadElsewhere, true)) { qWarning() << "Unable to update read message metadata for account:" << context->config().id(); } } - ImapClient *ImapStrategyContextBase::client() { return _client; @@ -164,6 +155,9 @@ void ImapStrategy::newConnection(ImapStrategyContextBase *context) { _transferState = Init; + ImapConfiguration imapCfg(context->config()); + _baseFolder = imapCfg.baseFolder(); + initialAction(context); } @@ -180,11 +174,18 @@ void ImapStrategy::initialAction(ImapStrategyContextBase *context) } } -void ImapStrategy::mailboxListed(ImapStrategyContextBase *, QMailFolder& folder, const QString &flags) +void ImapStrategy::mailboxListed(ImapStrategyContextBase *, QMailFolder& folder, const QString &flags, const QString &delimiter) { if (!folder.id().isValid()) { - if (!QMailStore::instance()->addFolder(&folder)) { - qWarning() << "Unable to add folder for account:" << folder.parentAccountId() << "path:" << folder.path(); + // Only folders beneath the base folder are relevant + QString path(folder.path()); + + if (_baseFolder.isEmpty() || + (path.startsWith(_baseFolder, Qt::CaseInsensitive) && (path.length() == _baseFolder.length())) || + (path.startsWith(_baseFolder + delimiter, Qt::CaseInsensitive))) { + if (!QMailStore::instance()->addFolder(&folder)) { + qWarning() << "Unable to add folder for account:" << folder.parentAccountId() << "path:" << folder.path(); + } } } @@ -263,7 +264,7 @@ void ImapStrategy::downloadSize(ImapStrategyContextBase *context, const QString /* A strategy that provides an interface for defining a set of messages - or message parts to operate on, and an abstract interface messageAction() + or message parts to operate on, and an abstract interface messageListMessageAction() for operating on messages. Also implements logic to determine which messages or message part to operate @@ -272,6 +273,7 @@ void ImapStrategy::downloadSize(ImapStrategyContextBase *context, const QString void ImapMessageListStrategy::clearSelection() { _selectionMap.clear(); + _folderItr = _selectionMap.end(); } void ImapMessageListStrategy::selectedMailsAppend(const QMailMessageIdList& ids) @@ -345,13 +347,13 @@ void ImapMessageListStrategy::transition(ImapStrategyContextBase *context, ImapC void ImapMessageListStrategy::handleLogin(ImapStrategyContextBase *context) { - messageAction(context); + messageListMessageAction(context); } void ImapMessageListStrategy::handleSelect(ImapStrategyContextBase *context) { // We're completing a message or section - messageAction(context); + messageListMessageAction(context); } bool ImapMessageListStrategy::computeStartEndPartRange(ImapStrategyContextBase *context) @@ -384,6 +386,11 @@ bool ImapMessageListStrategy::selectNextMessageSequence(ImapStrategyContextBase QMailMessagePart::Location location; int minimum = SectionProperties::All; + if (_folderItr == _selectionMap.end()) { + messageListCompleted(context); + return false; + } + FolderMap::ConstIterator selectionEnd = _folderItr.value().end(); while (_selectionItr == selectionEnd) { ++_folderItr; @@ -396,7 +403,7 @@ bool ImapMessageListStrategy::selectNextMessageSequence(ImapStrategyContextBase if ((_folderItr == _selectionMap.end()) || !_folderItr.key().isValid()) { _currentMailbox = QMailFolder(); _selectionMap.clear(); - folderAction(context); + messageListFolderAction(context); return false; } @@ -404,7 +411,7 @@ bool ImapMessageListStrategy::selectNextMessageSequence(ImapStrategyContextBase mailboxId = _folderItr.key(); if (mailboxId != _currentMailbox.id()) { _currentMailbox = QMailFolder(mailboxId); - folderAction(context); + messageListFolderAction(context); return false; } mailboxIdStr = QString::number(mailboxId.toULongLong()) + '|'; @@ -443,7 +450,7 @@ bool ImapMessageListStrategy::selectNextMessageSequence(ImapStrategyContextBase return true; } -void ImapMessageListStrategy::folderAction(ImapStrategyContextBase *context) +void ImapMessageListStrategy::messageListFolderAction(ImapStrategyContextBase *context) { if (_currentMailbox.id().isValid()) { if (_currentMailbox.id() == context->mailbox().id) { @@ -453,11 +460,11 @@ void ImapMessageListStrategy::folderAction(ImapStrategyContextBase *context) context->protocol().sendSelect(_currentMailbox); } } else { - completedAction(context); + messageListCompleted(context); } } -void ImapMessageListStrategy::completedAction(ImapStrategyContextBase *context) +void ImapMessageListStrategy::messageListCompleted(ImapStrategyContextBase *context) { context->operationCompleted(); } @@ -586,15 +593,15 @@ void ImapFetchSelectedMessagesStrategy::handleLogin(ImapStrategyContextBase *con if (_totalRetrievalSize) context->progressChanged(0, _totalRetrievalSize); - messageAction(context); + messageListMessageAction(context); } void ImapFetchSelectedMessagesStrategy::handleUidFetch(ImapStrategyContextBase *context) { - messageAction(context); + messageListMessageAction(context); } -void ImapFetchSelectedMessagesStrategy::messageAction(ImapStrategyContextBase *context) +void ImapFetchSelectedMessagesStrategy::messageListMessageAction(ImapStrategyContextBase *context) { if (selectNextMessageSequence(context)) { QStringList uids; @@ -712,14 +719,14 @@ void ImapFolderListStrategy::handleLogin(ImapStrategyContextBase *context) { _transferState = List; - processNextMailbox(context); + processNextFolder(context); } void ImapFolderListStrategy::handleList(ImapStrategyContextBase *context) { if (!_currentMailbox.id().isValid()) { // Try to proceed to another mailbox - processNextMailbox(context); + processNextFolder(context); } else { // If the current folder is not yet selected if (_currentMailbox.id() != context->mailbox().id) { @@ -727,7 +734,7 @@ void ImapFolderListStrategy::handleList(ImapStrategyContextBase *context) FolderStatus folderState = _folderStatus[_currentMailbox.id()]; if (folderState & NoSelect) { // We can't select this folder - processNextMailbox(context); + processNextFolder(context); } else { // Select this folder context->protocol().sendSelect( _currentMailbox ); @@ -735,11 +742,11 @@ void ImapFolderListStrategy::handleList(ImapStrategyContextBase *context) } } else { // This folder does not exist, according to the listing... - processNextMailbox(context); + processNextFolder(context); } } else { // This mailbox is selected - processMailbox(context); + folderListFolderAction(context); } } } @@ -750,14 +757,19 @@ void ImapFolderListStrategy::handleSelect(ImapStrategyContextBase *context) // We have selected this folder - find out how many undiscovered messages exist // We need the UID of the most recent message we have previously discovered in this folder - QMailMessageKey key(QMailMessageKey::parentFolderId(_currentMailbox.id())); - QMailMessageSortKey sortKey(QMailMessageSortKey::id(Qt::DescendingOrder)); - - QMailMessageIdList messageIds(QMailStore::instance()->queryMessages(key, sortKey)); - if (!messageIds.isEmpty()) { - // Find this message's MSN - QMailMessageMetaData message(messageIds.first()); - context->protocol().sendSearch(0, QString("UID ") + ImapProtocol::uid(message.serverUid())); + QMailFolderId folderId(context->mailbox().id); + QMailFolder folder(folderId); + + // toUint returns 0 on error, which is an invalid IMAP uid + int clientMax(folder.customField("qmf-max-serveruid").toUInt()); + + if (clientMax && context->mailbox().exists) { + if (context->mailbox().uidNext > (clientMax + 1)) { + context->protocol().sendSearch(0, QString("UID %1:%2").arg(clientMax + 1).arg(context->mailbox().uidNext)); + } else { + // There's no need to search if (clientMax <= (UIDNEXT - 1)) + handleSearch(context); + } } else { // No messages - nothing to discover... handleSearch(context); @@ -772,29 +784,28 @@ void ImapFolderListStrategy::handleSearch(ImapStrategyContextBase *context) updateUndiscoveredCount(context); // We have finished with this folder - processMailbox(context); + folderListFolderAction(context); } -void ImapFolderListStrategy::processMailbox(ImapStrategyContextBase *context) +void ImapFolderListStrategy::folderListFolderAction(ImapStrategyContextBase *context) { // The current mailbox is now selected - subclasses clients should do something now // Go onto the next mailbox - processNextMailbox(context); + processNextFolder(context); } -void ImapFolderListStrategy::processNextMailbox(ImapStrategyContextBase *context) +void ImapFolderListStrategy::processNextFolder(ImapStrategyContextBase *context) { - if (getnextMailbox()) { - newfolderAction(context); + if (nextFolder()) { + processFolder(context); return; } - listCompleted(context); + folderListCompleted(context); } -// TODO: change this name -bool ImapFolderListStrategy::getnextMailbox() +bool ImapFolderListStrategy::nextFolder() { while (!_mailboxIds.isEmpty()) { QMailFolderId folderId(_mailboxIds.takeFirst()); @@ -818,70 +829,57 @@ bool ImapFolderListStrategy::getnextMailbox() return false; } -// TODO: change this name -void ImapFolderListStrategy::newfolderAction(ImapStrategyContextBase *context) +void ImapFolderListStrategy::processFolder(ImapStrategyContextBase *context) { - if (_folderStatus.contains(_currentMailbox.id())) { - // We already have the status for this folder - select it - context->protocol().sendSelect(_currentMailbox); - } else { - // List the contents of the parent of this folder, to see if we can select it - QMailFolderId parentFolderId(_currentMailbox.parentFolderId()); - if (parentFolderId.isValid()) { - context->protocol().sendList(QMailFolder(parentFolderId), "%"); - } else { - QMailFolder root; - ImapConfiguration imapCfg(context->config()); - if (!imapCfg.baseFolder().isEmpty()) { - root.setPath(imapCfg.baseFolder()); - } - - context->protocol().sendList(root, "%"); - } - } + // Attempt to select the current folder + context->protocol().sendSelect(_currentMailbox); } -void ImapFolderListStrategy::listCompleted(ImapStrategyContextBase *context) +void ImapFolderListStrategy::folderListCompleted(ImapStrategyContextBase *context) { - // We have retrieved all the folders - completedAction(context); + // We have retrieved all the folders - process any messages + messageListMessageAction(context); } -void ImapFolderListStrategy::mailboxListed(ImapStrategyContextBase *context, QMailFolder &folder, const QString &flags) +void ImapFolderListStrategy::mailboxListed(ImapStrategyContextBase *context, QMailFolder &folder, const QString &flags, const QString &delimiter) { - ImapStrategy::mailboxListed(context, folder, flags); + ImapStrategy::mailboxListed(context, folder, flags, delimiter); - // Record the status of the listed mailbox - int status = 0; - if (flags.indexOf("NoInferiors", 0, Qt::CaseInsensitive) != -1) - status |= NoInferiors; - if (flags.indexOf("NoSelect", 0, Qt::CaseInsensitive) != -1) - status |= NoSelect; - if (flags.indexOf("Marked", 0, Qt::CaseInsensitive) != -1) - status |= Marked; - if (flags.indexOf("Unmarked", 0, Qt::CaseInsensitive) != -1) - status |= Unmarked; - if (flags.indexOf("HasChildren", 0, Qt::CaseInsensitive) != -1) - status |= HasChildren; - if (flags.indexOf("HasNoChildren", 0, Qt::CaseInsensitive) != -1) - status |= HasNoChildren; + if (folder.id().isValid()) { + // Record the status of the listed mailbox + int status = 0; + if (flags.indexOf("NoInferiors", 0, Qt::CaseInsensitive) != -1) + status |= NoInferiors; + if (flags.indexOf("NoSelect", 0, Qt::CaseInsensitive) != -1) + status |= NoSelect; + if (flags.indexOf("Marked", 0, Qt::CaseInsensitive) != -1) + status |= Marked; + if (flags.indexOf("Unmarked", 0, Qt::CaseInsensitive) != -1) + status |= Unmarked; + if (flags.indexOf("HasChildren", 0, Qt::CaseInsensitive) != -1) + status |= HasChildren; + if (flags.indexOf("HasNoChildren", 0, Qt::CaseInsensitive) != -1) + status |= HasNoChildren; - _folderStatus[folder.id()] = static_cast<FolderStatus>(status); + _folderStatus[folder.id()] = static_cast<FolderStatus>(status); + } } void ImapFolderListStrategy::updateUndiscoveredCount(ImapStrategyContextBase *context) { - // We should have the MSN of the our most recent message - uint msn = 0; - if (!context->mailbox().msnList.isEmpty()) { - msn = context->mailbox().msnList.first(); - } + // Initial case set the undiscovered count to exists in the case of no + // max-serveruid set for the folder + int undiscovered(context->mailbox().exists); - // The difference between the server count and the MSN of our message should yield the undiscovered count - // Note: MSN is 1-based, count is 0-based. QMailFolder folder(_currentMailbox.id()); - int undiscovered = folder.serverCount() - msn; - if ((undiscovered >= 0) && (uint(undiscovered) != folder.serverUndiscoveredCount())) { + int clientMax(folder.customField("qmf-max-serveruid").toUInt()); + if (clientMax) { + // The undiscovered count for a folder is the number of messages on the server newer + // than the most recent (highest server uid) message in the folder. + undiscovered = context->mailbox().msnList.count(); + } + + if (uint(undiscovered) != folder.serverUndiscoveredCount()) { folder.setServerUndiscoveredCount(undiscovered); if (!QMailStore::instance()->updateFolder(&folder)) { @@ -917,7 +915,7 @@ void ImapSynchronizeBaseStrategy::handleSelect(ImapStrategyContextBase *context) fetchNextMailPreview(context); } else if (_transferState == Complete) { // We're completing a message or section - messageAction(context); + messageListMessageAction(context); } else { ImapFolderListStrategy::handleSelect(context); } @@ -928,7 +926,7 @@ void ImapSynchronizeBaseStrategy::handleUidFetch(ImapStrategyContextBase *contex if (_transferState == Preview) { //getting headers fetchNextMailPreview(context); } else if (_transferState == Complete) { //getting complete messages - messageAction(context); + messageListMessageAction(context); } } @@ -952,52 +950,44 @@ void ImapSynchronizeBaseStrategy::previewDiscoveredMessages(ImapStrategyContextB _transferState = Preview; - if (!selectNextMailbox(context)) { + if (!selectNextPreviewFolder(context)) { // Could be no mailbox has been selected to be stored locally - completedAction(context); + messageListCompleted(context); } } -bool ImapSynchronizeBaseStrategy::selectNextMailbox(ImapStrategyContextBase *context) +bool ImapSynchronizeBaseStrategy::selectNextPreviewFolder(ImapStrategyContextBase *context) { - _newUids = QStringList(); + if (_retrieveUids.isEmpty()) { + _currentMailbox = QMailFolder(); + _newUids = QStringList(); + return false; + } - if (nextMailbox(context)) { - FolderStatus folderState = _folderStatus[_currentMailbox.id()]; - if (folderState & NoSelect) { - // Bypass the select and UID search, and go directly to the search result handler - processUidSearchResults(context); - } else { - if (_currentMailbox.id() == context->mailbox().id) { - // We already have the appropriate mailbox selected - handleSelect(context); - } else { - if (_transferState == List) { - QString status = QObject::tr("Checking", "Checking <mailbox name>") + QChar(' ') + _currentMailbox.displayName(); - context->updateStatus( status ); - } + // In preview mode, select the mailboxes where retrievable messages are located + QPair<QMailFolderId, QStringList> next = _retrieveUids.takeFirst(); + _currentMailbox = QMailFolder(next.first); + _newUids = next.second; - context->protocol().sendSelect( _currentMailbox ); - } - } - return true; + FolderStatus folderState = _folderStatus[_currentMailbox.id()]; + if (folderState & NoSelect) { + // Bypass the select and UID search, and go directly to the search result handler + processUidSearchResults(context); } else { - return false; - } -} + if (_currentMailbox.id() == context->mailbox().id) { + // We already have the appropriate mailbox selected + handleSelect(context); + } else { + if (_transferState == List) { + QString status = QObject::tr("Checking", "Checking <mailbox name>") + QChar(' ') + _currentMailbox.displayName(); + context->updateStatus( status ); + } -bool ImapSynchronizeBaseStrategy::nextMailbox(ImapStrategyContextBase *) -{ - if ((_transferState == Preview) && !_retrieveUids.isEmpty()) { - // In fetch mode, return the mailboxes where retrievable messages are located - QPair<QMailFolderId, QStringList> next = _retrieveUids.takeFirst(); - _currentMailbox = QMailFolder(next.first); - _newUids = next.second; - return true; + context->protocol().sendSelect( _currentMailbox ); + } } - _currentMailbox = QMailFolder(); - return false; + return true; } void ImapSynchronizeBaseStrategy::fetchNextMailPreview(ImapStrategyContextBase *context) @@ -1010,13 +1000,19 @@ void ImapSynchronizeBaseStrategy::fetchNextMailPreview(ImapStrategyContextBase * context->protocol().sendUidFetch(MetaDataFetchFlags, IntegerRegion(uidList).toString()); _newUids = _newUids.mid(uidList.count()); - } else if (!selectNextMailbox(context)) { + return; + } + + previewingCompleted(context); + if (!selectNextPreviewFolder(context)) { + // No more messages to preview if ((_transferState == Preview) || (_retrieveUids.isEmpty())) { if (!_completionList.isEmpty() || !_completionSectionList.isEmpty()) { // Fetch the messages that need completion clearSelection(); + selectedMailsAppend(_completionList); - _completionList.clear(); + QList<QPair<QMailMessagePart::Location, uint> >::const_iterator it = _completionSectionList.begin(), end = _completionSectionList.end(); for ( ; it != end; ++it) { if (it->second != 0) { @@ -1025,15 +1021,23 @@ void ImapSynchronizeBaseStrategy::fetchNextMailPreview(ImapStrategyContextBase * selectedSectionsAppend(it->first); } } + + _completionList.clear(); _completionSectionList.clear(); - messageAction(context); + + messageListMessageAction(context); } else { - completedAction(context); + // No messages to be completed + messageListCompleted(context); } } } } +void ImapSynchronizeBaseStrategy::previewingCompleted(ImapStrategyContextBase *) +{ +} + void ImapSynchronizeBaseStrategy::recursivelyCompleteParts(ImapStrategyContextBase *context, const QMailMessagePartContainer &partContainer, int &partsToRetrieve, @@ -1137,6 +1141,7 @@ void ImapRetrieveFolderListStrategy::setDescending(bool descending) void ImapRetrieveFolderListStrategy::newConnection(ImapStrategyContextBase *context) { _mailboxList.clear(); + _ancestorPaths.clear(); ImapSynchronizeBaseStrategy::newConnection(context); } @@ -1151,8 +1156,6 @@ void ImapRetrieveFolderListStrategy::handleLogin(ImapStrategyContextBase *contex ImapConfiguration imapCfg(context->config()); if (_baseId.isValid()) { folderId = _baseId; - } else { - folderId = context->client()->mailboxId(imapCfg.baseFolder()); } _transferState = List; @@ -1163,12 +1166,7 @@ void ImapRetrieveFolderListStrategy::handleLogin(ImapStrategyContextBase *contex ImapSynchronizeBaseStrategy::handleLogin(context); } else { // We need to search for folders at the account root - QMailFolder root; - if (!imapCfg.baseFolder().isEmpty()) { - root.setPath(imapCfg.baseFolder()); - } - - context->protocol().sendList(root, "%"); + context->protocol().sendList(QMailFolder(), "%"); } } @@ -1182,41 +1180,73 @@ void ImapRetrieveFolderListStrategy::handleSearch(ImapStrategyContextBase *conte // Find the child folders of this mailbox context->protocol().sendList(_currentMailbox, "%"); } else { - processMailbox(context); + folderListFolderAction(context); + } +} + +void ImapRetrieveFolderListStrategy::handleList(ImapStrategyContextBase *context) +{ + if (!_currentMailbox.id().isValid()) { + // See if there are any more ancestors to search + if (!_ancestorSearchPaths.isEmpty()) { + QMailFolder ancestor; + ancestor.setPath(_ancestorSearchPaths.takeFirst()); + + context->protocol().sendList(ancestor, "%"); + return; + } } + + ImapSynchronizeBaseStrategy::handleList(context); } -void ImapRetrieveFolderListStrategy::processNextMailbox(ImapStrategyContextBase *context) +void ImapRetrieveFolderListStrategy::processNextFolder(ImapStrategyContextBase *context) { - if (getnextMailbox()) { - newfolderAction(context); + if (nextFolder()) { + processFolder(context); return; } // We should have discovered all available mailboxes now _mailboxList = context->client()->mailboxIds(); - listCompleted(context); + folderListCompleted(context); } -void ImapRetrieveFolderListStrategy::listCompleted(ImapStrategyContextBase *context) +void ImapRetrieveFolderListStrategy::folderListCompleted(ImapStrategyContextBase *context) { removeDeletedMailboxes(context); - // We have retrieved all the folders - completedAction(context); + // We have retrieved all the folders - process any messages + messageListMessageAction(context); } -void ImapRetrieveFolderListStrategy::mailboxListed(ImapStrategyContextBase *context, QMailFolder &folder, const QString &flags) +void ImapRetrieveFolderListStrategy::mailboxListed(ImapStrategyContextBase *context, QMailFolder &folder, const QString &flags, const QString &delimiter) { - ImapSynchronizeBaseStrategy::mailboxListed(context, folder, flags); + ImapSynchronizeBaseStrategy::mailboxListed(context, folder, flags, delimiter); _mailboxPaths.append(folder.path()); if (_descending) { - if (folder.id() != _currentMailbox.id()) { - // We need to list this folder's contents, too - selectedFoldersAppend(QMailFolderIdList() << folder.id()); + QString path(folder.path()); + + if (folder.id().isValid()) { + if (folder.id() != _currentMailbox.id()) { + if (_baseFolder.isEmpty() || + (path.startsWith(_baseFolder, Qt::CaseInsensitive) && (path.length() == _baseFolder.length())) || + (path.startsWith(_baseFolder + delimiter, Qt::CaseInsensitive))) { + // We need to list this folder's contents, too + selectedFoldersAppend(QMailFolderIdList() << folder.id()); + } + } + } else { + if (!_ancestorPaths.contains(path)) { + if (_baseFolder.startsWith(path + delimiter, Qt::CaseInsensitive)) { + // This folder must be an ancestor of the base folder - list its contents + _ancestorPaths.insert(path); + _ancestorSearchPaths.append(path); + } + } } } } @@ -1258,7 +1288,7 @@ void ImapRetrieveFolderListStrategy::removeDeletedMailboxes(ImapStrategyContextB */ ImapSynchronizeAllStrategy::ImapSynchronizeAllStrategy() { - _options = (Options)(RetrieveMail | ImportChanges | ExportChanges); + _options = static_cast<Options>(RetrieveMail | ImportChanges | ExportChanges); } void ImapSynchronizeAllStrategy::setOptions(Options options) @@ -1295,42 +1325,6 @@ void ImapSynchronizeAllStrategy::transition(ImapStrategyContextBase *context, Im } } -void ImapSynchronizeAllStrategy::listCompleted(ImapStrategyContextBase *context) -{ - removeDeletedMailboxes(context); - - previewDiscoveredMessages(context); -} - -bool ImapSynchronizeAllStrategy::selectNextMailbox(ImapStrategyContextBase *context) -{ - _seenUids = QStringList(); - _unseenUids = QStringList(); - _readUids = QStringList(); - _removedUids = QStringList(); - _expungeRequired = false; - - _searchState = Seen; - return ImapRetrieveFolderListStrategy::selectNextMailbox(context); -} - -void ImapSynchronizeAllStrategy::handleSelect(ImapStrategyContextBase *context) -{ - // We have selected the current mailbox - if (_transferState == List) { - // We're searching mailboxes - if (context->mailbox().exists > 0) { - // Start by looking for previously-seen and unseen messages - context->protocol().sendUidSearch(MFlag_Seen); - } else { - // No messages, so no need to perform search - processUidSearchResults(context); - } - } else { - ImapRetrieveFolderListStrategy::handleSelect(context); - } -} - void ImapSynchronizeAllStrategy::handleUidSearch(ImapStrategyContextBase *context) { switch(_searchState) @@ -1339,8 +1333,14 @@ void ImapSynchronizeAllStrategy::handleUidSearch(ImapStrategyContextBase *contex { _seenUids = context->mailbox().uidList; - _searchState = Unseen; - context->protocol().sendUidSearch(MFlag_Unseen); + if (_seenUids.count() == context->mailbox().exists) { + // All of the messages are seen + _unseenUids.clear(); + processUidSearchResults(context); + } else { + _searchState = Unseen; + context->protocol().sendUidSearch(MFlag_Unseen); + } break; } case Unseen: @@ -1378,16 +1378,55 @@ void ImapSynchronizeAllStrategy::handleUidSearch(ImapStrategyContextBase *contex } } +void ImapSynchronizeAllStrategy::handleUidStore(ImapStrategyContextBase *context) +{ + if (!(_options & ExportChanges)) { + processNextFolder(context); + return; + } + if (!setNextSeen(context)) + if (!setNextDeleted(context)) + processNextFolder(context); +} + +void ImapSynchronizeAllStrategy::handleExpunge(ImapStrategyContextBase *context) +{ + processNextFolder(context); +} + +void ImapSynchronizeAllStrategy::folderListFolderAction(ImapStrategyContextBase *context) +{ + _seenUids = QStringList(); + _unseenUids = QStringList(); + _readUids = QStringList(); + _removedUids = QStringList(); + _expungeRequired = false; + + // Search for messages in the current mailbox + _searchState = Seen; + + if (context->mailbox().exists > 0) { + // Start by looking for previously-seen and unseen messages + context->protocol().sendUidSearch(MFlag_Seen); + } else { + // No messages, so no need to perform search + processUidSearchResults(context); + } +} + +void ImapSynchronizeAllStrategy::folderListCompleted(ImapStrategyContextBase *context) +{ + removeDeletedMailboxes(context); + + previewDiscoveredMessages(context); +} + void ImapSynchronizeAllStrategy::processUidSearchResults(ImapStrategyContextBase *context) { QMailFolderId boxId = _currentMailbox.id(); QMailMessageKey accountKey(QMailMessageKey::parentAccountId(context->config().id())); QMailFolder folder(boxId); - // Folder min/max invalidated - folder.removeCustomField("qmf-min-serveruid"); - folder.removeCustomField("qmf-max-serveruid"); - if ((_currentMailbox.status() & QMailFolder::SynchronizationEnabled) && !(_currentMailbox.status() & QMailFolder::Synchronized)) { // We have just synchronized this folder @@ -1446,18 +1485,7 @@ void ImapSynchronizeAllStrategy::processUidSearchResults(ImapStrategyContextBase void ImapSynchronizeAllStrategy::searchInconclusive(ImapStrategyContextBase *context) { - fetchNextMailPreview(context); -} - -void ImapSynchronizeAllStrategy::handleUidStore(ImapStrategyContextBase *context) -{ - if (!(_options & ExportChanges)) { - fetchNextMailPreview(context); - return; - } - if (!setNextSeen(context)) - if (!setNextDeleted(context)) - fetchNextMailPreview(context); + processNextFolder(context); } bool ImapSynchronizeAllStrategy::setNextSeen(ImapStrategyContextBase *context) @@ -1503,16 +1531,21 @@ bool ImapSynchronizeAllStrategy::setNextDeleted(ImapStrategyContextBase *context return false; } -void ImapSynchronizeAllStrategy::handleExpunge(ImapStrategyContextBase *context) +void ImapSynchronizeAllStrategy::previewingCompleted(ImapStrategyContextBase *context) { - fetchNextMailPreview(context); -} + QMailFolder folder(context->mailbox().id); + if (context->mailbox().exists > 0) { + folder.setCustomField("qmf-min-serveruid", QString::number(1)); + folder.setCustomField("qmf-max-serveruid", QString::number(context->mailbox().uidNext - 1)); + folder.setServerUndiscoveredCount(0); -void ImapSynchronizeAllStrategy::fetchNextMailPreview(ImapStrategyContextBase *context) -{ - ImapRetrieveFolderListStrategy::fetchNextMailPreview(context); + if (!QMailStore::instance()->updateFolder(&folder)) { + qWarning() << "Unable to update folder for account:" << context->config().id(); + } + } } + /* A strategy to retrieve all messages from an account. That is to retrieve message previews for all known messages @@ -1520,91 +1553,92 @@ void ImapSynchronizeAllStrategy::fetchNextMailPreview(ImapStrategyContextBase *c */ ImapRetrieveAllStrategy::ImapRetrieveAllStrategy() { - setOptions((Options)(RetrieveMail | ImportChanges)); + // This is just synchronize without update-exporting + setOptions(static_cast<Options>(RetrieveMail | ImportChanges)); } + /* A strategy to exports changes made on the client to the server. That is to export flag changes (unseen -> seen) and deletes. */ ImapExportUpdatesStrategy::ImapExportUpdatesStrategy() { - setOptions((Options)(ExportChanges)); + setOptions(ExportChanges); } void ImapExportUpdatesStrategy::handleLogin(ImapStrategyContextBase *context) { - ImapConfiguration imapCfg(context->config()); + _transferState = List; _completionList.clear(); _completionSectionList.clear(); - _mailboxList.clear(); + + ImapConfiguration imapCfg(context->config()); if (!imapCfg.canDeleteMail()) { - QMailAccountId id(context->config().id()); - QString name(QMailAccount(id).name()); - qMailLog(Messaging) << "Not exporting deletions. Deleting mail is " - "disabled for account name" << name << "id" << id; - } - QMailFolderIdList folders(context->client()->mailboxIds()); - QMailMessageKey statusKey(QMailMessageKey::status(QMailMessage::Read, QMailDataComparator::Includes)); - statusKey &= ~QMailMessageKey::status(QMailMessage::ReadElsewhere, QMailDataComparator::Includes); + QString name(QMailAccount(context->config().id()).name()); + qMailLog(Messaging) << "Not exporting deletions. Deleting mail is disabled for account name" << name; + } + + QMailMessageKey statusKey(QMailMessageKey::status(QMailMessage::Read, QMailDataComparator::Includes)); + statusKey &= ~QMailMessageKey::status(QMailMessage::ReadElsewhere, QMailDataComparator::Includes); + + _folderMessageUids.clear(); + ImapClient *c(context->client()); - foreach(QMailFolderId folderId, folders) { - QStringList deletedUids; - if (imapCfg.canDeleteMail()) - deletedUids = context->client()->deletedMessages(folderId); + foreach (const QMailFolderId &folderId, context->client()->mailboxIds()) { QMailMessageKey folderKey(c->messagesKey(folderId) | c->trashKey(folderId)); + + // Find messages marked as read locally + QStringList deletedUids; QStringList readUids = c->serverUids(folderKey & statusKey); - if (!deletedUids.isEmpty() || !readUids.isEmpty()) - _mailboxList.append(folderId); + + if (imapCfg.canDeleteMail()) { + // Also find messages deleted locally + deletedUids = context->client()->deletedMessages(folderId); + } + + if (!readUids.isEmpty() || !deletedUids.isEmpty()) + _folderMessageUids.insert(folderId, qMakePair(readUids, deletedUids)); } - _transferState = List; - if (!selectNextMailbox(context)) { - // No changes to export - completedAction(context); - } + processNextFolder(context); +} + +void ImapExportUpdatesStrategy::handleUidSearch(ImapStrategyContextBase *context) +{ + _serverReportedUids = context->mailbox().uidList; + + processUidSearchResults(context); } -void ImapExportUpdatesStrategy::handleSelect(ImapStrategyContextBase *context) +void ImapExportUpdatesStrategy::folderListFolderAction(ImapStrategyContextBase *context) { - _clientDeletedUids = QStringList(); - _clientReadUids = QStringList(); _serverReportedUids = QStringList(); // We have selected the current mailbox - if (_transferState == List) { - // We're searching mailboxes - if (context->mailbox().exists > 0) { - // Only interested in messages that are going to be operated on - ImapConfiguration imapCfg(context->config()); - QMailFolderId folderId(_currentMailbox.id()); - QMailMessageKey statusKey(QMailMessageKey::status(QMailMessage::Read, QMailDataComparator::Includes)); - statusKey &= ~QMailMessageKey::status(QMailMessage::ReadElsewhere, QMailDataComparator::Includes); - ImapClient *c(context->client()); - QMailMessageKey folderKey(c->messagesKey(folderId) | c->trashKey(folderId)); - _clientReadUids = c->serverUids(folderKey & statusKey); - if (imapCfg.canDeleteMail()) - _clientDeletedUids = context->client()->deletedMessages(folderId); - - if (_clientDeletedUids.isEmpty() && _clientReadUids.isEmpty()) { - processUidSearchResults(context); - return; - } - QStringList changedUids = _clientDeletedUids + _clientReadUids; - QString uidList = "UID " + stripFolderPrefix(changedUids).join(","); - context->protocol().sendUidSearch(MFlag_All, uidList); - } else { - // No messages, so no need to perform search - processUidSearchResults(context); - } + if (context->mailbox().exists > 0) { + // Find which of our messages-of-interest are still on the server + IntegerRegion clientRegion(stripFolderPrefix(_clientReadUids + _clientDeletedUids)); + context->protocol().sendUidSearch(MFlag_All, "UID " + clientRegion.toString()); } else { - ImapRetrieveFolderListStrategy::handleSelect(context); + // No messages, so no need to perform search + processUidSearchResults(context); } } -void ImapExportUpdatesStrategy::handleUidSearch(ImapStrategyContextBase *context) +bool ImapExportUpdatesStrategy::nextFolder() { - _serverReportedUids = context->mailbox().uidList; - processUidSearchResults(context); + if (_folderMessageUids.isEmpty()) { + return false; + } + + QMap<QMailFolderId, QPair<QStringList, QStringList> >::iterator it = _folderMessageUids.begin(); + + _currentMailbox = QMailFolder(it.key()); + _clientReadUids = it.value().first; + _clientDeletedUids = it.value().second; + + _folderMessageUids.erase(it); + return true; } void ImapExportUpdatesStrategy::processUidSearchResults(ImapStrategyContextBase *context) @@ -1628,7 +1662,9 @@ void ImapExportUpdatesStrategy::processUidSearchResults(ImapStrategyContextBase void ImapUpdateMessagesFlagsStrategy::clearSelection() { ImapFolderListStrategy::clearSelection(); + _monitoredFoldersIds.clear(); + _selectedMessageIds.clear(); _folderMessageUids.clear(); } @@ -1656,9 +1692,9 @@ void ImapUpdateMessagesFlagsStrategy::transition(ImapStrategyContextBase *contex void ImapUpdateMessagesFlagsStrategy::handleLogin(ImapStrategyContextBase *context) { - _serverUids.clear(); _transferState = List; - _searchState = Seen; + _serverUids.clear(); + _searchState = Unseen; // Associate each message to the relevant folder _folderMessageUids.clear(); @@ -1671,55 +1707,71 @@ void ImapUpdateMessagesFlagsStrategy::handleLogin(ImapStrategyContextBase *conte } } - processNextMailbox(context); -} - -void ImapUpdateMessagesFlagsStrategy::handleSelect(ImapStrategyContextBase *context) -{ - if (_transferState == List) { - // We're searching mailboxes - if (context->mailbox().exists > 0) { - IntegerRegion clientRegion(stripFolderPrefix(_serverUids)); - _filter = clientRegion.toString(); - _searchState = Seen; - - // Start by looking for previously-seen and unseen messages - context->protocol().sendUidSearch(MFlag_Seen, "UID " + _filter); - } else { - // No messages, so no need to perform search - processUidSearchResults(context); - } - } else { - ImapFolderListStrategy::handleSelect(context); - } + processNextFolder(context); } void ImapUpdateMessagesFlagsStrategy::handleUidSearch(ImapStrategyContextBase *context) { switch(_searchState) { - case Seen: + case Unseen: { - _seenUids = context->mailbox().uidList; + _unseenUids = context->mailbox().uidList; - _searchState = Unseen; - context->protocol().sendUidSearch(MFlag_Unseen, "UID " + _filter); + if (_unseenUids.count() == _serverUids.count()) { + // All of the messages are unseen + _seenUids.clear(); + processUidSearchResults(context); + } else { + _searchState = Seen; + context->protocol().sendUidSearch(MFlag_Seen, "UID " + _filter); + } break; } - case Unseen: + case Seen: { - _unseenUids = context->mailbox().uidList; + _seenUids = context->mailbox().uidList; processUidSearchResults(context); break; } default: qMailLog(IMAP) << "Unknown search status in transition"; Q_ASSERT(0); - completedAction(context); + + processNextFolder(context); } } -bool ImapUpdateMessagesFlagsStrategy::getnextMailbox() +void ImapUpdateMessagesFlagsStrategy::folderListFolderAction(ImapStrategyContextBase *context) +{ + if (context->mailbox().exists > 0) { + IntegerRegion clientRegion(stripFolderPrefix(_serverUids)); + _filter = clientRegion.toString(); + _searchState = Unseen; + + // Start by looking for previously-unseen messages + // If a message is moved from Unseen to Seen between our two searches, then we will + // miss this change by searching Unseen first; if, however, we were to search Seen first, + // then we would miss the message altogether and mark it as deleted... + context->protocol().sendUidSearch(MFlag_Unseen, "UID " + _filter); + } else { + // No messages, so no need to perform search + processUidSearchResults(context); + } +} + +void ImapUpdateMessagesFlagsStrategy::folderListCompleted(ImapStrategyContextBase *context) +{ + // Only allow monitoring of one folder other than the inbox + if (_monitoredFoldersIds.count() > 1) + _monitoredFoldersIds.clear(); + + context->client()->monitor(_monitoredFoldersIds); + + messageListCompleted(context); +} + +bool ImapUpdateMessagesFlagsStrategy::nextFolder() { if (_folderMessageUids.isEmpty()) { return false; @@ -1734,7 +1786,7 @@ bool ImapUpdateMessagesFlagsStrategy::getnextMailbox() return true; } -void ImapUpdateMessagesFlagsStrategy::newfolderAction(ImapStrategyContextBase *context) +void ImapUpdateMessagesFlagsStrategy::processFolder(ImapStrategyContextBase *context) { QMailFolderId folderId(_currentMailbox.id()); if ((folderId != context->client()->mailboxId("INBOX")) && @@ -1750,7 +1802,7 @@ void ImapUpdateMessagesFlagsStrategy::processUidSearchResults(ImapStrategyContex QMailFolderId folderId(_currentMailbox.id()); if (!folderId.isValid()) { // Folder was removed while we were updating messages flags in it - processNextMailbox(context); + processNextFolder(context); return; } @@ -1765,18 +1817,7 @@ void ImapUpdateMessagesFlagsStrategy::processUidSearchResults(ImapStrategyContex updateMessagesMetaData(context, storedKey, unseenKey, seenKey, unreadElsewhereKey); - processNextMailbox(context); -} - -void ImapUpdateMessagesFlagsStrategy::listCompleted(ImapStrategyContextBase *context) -{ - // Only allow monitoring of one folder other than the inbox - if (_monitoredFoldersIds.count() > 1) - _monitoredFoldersIds.clear(); - - context->client()->monitor(_monitoredFoldersIds); - - completedAction(context); + processNextFolder(context); } @@ -1819,7 +1860,7 @@ void ImapRetrieveMessageListStrategy::handleLogin(ImapStrategyContextBase *conte ImapSynchronizeBaseStrategy::handleLogin(context); } -void ImapRetrieveMessageListStrategy::completedAction(ImapStrategyContextBase *context) +void ImapRetrieveMessageListStrategy::messageListCompleted(ImapStrategyContextBase *context) { foreach (const QMailFolderId &folderId, _updatedFolders) { QMailFolder folder(folderId); @@ -1843,10 +1884,10 @@ void ImapRetrieveMessageListStrategy::completedAction(ImapStrategyContextBase *c _updatedFolders.clear(); _newMinMaxMap.clear(); - ImapSynchronizeBaseStrategy::completedAction(context); + ImapSynchronizeBaseStrategy::messageListCompleted(context); } -void ImapRetrieveMessageListStrategy::listCompleted(ImapStrategyContextBase *context) +void ImapRetrieveMessageListStrategy::folderListCompleted(ImapStrategyContextBase *context) { previewDiscoveredMessages(context); } @@ -1909,7 +1950,7 @@ void ImapRetrieveMessageListStrategy::handleUidSearch(ImapStrategyContextBase *c processUidSearchResults(context); } -void ImapRetrieveMessageListStrategy::processMailbox(ImapStrategyContextBase *context) +void ImapRetrieveMessageListStrategy::folderListFolderAction(ImapStrategyContextBase *context) { // The current mailbox is now selected QMailFolderId folderId(context->mailbox().id); @@ -1975,7 +2016,7 @@ void ImapRetrieveMessageListStrategy::processMailbox(ImapStrategyContextBase *co void ImapRetrieveMessageListStrategy::processUidSearchResults(ImapStrategyContextBase *context) { - processNextMailbox(context); + processNextFolder(context); } @@ -2044,7 +2085,7 @@ void ImapCopyMessagesStrategy::handleSelect(ImapStrategyContextBase *context) //_uidNext = context->mailbox().uidNext; // Begin copying messages - messageAction(context); + messageListMessageAction(context); } else if (_transferState == Search) { // We have selected the destination folder - find the newly added messages //context->protocol().sendUidSearch(MFlag_Recent, QString("UID %1:*").arg(ImapProtocol::uid(_uidNext))); @@ -2056,7 +2097,7 @@ void ImapCopyMessagesStrategy::handleSelect(ImapStrategyContextBase *context) void ImapCopyMessagesStrategy::handleUidCopy(ImapStrategyContextBase *context) { - messageAction(context); + messageListMessageAction(context); } void ImapCopyMessagesStrategy::handleUidSearch(ImapStrategyContextBase *context) @@ -2070,7 +2111,7 @@ void ImapCopyMessagesStrategy::handleUidFetch(ImapStrategyContextBase *context) fetchNextCopy(context); } -void ImapCopyMessagesStrategy::messageAction(ImapStrategyContextBase *context) +void ImapCopyMessagesStrategy::messageListMessageAction(ImapStrategyContextBase *context) { if (selectNextMessageSequence(context, 1)) { QStringList uids; @@ -2086,10 +2127,10 @@ void ImapCopyMessagesStrategy::messageAction(ImapStrategyContextBase *context) } } -void ImapCopyMessagesStrategy::completedAction(ImapStrategyContextBase *context) +void ImapCopyMessagesStrategy::messageListCompleted(ImapStrategyContextBase *context) { if (_transferState == Search) { - ImapFetchSelectedMessagesStrategy::completedAction(context); + ImapFetchSelectedMessagesStrategy::messageListCompleted(context); } else { // We have copied all the messages - now we need to retrieve the copies _transferState = Search; @@ -2146,7 +2187,7 @@ void ImapCopyMessagesStrategy::fetchNextCopy(ImapStrategyContextBase *context) QString firstUid = ImapProtocol::uid(_createdUids.takeFirst()); context->protocol().sendUidFetch(MetaDataFetchFlags, firstUid); } else { - completedAction(context); + messageListCompleted(context); } } @@ -2206,7 +2247,7 @@ void ImapMoveMessagesStrategy::handleUidCopy(ImapStrategyContextBase *context) void ImapMoveMessagesStrategy::handleUidStore(ImapStrategyContextBase *context) { _lastMailbox = _currentMailbox; - messageAction(context); + messageListMessageAction(context); } void ImapMoveMessagesStrategy::handleClose(ImapStrategyContextBase *context) @@ -2218,7 +2259,7 @@ void ImapMoveMessagesStrategy::handleClose(ImapStrategyContextBase *context) void ImapMoveMessagesStrategy::handleExamine(ImapStrategyContextBase *context) { // Select the next folder - ImapCopyMessagesStrategy::folderAction(context); + ImapCopyMessagesStrategy::messageListFolderAction(context); } void ImapMoveMessagesStrategy::handleUidFetch(ImapStrategyContextBase *context) @@ -2227,17 +2268,17 @@ void ImapMoveMessagesStrategy::handleUidFetch(ImapStrategyContextBase *context) fetchNextCopy(context); } -void ImapMoveMessagesStrategy::folderAction(ImapStrategyContextBase *context) +void ImapMoveMessagesStrategy::messageListFolderAction(ImapStrategyContextBase *context) { // If we're already in a mailbox, we need to close it to expunge the messages if ((context->mailbox().isSelected()) && (_lastMailbox.id().isValid())) { context->protocol().sendClose(); } else { - ImapCopyMessagesStrategy::folderAction(context); + ImapCopyMessagesStrategy::messageListFolderAction(context); } } -void ImapMoveMessagesStrategy::messageAction(ImapStrategyContextBase *context) +void ImapMoveMessagesStrategy::messageListMessageAction(ImapStrategyContextBase *context) { if (selectNextMessageSequence(context, 1)) { QStringList uids; @@ -2253,7 +2294,7 @@ void ImapMoveMessagesStrategy::messageAction(ImapStrategyContextBase *context) } } -void ImapMoveMessagesStrategy::completedAction(ImapStrategyContextBase *context) +void ImapMoveMessagesStrategy::messageListCompleted(ImapStrategyContextBase *context) { if (_transferState == Search) { // We don't need to keep the source messages any longer @@ -2266,7 +2307,7 @@ void ImapMoveMessagesStrategy::completedAction(ImapStrategyContextBase *context) } } - ImapCopyMessagesStrategy::completedAction(context); + ImapCopyMessagesStrategy::messageListCompleted(context); } static void transferPartBodies(QMailMessagePartContainer &destination, const QMailMessagePartContainer &source) @@ -2346,7 +2387,7 @@ void ImapDeleteMessagesStrategy::handleUidStore(ImapStrategyContextBase *context _storedList += _retrieveUid.split("\n"); _lastMailbox = _currentMailbox; - messageAction(context); + messageListMessageAction(context); } void ImapDeleteMessagesStrategy::handleClose(ImapStrategyContextBase *context) @@ -2369,10 +2410,10 @@ void ImapDeleteMessagesStrategy::handleClose(ImapStrategyContextBase *context) void ImapDeleteMessagesStrategy::handleExamine(ImapStrategyContextBase *context) { // Select the next folder - ImapFetchSelectedMessagesStrategy::folderAction(context); + ImapFetchSelectedMessagesStrategy::messageListFolderAction(context); } -void ImapDeleteMessagesStrategy::messageAction(ImapStrategyContextBase *context) +void ImapDeleteMessagesStrategy::messageListMessageAction(ImapStrategyContextBase *context) { if (selectNextMessageSequence(context, 1000)) { QStringList uids; @@ -2383,7 +2424,7 @@ void ImapDeleteMessagesStrategy::messageAction(ImapStrategyContextBase *context) } } -void ImapDeleteMessagesStrategy::folderAction(ImapStrategyContextBase *context) +void ImapDeleteMessagesStrategy::messageListFolderAction(ImapStrategyContextBase *context) { // If we're already in a mailbox, we need to close it to expunge the messages if ((context->mailbox().isSelected()) && (_lastMailbox.id().isValid())) { @@ -2391,17 +2432,17 @@ void ImapDeleteMessagesStrategy::folderAction(ImapStrategyContextBase *context) } else { // Select the next folder, and clear the stored list _storedList.clear(); - ImapFetchSelectedMessagesStrategy::folderAction(context); + ImapFetchSelectedMessagesStrategy::messageListFolderAction(context); } } -void ImapDeleteMessagesStrategy::completedAction(ImapStrategyContextBase *context) +void ImapDeleteMessagesStrategy::messageListCompleted(ImapStrategyContextBase *context) { // If we're already in a mailbox, we need to close it to expunge the messages if ((context->mailbox().isSelected()) && (_lastMailbox.id().isValid())) { context->protocol().sendClose(); } else { - ImapFetchSelectedMessagesStrategy::completedAction(context); + ImapFetchSelectedMessagesStrategy::messageListCompleted(context); } } diff --git a/src/plugins/messageservices/imap/imapstrategy.h b/src/plugins/messageservices/imap/imapstrategy.h index 91b1d1b6..8f7547b9 100644 --- a/src/plugins/messageservices/imap/imapstrategy.h +++ b/src/plugins/messageservices/imap/imapstrategy.h @@ -75,7 +75,7 @@ public: virtual void newConnection(ImapStrategyContextBase *context); virtual void transition(ImapStrategyContextBase*, const ImapCommand, const OperationStatus) = 0; - virtual void mailboxListed(ImapStrategyContextBase *context, QMailFolder& folder, const QString &flags); + virtual void mailboxListed(ImapStrategyContextBase *context, QMailFolder& folder, const QString &flags, const QString &delimiter); virtual void messageFetched(ImapStrategyContextBase *context, QMailMessage &message); virtual void dataFetched(ImapStrategyContextBase *context, QMailMessage &message, const QString &uid, const QString §ion); virtual void nonexistentUid(ImapStrategyContextBase *context, const QString &uid); @@ -89,6 +89,7 @@ protected: enum TransferState { Init, List, Search, Preview, Complete }; TransferState _transferState; + QString _baseFolder; }; class ImapMessageListStrategy : public ImapStrategy @@ -110,9 +111,9 @@ protected: virtual void handleLogin(ImapStrategyContextBase *context); virtual void handleSelect(ImapStrategyContextBase *context); - virtual void folderAction(ImapStrategyContextBase *context); - virtual void messageAction(ImapStrategyContextBase *context) = 0; - virtual void completedAction(ImapStrategyContextBase *context); + virtual void messageListFolderAction(ImapStrategyContextBase *context); + virtual void messageListMessageAction(ImapStrategyContextBase *context) = 0; + virtual void messageListCompleted(ImapStrategyContextBase *context); virtual bool computeStartEndPartRange(ImapStrategyContextBase *context); virtual bool selectNextMessageSequence(ImapStrategyContextBase *context, int maximum = DefaultBatchSize); @@ -149,7 +150,7 @@ protected: virtual void handleLogin(ImapStrategyContextBase *context); virtual void handleUidFetch(ImapStrategyContextBase *context); - virtual void messageAction(ImapStrategyContextBase *context); + virtual void messageListMessageAction(ImapStrategyContextBase *context); virtual void itemFetched(ImapStrategyContextBase *context, const QString &uid); @@ -176,7 +177,7 @@ public: virtual void newConnection(ImapStrategyContextBase *context); virtual void transition(ImapStrategyContextBase*, const ImapCommand, const OperationStatus); - virtual void mailboxListed(ImapStrategyContextBase *context, QMailFolder& folder, const QString &flags); + virtual void mailboxListed(ImapStrategyContextBase *context, QMailFolder& folder, const QString &flags, const QString &delimiter); protected: virtual void handleLogin(ImapStrategyContextBase *context); @@ -184,13 +185,12 @@ protected: virtual void handleSelect(ImapStrategyContextBase *context); virtual void handleSearch(ImapStrategyContextBase *context); - virtual void listCompleted(ImapStrategyContextBase *context); + virtual void folderListFolderAction(ImapStrategyContextBase *context); + virtual void folderListCompleted(ImapStrategyContextBase *context); - virtual void processMailbox(ImapStrategyContextBase *context); - - virtual void processNextMailbox(ImapStrategyContextBase *context); - virtual bool getnextMailbox(); - virtual void newfolderAction(ImapStrategyContextBase *context); + virtual void processNextFolder(ImapStrategyContextBase *context); + virtual bool nextFolder(); + virtual void processFolder(ImapStrategyContextBase *context); void updateUndiscoveredCount(ImapStrategyContextBase *context); @@ -221,15 +221,15 @@ public: protected: virtual void handleLogin(ImapStrategyContextBase *context); - virtual void handleSelect(ImapStrategyContextBase *context); virtual void handleUidSearch(ImapStrategyContextBase *context); - virtual bool getnextMailbox(); - virtual void newfolderAction(ImapStrategyContextBase *context); + virtual void folderListFolderAction(ImapStrategyContextBase *context); + virtual void folderListCompleted(ImapStrategyContextBase *context); - virtual void processUidSearchResults(ImapStrategyContextBase *context); + virtual bool nextFolder(); + virtual void processFolder(ImapStrategyContextBase *context); - virtual void listCompleted(ImapStrategyContextBase *context); + virtual void processUidSearchResults(ImapStrategyContextBase *context); private: QMailMessageIdList _selectedMessageIds; @@ -260,10 +260,10 @@ protected: virtual void handleUidFetch(ImapStrategyContextBase *context); virtual void previewDiscoveredMessages(ImapStrategyContextBase *context); - virtual bool selectNextMailbox(ImapStrategyContextBase *context); - virtual bool nextMailbox(ImapStrategyContextBase *context); + virtual bool selectNextPreviewFolder(ImapStrategyContextBase *context); virtual void fetchNextMailPreview(ImapStrategyContextBase *context); + virtual void previewingCompleted(ImapStrategyContextBase *context); virtual void processUidSearchResults(ImapStrategyContextBase *context); @@ -291,21 +291,24 @@ public: virtual void newConnection(ImapStrategyContextBase *context); - virtual void mailboxListed(ImapStrategyContextBase *context, QMailFolder& folder, const QString &flags); + virtual void mailboxListed(ImapStrategyContextBase *context, QMailFolder& folder, const QString &flags, const QString &delimiter); protected: virtual void handleLogin(ImapStrategyContextBase *context); virtual void handleSearch(ImapStrategyContextBase *context); + virtual void handleList(ImapStrategyContextBase *context); - virtual void listCompleted(ImapStrategyContextBase *context); + virtual void folderListCompleted(ImapStrategyContextBase *context); - virtual void processNextMailbox(ImapStrategyContextBase *context); + virtual void processNextFolder(ImapStrategyContextBase *context); void removeDeletedMailboxes(ImapStrategyContextBase *context); QMailFolderId _baseId; bool _descending; QStringList _mailboxPaths; + QSet<QString> _ancestorPaths; + QStringList _ancestorSearchPaths; QMailFolderIdList _mailboxList; }; @@ -323,11 +326,11 @@ protected: virtual void handleLogin(ImapStrategyContextBase *context); virtual void handleUidSearch(ImapStrategyContextBase *context); - virtual void completedAction(ImapStrategyContextBase *context); - virtual void listCompleted(ImapStrategyContextBase *context); + virtual void messageListCompleted(ImapStrategyContextBase *context); + virtual void folderListCompleted(ImapStrategyContextBase *context); virtual void processUidSearchResults(ImapStrategyContextBase *context); - virtual void processMailbox(ImapStrategyContextBase *context); + virtual void folderListFolderAction(ImapStrategyContextBase *context); uint _minimum; bool _fillingGap; @@ -355,17 +358,21 @@ public: virtual void transition(ImapStrategyContextBase*, const ImapCommand, const OperationStatus); protected: - virtual void listCompleted(ImapStrategyContextBase *context); - virtual bool selectNextMailbox(ImapStrategyContextBase *context); - virtual void handleSelect(ImapStrategyContextBase *context); virtual void handleUidSearch(ImapStrategyContextBase *context); + virtual void handleUidStore(ImapStrategyContextBase *context); + virtual void handleExpunge(ImapStrategyContextBase *context); + + virtual void folderListFolderAction(ImapStrategyContextBase *context); + virtual void processUidSearchResults(ImapStrategyContextBase *context); virtual void searchInconclusive(ImapStrategyContextBase *context); - virtual void handleUidStore(ImapStrategyContextBase *context); + + virtual void folderListCompleted(ImapStrategyContextBase *context); + virtual bool setNextSeen(ImapStrategyContextBase *context); virtual bool setNextDeleted(ImapStrategyContextBase *context); - virtual void handleExpunge(ImapStrategyContextBase *context); - virtual void fetchNextMailPreview(ImapStrategyContextBase *context); + + virtual void previewingCompleted(ImapStrategyContextBase *context); protected: QStringList _readUids; @@ -397,13 +404,18 @@ public: protected: virtual void handleLogin(ImapStrategyContextBase *context); - virtual void handleSelect(ImapStrategyContextBase *context); virtual void handleUidSearch(ImapStrategyContextBase *context); + + virtual void folderListFolderAction(ImapStrategyContextBase *context); + virtual bool nextFolder(); + virtual void processUidSearchResults(ImapStrategyContextBase *context); QStringList _serverReportedUids; QStringList _clientDeletedUids; QStringList _clientReadUids; + + QMap<QMailFolderId, QPair<QStringList, QStringList> > _folderMessageUids; }; class ImapCopyMessagesStrategy : public ImapFetchSelectedMessagesStrategy @@ -427,8 +439,8 @@ protected: virtual void handleUidSearch(ImapStrategyContextBase *context); virtual void handleUidFetch(ImapStrategyContextBase *context); - virtual void messageAction(ImapStrategyContextBase *context); - virtual void completedAction(ImapStrategyContextBase *context); + virtual void messageListMessageAction(ImapStrategyContextBase *context); + virtual void messageListCompleted(ImapStrategyContextBase *context); virtual void updateCopiedMessage(ImapStrategyContextBase *context, QMailMessage &message, const QMailMessage &source); @@ -458,9 +470,9 @@ protected: virtual void handleUidFetch(ImapStrategyContextBase *context); virtual void handleExamine(ImapStrategyContextBase *context); - virtual void folderAction(ImapStrategyContextBase *context); - virtual void messageAction(ImapStrategyContextBase *context); - virtual void completedAction(ImapStrategyContextBase *context); + virtual void messageListFolderAction(ImapStrategyContextBase *context); + virtual void messageListMessageAction(ImapStrategyContextBase *context); + virtual void messageListCompleted(ImapStrategyContextBase *context); virtual void updateCopiedMessage(ImapStrategyContextBase *context, QMailMessage &message, const QMailMessage &source); @@ -482,9 +494,9 @@ protected: virtual void handleClose(ImapStrategyContextBase *context); virtual void handleExamine(ImapStrategyContextBase *context); - virtual void messageAction(ImapStrategyContextBase *context); - virtual void folderAction(ImapStrategyContextBase *context); - virtual void completedAction(ImapStrategyContextBase *context); + virtual void messageListFolderAction(ImapStrategyContextBase *context); + virtual void messageListMessageAction(ImapStrategyContextBase *context); + virtual void messageListCompleted(ImapStrategyContextBase *context); QStringList _storedList; bool _removal; @@ -510,7 +522,7 @@ public: void newConnection() { _strategy->newConnection(this); } void commandTransition(const ImapCommand command, const OperationStatus status) { _strategy->transition(this, command, status); } - void mailboxListed(QMailFolder& folder, const QString &flags) { _strategy->mailboxListed(this, folder, flags); } + void mailboxListed(QMailFolder& folder, const QString &flags, const QString &delimiter) { _strategy->mailboxListed(this, folder, flags, delimiter); } void messageFetched(QMailMessage &message) { _strategy->messageFetched(this, message); } void dataFetched(QMailMessage &message, const QString &uid, const QString §ion) { _strategy->dataFetched(this, message, uid, section); } void nonexistentUid(const QString &uid) { _strategy->nonexistentUid(this, uid); } diff --git a/src/tools/messageserver/messageserver.cpp b/src/tools/messageserver/messageserver.cpp index f4d30d3c..2e5cf88e 100644 --- a/src/tools/messageserver/messageserver.cpp +++ b/src/tools/messageserver/messageserver.cpp @@ -36,7 +36,7 @@ MessageServer::MessageServer(QObject *parent) it.value() = 0; QMailStore *store = QMailStore::instance(); - if (!store->initialized()) { + if (store->initializationState() != QMailStore::Initialized) { qFatal("Messaging DB Invalid: Messaging cannot operate due to database incompatibilty!"); // Do not close, however, or QPE will start another instance. } else { diff --git a/src/tools/messageserver/servicehandler.cpp b/src/tools/messageserver/servicehandler.cpp index 78e72dec..a7c773d8 100644 --- a/src/tools/messageserver/servicehandler.cpp +++ b/src/tools/messageserver/servicehandler.cpp @@ -16,10 +16,10 @@ #include <qmailmessageserver.h> #include <qmailserviceconfiguration.h> #include <qmailstore.h> -#include <QTimer> #include <qmaillog.h> #include <QApplication> -#include <QFile> +#include <QDir> +#include <QTimer> // Account preparation is handled by an external function extern void prepareAccounts(); @@ -224,6 +224,11 @@ bool messageBodyContainsText(const QMailMessage &message, const QString& text) return false; } +QString requestsFileName() +{ + return QDir::tempPath() + "/qmf-messageserver-requests"; +} + } @@ -292,7 +297,8 @@ QMailMessageIdList ServiceHandler::MessageSearch::takeBatch() ServiceHandler::ServiceHandler(QObject* parent) - : QObject(parent) + : QObject(parent), + _requestsFile(requestsFileName()) { LongStream::cleanupTempFiles(); @@ -308,6 +314,39 @@ ServiceHandler::ServiceHandler(QObject* parent) } connect(this, SIGNAL(remoteSearchCompleted(quint64)), this, SLOT(finaliseSearch(quint64))); + + // See if there are any requests remaining from our previous run + if (_requestsFile.exists()) { + if (!_requestsFile.open(QIODevice::ReadOnly)) { + qWarning() << "Unable to open requests file for read!"; + } else { + QString line; + + // Every request still in the file failed to complete + for (QByteArray line = _requestsFile.readLine(); !line.isEmpty(); line = _requestsFile.readLine()) { + if (quint64 action = line.trimmed().toULongLong()) { + _failedRequests.append(action); + } + } + + _requestsFile.close(); + } + } + + if (!_requestsFile.open(QIODevice::WriteOnly)) { + qWarning() << "Unable to open requests file for write!" << _requestsFile.fileName(); + } else { + if (!_requestsFile.resize(0)) { + qWarning() << "Unable to truncate requests file!"; + } else { + _requestsFile.flush(); + } + } + + if (!_failedRequests.isEmpty()) { + // Allow the clients some time to reconnect, then report our failures + QTimer::singleShot(2000, this, SLOT(reportFailures())); + } } ServiceHandler::~ServiceHandler() @@ -602,6 +641,16 @@ void ServiceHandler::enqueueRequest(quint64 action, const QByteArray &data, cons req.completion = completion; mRequests.append(req); + + // Add this request to the outstanding list + if (!_outstandingRequests.contains(action)) { + _outstandingRequests.insert(action); + + QByteArray requestNumber(QByteArray::number(action)); + _requestsFile.write(requestNumber.append("\n")); + _requestsFile.flush(); + } + QTimer::singleShot(0, this, SLOT(dispatchRequest())); } @@ -643,6 +692,7 @@ void ServiceHandler::activateAction(quint64 action, const QSet<QMailMessageServi data.services = services; data.completion = completion; data.expiry = QTime::currentTime().addMSecs(ExpiryPeriod); + data.reported = false; mActiveActions.insert(action, data); @@ -688,10 +738,35 @@ void ServiceHandler::expireAction() QSet<QMailAccountId> serviceAccounts; + bool retrievalSetModified(false); + bool transmissionSetModified(false); + // Remove this action foreach (QMailMessageService *service, data.services) { serviceAccounts.insert(service->accountId()); mServiceAction.remove(service); + + QMailAccountId accountId(service->accountId()); + if (accountId.isValid()) { + if (data.completion == &ServiceHandler::retrievalCompleted) { + if (_retrievalAccountIds.contains(accountId)) { + _retrievalAccountIds.remove(accountId); + retrievalSetModified = true; + } + } else if (data.completion == &ServiceHandler::transmissionCompleted) { + if (_transmissionAccountIds.contains(accountId)) { + _transmissionAccountIds.remove(accountId); + transmissionSetModified = true; + } + } + } + } + + if (retrievalSetModified) { + QMailStore::instance()->setRetrievalInProgress(_retrievalAccountIds.toList()); + } + if (transmissionSetModified) { + QMailStore::instance()->setTransmissionInProgress(_transmissionAccountIds.toList()); } mActiveActions.erase(it); @@ -722,9 +797,35 @@ void ServiceHandler::cancelTransfer(quint64 action) { QMap<quint64, ActionData>::iterator it = mActiveActions.find(action); if (it != mActiveActions.end()) { - foreach (QMailMessageService *service, it.value().services) { + bool retrievalSetModified(false); + bool transmissionSetModified(false); + + const ActionData &data(it.value()); + foreach (QMailMessageService *service, data.services) { service->cancelOperation(); mServiceAction.remove(service); + + QMailAccountId accountId(service->accountId()); + if (accountId.isValid()) { + if (data.completion == &ServiceHandler::retrievalCompleted) { + if (_retrievalAccountIds.contains(accountId)) { + _retrievalAccountIds.remove(accountId); + retrievalSetModified = true; + } + } else if (data.completion == &ServiceHandler::transmissionCompleted) { + if (_transmissionAccountIds.contains(accountId)) { + _transmissionAccountIds.remove(accountId); + transmissionSetModified = true; + } + } + } + } + + if (retrievalSetModified) { + QMailStore::instance()->setRetrievalInProgress(_retrievalAccountIds.toList()); + } + if (transmissionSetModified) { + QMailStore::instance()->setTransmissionInProgress(_transmissionAccountIds.toList()); } mActiveActions.erase(it); @@ -737,9 +838,12 @@ void ServiceHandler::cancelTransfer(quint64 action) for ( ; it != end; ++it) { if ((*it).action == action) { mRequests.erase(it); - return; + break; } } + + // Report this action as failed + reportFailure(action, QMailServiceAction::Status::ErrCancel, tr("Cancelled by user")); } } @@ -763,13 +867,18 @@ bool ServiceHandler::dispatchTransmitMessages(quint64 action, const QByteArray & if (QMailMessageSink *sink = accountSink(accountId)) { // Transmit any messages in the Outbox for this account QMailMessageKey accountKey(QMailMessageKey::parentAccountId(accountId)); - QMailMessageKey folderKey(QMailMessageKey::parentFolderId(QMailFolderId(QMailFolder::OutboxFolder))); + + QMailAccount account(accountId); + QMailMessageKey folderKey(QMailMessageKey::parentFolderId(account.standardFolder(QMailFolder::OutboxFolder))); // TODO: Prepare any unresolved messages for transmission if (!sink->transmitMessages(QMailStore::instance()->queryMessages(accountKey & folderKey))) { qMailLog(Messaging) << "Unable to service request to add messages to sink for account:" << accountId; return false; + } else { + // This account is now transmitting + setTransmissionInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate sink for account"), accountId); @@ -801,6 +910,9 @@ bool ServiceHandler::dispatchRetrieveFolderListAccount(quint64 action, const QBy if (!source->retrieveFolderList(accountId, folderId, descending)) { qMailLog(Messaging) << "Unable to service request to retrieve folder list for account:" << accountId; return false; + } else { + // This account is now retrieving (arguably...) + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -833,6 +945,9 @@ bool ServiceHandler::dispatchRetrieveMessageList(quint64 action, const QByteArra if (!source->retrieveMessageList(accountId, folderId, minimum, sort)) { qMailLog(Messaging) << "Unable to service request to retrieve message list for folder:" << folderId; return false; + } else { + // This account is now retrieving + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -867,6 +982,11 @@ bool ServiceHandler::dispatchRetrieveMessages(quint64 action, const QByteArray & if (!source->retrieveMessages(it.value(), spec)) { qMailLog(Messaging) << "Unable to service request to retrieve messages for account:" << it.key(); return false; + } else if (spec != QMailRetrievalAction::Flags) { + // This account is now retrieving + if (!_retrievalAccountIds.contains(it.key())) { + _retrievalAccountIds.insert(it.key()); + } } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), it.key()); @@ -874,6 +994,7 @@ bool ServiceHandler::dispatchRetrieveMessages(quint64 action, const QByteArray & } } + QMailStore::instance()->setRetrievalInProgress(_retrievalAccountIds.toList()); return true; } @@ -899,6 +1020,9 @@ bool ServiceHandler::dispatchRetrieveMessagePart(quint64 action, const QByteArra if (!source->retrieveMessagePart(partLocation)) { qMailLog(Messaging) << "Unable to service request to retrieve part for message:" << partLocation.containingMessageId(); return false; + } else { + // This account is now retrieving + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -931,6 +1055,9 @@ bool ServiceHandler::dispatchRetrieveMessageRange(quint64 action, const QByteArr if (!source->retrieveMessageRange(messageId, minimum)) { qMailLog(Messaging) << "Unable to service request to retrieve range:" << minimum << "for message:" << messageId; return false; + } else { + // This account is now retrieving + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -963,6 +1090,9 @@ bool ServiceHandler::dispatchRetrieveMessagePartRange(quint64 action, const QByt if (!source->retrieveMessagePartRange(partLocation, minimum)) { qMailLog(Messaging) << "Unable to service request to retrieve range:" << minimum << "for part in message:" << partLocation.containingMessageId(); return false; + } else { + // This account is now retrieving + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -992,6 +1122,9 @@ bool ServiceHandler::dispatchRetrieveAll(quint64 action, const QByteArray &data) if (!source->retrieveAll(accountId)) { qMailLog(Messaging) << "Unable to service request to retrieve all messages for account:" << accountId; return false; + } else { + // This account is now retrieving + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -1050,6 +1183,9 @@ bool ServiceHandler::dispatchSynchronize(quint64 action, const QByteArray &data) if (!source->synchronize(accountId)) { qMailLog(Messaging) << "Unable to service request to synchronize account:" << accountId; return false; + } else { + // This account is now retrieving + setRetrievalInProgress(accountId, true); } } else { reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Unable to locate source for account"), accountId); @@ -1499,14 +1635,25 @@ void ServiceHandler::actionCompleted(bool success) // Remove this service from the set for the action data.services.erase(sit); + // This account is no longer retrieving/transmitting + QMailAccountId accountId(service->accountId()); + if (accountId.isValid()) { + if (data.completion == &ServiceHandler::retrievalCompleted) { + setRetrievalInProgress(accountId, false); + } else if (data.completion == &ServiceHandler::transmissionCompleted) { + setTransmissionInProgress(accountId, false); + } + } + if (success) { - if (data.services.isEmpty() && data.completion != 0) { + if (data.services.isEmpty() && (data.reported == false)) { // Report success emit (this->*data.completion)(action); + data.reported = true; } } else { - // This action has failed - remove the completion signal so it can't be reported as successful - data.completion = 0; + // This action has failed - mark it so that it can't be reported as successful + data.reported = true; } } @@ -1516,6 +1663,18 @@ void ServiceHandler::actionCompleted(bool success) } } + if (_outstandingRequests.contains(action)) { + _outstandingRequests.remove(action); + + // Ensure this request is no longer in the file + _requestsFile.resize(0); + foreach (quint64 req, _outstandingRequests) { + QByteArray requestNumber(QByteArray::number(req)); + _requestsFile.write(requestNumber.append("\n")); + } + _requestsFile.flush(); + } + mServiceAction.remove(service); } } @@ -1606,3 +1765,49 @@ void ServiceHandler::finaliseSearch(quint64 action) } } +void ServiceHandler::reportFailures() +{ + // We have no active accounts at this point + QMailStore::instance()->setRetrievalInProgress(QMailAccountIdList()); + QMailStore::instance()->setTransmissionInProgress(QMailAccountIdList()); + + while (!_failedRequests.isEmpty()) { + quint64 action(_failedRequests.takeFirst()); + reportFailure(action, QMailServiceAction::Status::ErrFrameworkFault, tr("Failed to perform requested action!")); + } +} + +void ServiceHandler::setRetrievalInProgress(const QMailAccountId &accountId, bool inProgress) +{ + bool modified(false); + + if (inProgress && !_retrievalAccountIds.contains(accountId)) { + _retrievalAccountIds.insert(accountId); + modified = true; + } else if (!inProgress && _retrievalAccountIds.contains(accountId)) { + _retrievalAccountIds.remove(accountId); + modified = true; + } + + if (modified) { + QMailStore::instance()->setRetrievalInProgress(_retrievalAccountIds.toList()); + } +} + +void ServiceHandler::setTransmissionInProgress(const QMailAccountId &accountId, bool inProgress) +{ + bool modified(false); + + if (inProgress && !_transmissionAccountIds.contains(accountId)) { + _transmissionAccountIds.insert(accountId); + modified = true; + } else if (!inProgress && _transmissionAccountIds.contains(accountId)) { + _transmissionAccountIds.remove(accountId); + modified = true; + } + + if (modified) { + QMailStore::instance()->setTransmissionInProgress(_transmissionAccountIds.toList()); + } +} + diff --git a/src/tools/messageserver/servicehandler.h b/src/tools/messageserver/servicehandler.h index f6d9e790..972763e0 100644 --- a/src/tools/messageserver/servicehandler.h +++ b/src/tools/messageserver/servicehandler.h @@ -12,6 +12,7 @@ #define SERVICEHANDLER_H #include <QByteArray> +#include <QFile> #include <QLinkedList> #include <QList> #include <qmailmessageserver.h> @@ -107,6 +108,8 @@ private slots: void expireAction(); + void reportFailures(); + private: QMailAccountId transmissionAccountId(const QMailAccountId &accountId) const; @@ -168,6 +171,9 @@ private: void activateAction(quint64, const QSet<QMailMessageService*> &, CompletionSignal); void updateAction(quint64); + void setRetrievalInProgress(const QMailAccountId &id, bool inProgress); + void setTransmissionInProgress(const QMailAccountId &id, bool inProgress); + QMap<QPair<QMailAccountId, QString>, QMailMessageService*> serviceMap; QMap<QMailAccountId, QMailMessageSource*> sourceMap; QMap<QMailAccountId, QMailMessageSink*> sinkMap; @@ -183,6 +189,7 @@ private: QSet<QMailMessageService*> services; CompletionSignal completion; QTime expiry; + bool reported; }; QMap<quint64, ActionData> mActiveActions; @@ -233,6 +240,13 @@ private: QList<MessageSearch> mSearches; QMailMessageIdList mMatchingIds; + + QFile _requestsFile; + QSet<quint64> _outstandingRequests; + QList<quint64> _failedRequests; + + QSet<QMailAccountId> _retrievalAccountIds; + QSet<QMailAccountId> _transmissionAccountIds; }; #endif diff --git a/tests/tests.pro b/tests/tests.pro index b0deaf82..6cd0a154 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs +CONFIG += ordered SUBDIRS = \ tst_python_email \ tst_qmailaddress \ diff --git a/tests/tst_qmailstorekeys/tst_qmailstorekeys.cpp b/tests/tst_qmailstorekeys/tst_qmailstorekeys.cpp index f78b3002..55b89f8b 100644 --- a/tests/tst_qmailstorekeys/tst_qmailstorekeys.cpp +++ b/tests/tst_qmailstorekeys/tst_qmailstorekeys.cpp @@ -119,7 +119,7 @@ tst_QMailStoreKeys::~tst_QMailStoreKeys() void tst_QMailStoreKeys::initTestCase() { - // Instantiate the store to initialise the values of the status flags + // Instantiate the store to initialise the values of the status flags and create the standard folders QMailStore::instance(); // Create the data set we will test our keys upon @@ -446,6 +446,7 @@ void tst_QMailStoreKeys::initTestCase() void tst_QMailStoreKeys::cleanupTestCase() { + QMailStore::instance()->clearContent(); } using namespace QMailDataComparator; |
