summaryrefslogtreecommitdiffstats
path: root/examples/qtmail/emailclient.cpp
diff options
context:
space:
mode:
authorRobin Burchell <[email protected]>2014-02-03 16:55:05 +0100
committerThe Qt Project <[email protected]>2014-02-03 16:58:57 +0100
commitcc24f4f33e6342b3d95a8988f904073e2f6f3b32 (patch)
tree0a21f172723a375f3df38db694c015ab3265fba3 /examples/qtmail/emailclient.cpp
parenteef36ce2e30e6e1c60f527eed54f3abae21ecfb9 (diff)
Restore compilation of qtmail example.
Change-Id: Id59253e1d121ab0dfcdb59f7018b897f6c1df086 Reviewed-by: Robin Burchell <[email protected]>
Diffstat (limited to 'examples/qtmail/emailclient.cpp')
-rw-r--r--examples/qtmail/emailclient.cpp3055
1 files changed, 3055 insertions, 0 deletions
diff --git a/examples/qtmail/emailclient.cpp b/examples/qtmail/emailclient.cpp
new file mode 100644
index 00000000..a71ebad1
--- /dev/null
+++ b/examples/qtmail/emailclient.cpp
@@ -0,0 +1,3055 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Messaging Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "emailclient.h"
+#include "selectfolder.h"
+#include "emailfoldermodel.h"
+#include "emailfolderview.h"
+#include "accountsettings.h"
+#include "searchview.h"
+#include "readmail.h"
+#include "writemail.h"
+#include <private/longstream_p.h>
+#include <qmaillog.h>
+#include <qmailnamespace.h>
+#include <qmailaccount.h>
+#include <qmailaddress.h>
+#include <qmailcomposer.h>
+#include <qmailstore.h>
+#include <qmailtimestamp.h>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QFile>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QInputDialog>
+#include <QLabel>
+#include <QMessageBox>
+#include <QStack>
+#include <QStackedWidget>
+#include <QThread>
+#include <QVBoxLayout>
+#include <QKeyEvent>
+#include <QSettings>
+#include <QMenuBar>
+#include <QSplitter>
+#include <QListView>
+#include <QToolBar>
+#include <QMovie>
+#include <QStatusBar>
+#include "statusmonitorwidget.h"
+#include "statusbar.h"
+#include "statusmonitor.h"
+#include <qtmailnamespace.h>
+#include <qmaildisconnected.h>
+#if defined(SERVER_AS_DLL)
+#include "messageserver.h"
+#endif
+
+static const unsigned int StatusBarHeight = 20;
+#ifdef LOAD_DEBUG_VERSION
+static const QString debugSuffix("d");
+#else
+static const QString debugSuffix;
+#endif
+
+class ActivityIcon : public QLabel
+{
+ Q_OBJECT
+
+public:
+ ActivityIcon(QWidget* parent = 0);
+
+private slots:
+ void itemChanged(StatusItem* item);
+ void showActivity(bool val);
+
+private:
+ QMovie m_activeIcon;
+ QPixmap m_inactiveIcon;
+};
+
+ActivityIcon::ActivityIcon(QWidget* parent)
+:
+QLabel(parent),
+m_activeIcon(":icon/activity_working"),
+m_inactiveIcon(":icon/activity_idle")
+{
+ setPixmap(m_inactiveIcon);
+ setPalette(parent->palette());
+ connect(StatusMonitor::instance(),SIGNAL(added(StatusItem*)),this,SLOT(itemChanged(StatusItem*)));
+ connect(StatusMonitor::instance(),SIGNAL(removed(StatusItem*)),this,SLOT(itemChanged(StatusItem*)));
+
+ showActivity(StatusMonitor::instance()->itemCount() != 0);
+}
+
+void ActivityIcon::itemChanged(StatusItem* item)
+{
+ Q_UNUSED(item);
+ showActivity(StatusMonitor::instance()->itemCount() != 0);
+}
+
+void ActivityIcon::showActivity(bool val)
+{
+ if(val)
+ {
+ if(m_activeIcon.state() == QMovie::Running)
+ return;
+ setMovie(&m_activeIcon);
+ m_activeIcon.start();
+ }
+ else
+ {
+ if(m_activeIcon.state() == QMovie::NotRunning)
+ return;
+ m_activeIcon.stop();
+ setPixmap(m_inactiveIcon);
+ }
+}
+
+static const int defaultWidth = 1024;
+static const int defaultHeight = 768;
+
+enum ActivityType {
+ Inactive = 0,
+ Retrieving = 1,
+ Sending = 2
+};
+
+static bool confirmDelete( QWidget *parent, const QString & caption, const QString & object ) {
+ QString msg = "<qt>" + QObject::tr("Are you sure you want to delete: %1?").arg( object ) + "</qt>";
+ int r = QMessageBox::question( parent, caption, msg, QMessageBox::Yes, QMessageBox::No|QMessageBox::Default| QMessageBox::Escape, 0 );
+ return r == QMessageBox::Yes;
+}
+
+// This is used regularly:
+static const QMailMessage::MessageType nonEmailType = static_cast<QMailMessage::MessageType>(QMailMessage::Mms |
+ QMailMessage::Sms |
+ QMailMessage::Instant |
+ QMailMessage::System);
+
+class AcknowledgmentBox : public QMessageBox
+{
+ Q_OBJECT
+
+public:
+ static void show(const QString& title, const QString& text);
+
+private:
+ AcknowledgmentBox(const QString& title, const QString& text);
+
+ virtual void keyPressEvent(QKeyEvent* event);
+
+ static const int _timeout = 3 * 1000;
+};
+
+AcknowledgmentBox::AcknowledgmentBox(const QString& title, const QString& text)
+ : QMessageBox(0)
+{
+ setWindowTitle(title);
+ setText(text);
+ setIcon(QMessageBox::Information);
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ QDialog::show();
+ QTimer::singleShot(_timeout, this, SLOT(accept()));
+}
+
+void AcknowledgmentBox::show(const QString& title, const QString& text)
+{
+ (void)new AcknowledgmentBox(title, text);
+}
+
+void AcknowledgmentBox::keyPressEvent(QKeyEvent* event)
+{
+ if (event->key() == Qt::Key_Select) {
+ event->accept();
+ accept();
+ } else {
+ QMessageBox::keyPressEvent(event);
+ }
+}
+
+MessageUiBase::MessageUiBase(QWidget *parent, Qt::WindowFlags f)
+ : QMainWindow(parent,f),
+ appTitle(tr("QtMail")),
+ suspendMailCount(true),
+ markingMode(false),
+ threaded(true),
+ selectionCount(0),
+ emailCountSuspended(false)
+{
+ setWindowTitle( appTitle );
+}
+
+void MessageUiBase::viewSearchResults(const QMailMessageKey&, const QString& title)
+{
+ //TODO
+ QString caption(title);
+ if (caption.isNull())
+ caption = tr("Search Results");
+}
+
+void MessageUiBase::viewComposer()
+{
+ writeMailWidget()->raise();
+ writeMailWidget()->activateWindow();
+ writeMailWidget()->show();
+}
+
+WriteMail* MessageUiBase::writeMailWidget() const
+{
+ static WriteMail* writeMail = const_cast<MessageUiBase*>(this)->createWriteMailWidget();
+ return writeMail;
+}
+
+ReadMail* MessageUiBase::readMailWidget() const
+{
+ static ReadMail* readMail = const_cast<MessageUiBase*>(this)->createReadMailWidget();
+ return readMail;
+}
+
+EmailFolderView* MessageUiBase::folderView() const
+{
+ static EmailFolderView* view = const_cast<MessageUiBase*>(this)->createFolderView();
+ return view;
+}
+
+MessageListView* MessageUiBase::messageListView() const
+{
+ static MessageListView* view = const_cast<MessageUiBase*>(this)->createMessageListView();
+ return view;
+}
+
+EmailFolderModel* MessageUiBase::emailFolderModel() const
+{
+ static EmailFolderModel* model = const_cast<MessageUiBase*>(this)->createEmailFolderModel();
+ return model;
+}
+
+SearchView* MessageUiBase::searchView() const
+{
+ static SearchView* searchview = const_cast<MessageUiBase*>(this)->createSearchView();
+ return searchview;
+}
+
+void MessageUiBase::showFolderStatus(QMailMessageSet* item)
+{
+ if (item)
+ emit updateStatus(item->data(EmailFolderModel::FolderStatusDetailRole).value<QString>());
+}
+
+void MessageUiBase::contextStatusUpdate()
+{
+ if (suspendMailCount)
+ return;
+ showFolderStatus(folderView()->currentItem());
+}
+
+void MessageUiBase::suspendMailCounts()
+{
+ suspendMailCount = true;
+
+ if (!emailFolderModel()->ignoreMailStoreUpdates()) {
+ emailFolderModel()->setIgnoreMailStoreUpdates(true);
+ emailCountSuspended = true;
+ }
+}
+
+void MessageUiBase::resumeMailCounts()
+{
+ suspendMailCount = false;
+
+ if (emailCountSuspended) {
+ emailFolderModel()->setIgnoreMailStoreUpdates(false);
+ emailCountSuspended = false;
+ }
+
+ contextStatusUpdate();
+}
+
+void MessageUiBase::messageSelectionChanged()
+{
+ selectionCount = messageListView()->selected().count();
+ contextStatusUpdate();
+}
+
+void MessageUiBase::setMarkingMode(bool set)
+{
+ markingMode = set;
+
+ messageListView()->setMarkingMode(markingMode);
+ if (!markingMode) {
+ // Clear whatever selections were previously made
+ messageListView()->clearSelection();
+
+ }
+ contextStatusUpdate();
+}
+
+void MessageUiBase::setThreaded(bool set)
+{
+ threaded = set;
+
+ messageListView()->setThreaded(threaded);
+ contextStatusUpdate();
+}
+
+void MessageUiBase::clearStatusText()
+{
+ emit clearStatus();
+}
+
+void MessageUiBase::presentMessage(const QMailMessageId &id, QMailViewerFactory::PresentationType type)
+{
+ readMailWidget()->displayMessage(id, type, false, false);
+}
+
+void MessageUiBase::updateWindowTitle()
+{
+ QMailMessageSet* item = folderView()->currentItem();
+ if(!item) return;
+
+ QString folderName = item->data(Qt::DisplayRole).value<QString>();
+ QString folderStatus = item->data(EmailFolderModel::FolderStatusRole).value<QString>();
+ QString accountName;
+ QMailFolderId folderId = item->data(EmailFolderModel::FolderIdRole).value<QMailFolderId>();
+ QMailAccountId accountId = item->data(EmailFolderModel::ContextualAccountIdRole).value<QMailAccountId>();
+
+ if(!folderStatus.isEmpty())
+ folderStatus = " (" + folderStatus + ")";
+
+ //don't display account prefix for account root items
+ bool isFolderItem = accountId.isValid() && folderId.isValid();
+ if(isFolderItem)
+ {
+ QMailAccount account(accountId);
+ if(!account.name().isEmpty())
+ accountName = account.name() + '/';
+ }
+
+ setWindowTitle(accountName + folderName + folderStatus + " - " + appTitle);
+}
+
+void MessageUiBase::checkUpdateWindowTitle(const QModelIndex& topLeft, const QModelIndex& bottomRight)
+{
+ if(topLeft == folderView()->currentIndex() || bottomRight == folderView()->currentIndex())
+ updateWindowTitle();
+}
+
+WriteMail* MessageUiBase::createWriteMailWidget()
+{
+ WriteMail* writeMail = new WriteMail(this);
+ writeMail->setObjectName("write-mail");
+
+ connect(writeMail, SIGNAL(enqueueMail(QMailMessage&)), this, SLOT(beginEnqueueMail(QMailMessage&)));
+ connect(writeMail, SIGNAL(discardMail()), this, SLOT(discardMail()));
+ connect(writeMail, SIGNAL(saveAsDraft(QMailMessage&)), this, SLOT(saveAsDraft(QMailMessage&)));
+ connect(writeMail, SIGNAL(noSendAccount(QMailMessage::MessageType)), this, SLOT(noSendAccount(QMailMessage::MessageType)));
+ connect(writeMail, SIGNAL(editAccounts()), this, SLOT(settings()));
+
+ return writeMail;
+}
+
+ReadMail* MessageUiBase::createReadMailWidget()
+{
+ ReadMail* readMail = new ReadMail(this);
+
+ readMail->setObjectName("read-message");
+
+ readMail->setGeometry(geometry());
+
+ connect(readMail, SIGNAL(responseRequested(QMailMessage,QMailMessage::ResponseType)), this, SLOT(respond(QMailMessage,QMailMessage::ResponseType)));
+ connect(readMail, SIGNAL(responseRequested(QMailMessagePart::Location,QMailMessage::ResponseType)), this, SLOT(respond(QMailMessagePart::Location,QMailMessage::ResponseType)));
+ connect(readMail, SIGNAL(getMailRequested(QMailMessageMetaData)), this, SLOT(getSingleMail(QMailMessageMetaData)));
+ connect(readMail, SIGNAL(readReplyRequested(QMailMessageMetaData)), this, SLOT(readReplyRequested(QMailMessageMetaData)));
+ connect(readMail, SIGNAL(sendMessageTo(QMailAddress,QMailMessage::MessageType)), this, SLOT(sendMessageTo(QMailAddress,QMailMessage::MessageType)));
+ connect(readMail, SIGNAL(viewMessage(QMailMessageId,QMailViewerFactory::PresentationType)), this, SLOT(presentMessage(QMailMessageId,QMailViewerFactory::PresentationType)));
+ connect(readMail, SIGNAL(sendMessage(QMailMessage&)), this, SLOT(beginEnqueueMail(QMailMessage&)));
+ connect(readMail, SIGNAL(retrieveMessagePortion(QMailMessageMetaData, uint)), this, SLOT(retrieveMessagePortion(QMailMessageMetaData, uint)));
+ connect(readMail, SIGNAL(retrieveMessagePart(QMailMessagePart::Location)), this, SLOT(retrieveMessagePart(QMailMessagePart::Location)));
+ connect(readMail, SIGNAL(retrieveMessagePartPortion(QMailMessagePart::Location, uint)), this, SLOT(retrieveMessagePartPortion(QMailMessagePart::Location, uint)));
+ connect(readMail, SIGNAL(flagMessage(QMailMessageId, quint64, quint64)), this, SLOT(flagMessage(QMailMessageId, quint64, quint64)));
+
+ return readMail;
+}
+
+EmailFolderView* MessageUiBase::createFolderView()
+{
+ EmailFolderView* view = new EmailFolderView(this);
+
+ view->setObjectName("read-email");
+ view->setModel(emailFolderModel());
+
+ connect(view, SIGNAL(selected(QMailMessageSet*)), this, SLOT(folderSelected(QMailMessageSet*)));
+ connect(view, SIGNAL(selected(QMailMessageSet*)), this, SLOT(updateWindowTitle()));
+ connect(emailFolderModel(),SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),this,
+ SLOT(checkUpdateWindowTitle(const QModelIndex&,const QModelIndex&)));
+// connect(view, SIGNAL(selectionUpdated()), this, SLOT(updateWindowTitle()));
+
+ return view;
+}
+
+MessageListView* MessageUiBase::createMessageListView()
+{
+ MessageListView* view = new MessageListView(this);
+
+ // Default sort is by descending send timestamp
+ view->setSortKey(QMailMessageSortKey::timeStamp(Qt::DescendingOrder));
+
+ connect(view, SIGNAL(clicked(QMailMessageId)), this, SLOT(messageActivated()));
+ connect(view, SIGNAL(selectionChanged()), this, SLOT(messageSelectionChanged()));
+ connect(view, SIGNAL(rowCountChanged()), this, SLOT(messageSelectionChanged()));
+ connect(view, SIGNAL(responseRequested(QMailMessage,QMailMessage::ResponseType)), this, SLOT(respond(QMailMessage,QMailMessage::ResponseType)) );
+ connect(view, SIGNAL(moreClicked()), this, SLOT(retrieveMoreMessages()) );
+ connect(view, SIGNAL(visibleMessagesChanged()), this, SLOT(retrieveVisibleMessagesFlags()) );
+ connect(view, SIGNAL(fullSearchRequested()),this,SLOT(search()));
+ connect(view, SIGNAL(doubleClicked(QMailMessageId)), this, SLOT(messageOpenRequested()));
+
+ return view;
+}
+
+EmailFolderModel* MessageUiBase::createEmailFolderModel()
+{
+ EmailFolderModel* model = new EmailFolderModel(this);
+ model->init();
+ return model;
+}
+
+SearchView* MessageUiBase::createSearchView()
+{
+ SearchView* searchview = new SearchView(this);
+ searchview->setObjectName("searchview");
+ return searchview;
+}
+
+EmailClient::EmailClient(QWidget *parent, Qt::WindowFlags f)
+ : MessageUiBase( parent, f ),
+ filesRead(false),
+ transferStatus(Inactive),
+ primaryActivity(Inactive),
+ enableMessageActions(false),
+ closeAfterTransmissions(false),
+ closeAfterWrite(false),
+ transmissionFailure(false),
+ fetchTimer(this),
+ autoGetMail(false),
+ initialAction(None),
+ preSearchWidgetId(-1),
+#if defined(SERVER_AS_DLL)
+ m_messageServerThread(0),
+#else
+ m_messageServerProcess(0),
+#endif
+ m_contextMenu(0),
+ m_transmitAction(0),
+ m_retrievalAction(0),
+ m_flagRetrievalAction(0),
+ m_exportAction(0)
+{
+ setObjectName( "EmailClient" );
+
+ //start messageserver if it's not running
+ if (!isMessageServerRunning() && !startMessageServer())
+ qFatal("Unable to start messageserver!");
+
+ //run account setup if we don't have any defined yet
+ bool haveAccounts = QMailStore::instance()->countAccounts() > 0;
+ if(!haveAccounts)
+ QTimer::singleShot(0,this,SLOT(settings()));
+
+ init();
+ setupUi();
+}
+
+EmailClient::~EmailClient()
+{
+ clearNewMessageStatus(messageListView()->key());
+ waitForMessageServer();
+}
+
+
+void EmailClient::openFiles()
+{
+ delayedInit();
+
+ if ( filesRead ) {
+ if ( cachedDisplayMailId.isValid() )
+ displayCachedMail();
+
+ return;
+ }
+
+ filesRead = true;
+
+ QMailMessageKey outboxFilter(QMailMessageKey::status(QMailMessage::Outbox));
+ if (QMailStore::instance()->countMessages(outboxFilter)) {
+ // There are messages ready to be sent
+ QTimer::singleShot( 0, this, SLOT(sendAllQueuedMail()) );
+ }
+
+ if ( cachedDisplayMailId.isValid() ) {
+ displayCachedMail();
+ }
+
+ // See if there is a draft whose composition was interrupted by the Red Key (tm)
+ QTimer::singleShot(0, this, SLOT(resumeInterruptedComposition()));
+}
+
+void EmailClient::displayCachedMail()
+{
+ presentMessage(cachedDisplayMailId,QMailViewerFactory::AnyPresentation);
+ cachedDisplayMailId = QMailMessageId();
+}
+
+void EmailClient::resumeInterruptedComposition()
+{
+ QSettings mailconf("QtProject", "qtmail");
+ mailconf.beginGroup("restart");
+
+ QVariant var = mailconf.value("lastDraftId");
+ if (!var.isNull()) {
+ lastDraftId = QMailMessageId(var.toULongLong());
+ mailconf.remove("lastDraftId");
+ }
+
+ mailconf.endGroup();
+
+ if (lastDraftId.isValid()) {
+ if (QMessageBox::question(0,
+ tr("Incomplete message"),
+ tr("Messages was previously interrupted while composing a message.\n"
+ "Do you want to resume composing the message?"),
+ QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
+ QMailMessage message(lastDraftId);
+ modify(message);
+ }
+ }
+}
+
+bool EmailClient::startMessageServer()
+{
+#if defined(SERVER_AS_DLL)
+ m_messageServerThread = new MessageServerThread();
+ m_messageServerThread->start();
+ QEventLoop loop;
+ QObject::connect(m_messageServerThread, SIGNAL(messageServerStarted()), &loop, SLOT(quit()));
+ loop.exec();
+ return true;
+#else
+ qMailLog(Messaging) << "Starting messageserver child process...";
+ if(m_messageServerProcess) delete m_messageServerProcess;
+ m_messageServerProcess = new QProcess(this);
+ connect(m_messageServerProcess,SIGNAL(error(QProcess::ProcessError)),
+ this,SLOT(messageServerProcessError(QProcess::ProcessError)));
+
+#ifdef Q_OS_WIN
+ static const QString binary(QString("/messageserver5%1.exe").arg(debugSuffix));
+#else
+ static const QString binary(QString("/messageserver5%1").arg(debugSuffix));
+#endif
+
+ m_messageServerProcess->start(QMail::messageServerPath() + binary);
+ return m_messageServerProcess->waitForStarted();
+#endif
+}
+
+bool EmailClient::waitForMessageServer()
+{
+#if defined(SERVER_AS_DLL)
+ if (m_messageServerThread) {
+ delete m_messageServerThread;
+ m_messageServerThread = 0;
+ }
+#else
+ if(m_messageServerProcess)
+ {
+ qMailLog(Messaging) << "Shutting down messageserver child process..";
+ bool result = m_messageServerProcess->waitForFinished();
+ delete m_messageServerProcess; m_messageServerProcess = 0;
+ return result;
+ }
+#endif
+ return true;
+}
+
+void EmailClient::messageServerProcessError(QProcess::ProcessError e)
+{
+ QString errorMsg = tr("The Message server child process encountered an error (%1). Qtmail will now exit.").arg(static_cast<int>(e));
+ QMessageBox::critical(this, tr("Message Server"), errorMsg);
+ qFatal(errorMsg.toLatin1(), "");
+}
+
+void EmailClient::connectServiceAction(QMailServiceAction* action)
+{
+ connect(action, SIGNAL(connectivityChanged(QMailServiceAction::Connectivity)), this, SLOT(connectivityChanged(QMailServiceAction::Connectivity)));
+ connect(action, SIGNAL(activityChanged(QMailServiceAction::Activity)), this, SLOT(activityChanged(QMailServiceAction::Activity)));
+ connect(action, SIGNAL(statusChanged(QMailServiceAction::Status)), this, SLOT(statusChanged(QMailServiceAction::Status)));
+ connect(action, SIGNAL(progressChanged(uint, uint)), this, SLOT(progressChanged(uint, uint)));
+}
+
+bool EmailClient::isMessageServerRunning() const
+{
+ QString lockfile = "messageserver-instance.lock";
+ int lockid = QMail::fileLock(lockfile);
+ if (lockid == -1)
+ return true;
+
+ QMail::fileUnlock(lockid);
+ return false;
+}
+
+bool EmailClient::cleanExit(bool force)
+{
+ bool result = true;
+
+ if (isTransmitting()) {
+ if (force) {
+ qMailLog(Messaging) << "EmailClient::cleanExit: forcing cancel to exit";
+ cancelOperation(); //abort all transfer
+ }
+ result = false;
+ }
+
+ saveSettings();
+ return result;
+}
+
+bool EmailClient::closeImmediately()
+{
+ if (isTransmitting()) { // obsolete?
+ closeAfterTransmissionsFinished();
+ return false;
+ }
+
+ return true;
+}
+
+void EmailClient::setVisible(bool visible)
+{
+ if(visible)
+ {
+ QPoint p(0, 0);
+ int extraw = 0, extrah = 0, scrn = 0;
+ QRect desk;
+ 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);
+ }
+ QMainWindow::setVisible(visible);
+}
+
+
+void EmailClient::closeAfterTransmissionsFinished()
+{
+ closeAfterWrite = false;
+ closeAfterTransmissions = true;
+}
+
+void EmailClient::closeApplication()
+{
+ cleanExit(false);
+
+ // If we're still transmitting, just hide until it completes
+ if (isTransmitting())
+ hide();
+ else
+ close();
+}
+
+void EmailClient::allWindowsClosed()
+{
+ closeAfterTransmissionsFinished();
+ closeApplication();
+}
+
+bool EmailClient::isTransmitting()
+{
+ return (transferStatus != Inactive);
+}
+
+bool EmailClient::isSending()
+{
+ return (transferStatus & Sending);
+}
+
+bool EmailClient::isRetrieving()
+{
+ return (transferStatus & Retrieving);
+}
+
+
+void EmailClient::initActions()
+{
+ if (!getMailButton) {
+ getMailButton = new QAction( Qtmail::icon("sendandreceive"), tr("Synchronize"), this );
+ connect(getMailButton, SIGNAL(triggered()), this, SLOT(getAllNewMail()) );
+ getMailButton->setWhatsThis( tr("Synchronize all your accounts.") );
+ setActionVisible(getMailButton, false);
+
+ getAccountButton = new QAction( Qtmail::icon("accountfolder"), QString(), this );
+ connect(getAccountButton, SIGNAL(triggered()), this, SLOT(getAccountMail()) );
+ getAccountButton->setWhatsThis( tr("Synchronize current account.") );
+ setActionVisible(getAccountButton, false);
+
+ cancelButton = new QAction( Qtmail::icon("cancel"), tr("Cancel transfer"), this );
+ connect(cancelButton, SIGNAL(triggered()), this, SLOT(cancelOperation()) );
+ cancelButton->setWhatsThis( tr("Abort all transfer of mail.") );
+ setActionVisible(cancelButton, false);
+
+ composeButton = new QAction( Qtmail::icon("compose"), tr("New"), this );
+ connect(composeButton, SIGNAL(triggered()), this, SLOT(composeActivated()) );
+ composeButton->setWhatsThis( tr("Write a new message.") );
+
+ searchButton = new QAction( Qtmail::icon("search"), tr("Search"), this );
+ connect(searchButton, SIGNAL(triggered()), this, SLOT(search()) );
+ searchButton->setWhatsThis( tr("Search for messages in your folders.") );
+ searchButton->setIconText("");
+
+ synchronizeAction = new QAction( this );
+ connect(synchronizeAction, SIGNAL(triggered()), this, SLOT(synchronizeFolder()) );
+ synchronizeAction->setWhatsThis( tr("Decide whether messages in this folder should be retrieved.") );
+ setActionVisible(synchronizeAction, false);
+
+ createFolderAction = new QAction( tr("Create Folder"), this );
+ connect(createFolderAction, SIGNAL(triggered()), this, SLOT(createFolder()));
+ createFolderAction->setWhatsThis( tr("Create folder and all messages and subfolders") );
+ setActionVisible(createFolderAction, false);
+
+ deleteFolderAction = new QAction( tr("Delete Folder"), this );
+ connect(deleteFolderAction, SIGNAL(triggered()), this, SLOT(deleteFolder()));
+ deleteFolderAction->setWhatsThis( tr("Delete folder and all messages and subfolders") );
+ setActionVisible(deleteFolderAction, false);
+
+ renameFolderAction = new QAction( tr("Rename Folder"), this );
+ connect(renameFolderAction, SIGNAL(triggered()), this, SLOT(renameFolder()));
+ renameFolderAction->setWhatsThis( tr("Give the folder a different name") );
+ setActionVisible(renameFolderAction, false);
+
+ settingsAction = new QAction( Qtmail::icon("settings"), tr("Account settings..."), this );
+ connect(settingsAction, SIGNAL(triggered()), this, SLOT(settings()));
+ settingsAction->setIconText(QString());
+
+ standardFoldersAction = new QAction( Qtmail::icon("Create standard folders"), tr("Create standard folders"), this );
+ connect(standardFoldersAction, SIGNAL(triggered()), this, SLOT(createStandardFolders()));
+ standardFoldersAction->setIconText(QString());
+
+ workOfflineAction = new QAction( Qtmail::icon("workoffline"), tr("Work offline"), this );
+ connect(workOfflineAction, SIGNAL(triggered()), this, SLOT(connectionStateChanged()));
+ workOfflineAction->setCheckable(true);
+ workOfflineAction->setChecked(false);
+ workOfflineAction->setIconText(QString());
+
+ notificationAction = new QAction(tr("Enable Notifications"), this);
+ connect(notificationAction, SIGNAL(triggered()), this, SLOT(notificationStateChanged()));
+ notificationAction->setCheckable(true);
+ notificationAction->setChecked(false);
+ notificationAction->setIconText(QString());
+
+ emptyTrashAction = new QAction( Qtmail::icon("trashfolder"), tr("Empty trash"), this );
+ connect(emptyTrashAction, SIGNAL(triggered()), this, SLOT(emptyTrashFolder()));
+ setActionVisible(emptyTrashAction, false);
+
+ moveAction = new QAction( this );
+ connect(moveAction, SIGNAL(triggered()), this, SLOT(moveSelectedMessages()));
+ setActionVisible(moveAction, false);
+
+ copyAction = new QAction( this );
+ connect(copyAction, SIGNAL(triggered()), this, SLOT(copySelectedMessages()));
+ setActionVisible(copyAction, false);
+
+ restoreAction = new QAction( this );
+ connect(restoreAction, SIGNAL(triggered()), this, SLOT(restoreSelectedMessages()));
+ setActionVisible(restoreAction, false);
+
+ selectAllAction = new QAction( tr("Select all"), this );
+ connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll()));
+ setActionVisible(selectAllAction, false);
+
+ deleteMailAction = new QAction( this );
+ deleteMailAction->setIcon( Qtmail::icon("deletemail") );
+ deleteMailAction->setShortcut(QKeySequence(Qt::Key_Delete));
+ connect(deleteMailAction, SIGNAL(triggered()), this, SLOT(deleteSelectedMessages()));
+ setActionVisible(deleteMailAction, false);
+
+ detachThreadAction = new QAction( tr("Detach from thread"), this );
+ connect(detachThreadAction, SIGNAL(triggered()), this, SLOT(detachThread()));
+ setActionVisible(detachThreadAction, false);
+
+ markAction = new QAction( tr("Mark messages"), this );
+ connect(markAction, SIGNAL(triggered()), this, SLOT(markMessages()));
+ setActionVisible(markAction, true);
+
+ threadAction = new QAction( tr("Unthread messages"), this );
+ connect(threadAction, SIGNAL(triggered()), this, SLOT(threadMessages()));
+ setActionVisible(threadAction, true);
+
+ replyAction= new QAction( Qtmail::icon("reply"), tr("Reply"), this );
+ connect(replyAction, SIGNAL(triggered()), this, SLOT(replyClicked()));
+ replyAction->setWhatsThis( tr("Reply to sender only. Select Reply all from the menu if you want to reply to all recipients.") );
+
+ replyAllAction = new QAction( Qtmail::icon("replyall"), tr("Reply all"), this );
+ connect(replyAllAction, SIGNAL(triggered()), this, SLOT(replyAllClicked()));
+
+ forwardAction = new QAction(Qtmail::icon("forward"),tr("Forward"), this );
+ connect(forwardAction, SIGNAL(triggered()), this, SLOT(forwardClicked()));
+
+ nextMessageAction = new QAction( tr("Next Message"), this );
+ nextMessageAction->setShortcut(QKeySequence(Qt::ALT|Qt::Key_Right));
+ connect(nextMessageAction, SIGNAL(triggered()), this, SLOT(nextMessage()));
+
+ previousMessageAction = new QAction( tr("Previous Message"), this );
+ previousMessageAction->setShortcut(QKeySequence(Qt::ALT|Qt::Key_Left));
+ connect(previousMessageAction, SIGNAL(triggered()), this, SLOT(previousMessage()));
+
+ nextUnreadMessageAction = new QAction( tr("Next Unread Message"), this );
+ nextUnreadMessageAction->setShortcut(QKeySequence(Qt::ALT|Qt::Key_Plus));
+ connect(nextUnreadMessageAction, SIGNAL(triggered()), this, SLOT(nextUnreadMessage()));
+
+ previousUnreadMessageAction = new QAction( tr("Previous Unread Message"), this );
+ previousUnreadMessageAction->setShortcut(QKeySequence(Qt::ALT|Qt::Key_Minus));
+ connect(previousUnreadMessageAction, SIGNAL(triggered()), this, SLOT(previousUnreadMessage()));
+
+ scrollReaderDownAction = new QAction( tr("Scroll Down"), this );
+ scrollReaderDownAction->setShortcut(QKeySequence(Qt::ALT|Qt::Key_Down));
+ connect(scrollReaderDownAction, SIGNAL(triggered()), this, SLOT(scrollReaderDown()));
+
+ scrollReaderUpAction = new QAction( tr("Scroll Up"), this );
+ scrollReaderUpAction->setShortcut(QKeySequence(Qt::ALT|Qt::Key_Up));
+ connect(scrollReaderUpAction, SIGNAL(triggered()), this, SLOT(scrollReaderUp()));
+
+ readerMarkMessageAsUnreadAction = new QAction( tr("Mark as Unread"), this );
+ connect(readerMarkMessageAsUnreadAction, SIGNAL(triggered()), this, SLOT(readerMarkMessageAsUnread()));
+
+ readerMarkMessageAsImportantAction = new QAction( tr("Mark as Important"), this );
+ connect(readerMarkMessageAsImportantAction, SIGNAL(triggered()), this, SLOT(readerMarkMessageAsImportant()));
+
+ readerMarkMessageAsNotImportantAction = new QAction( tr("Mark as Not Important"), this );
+ connect(readerMarkMessageAsNotImportantAction, SIGNAL(triggered()), this, SLOT(readerMarkMessageAsNotImportant()));
+
+ QMenu* fileMenu = m_contextMenu;
+ fileMenu->addAction( composeButton );
+ fileMenu->addAction( getMailButton );
+ fileMenu->addAction( getAccountButton );
+ fileMenu->addAction( searchButton );
+ fileMenu->addAction( cancelButton );
+ fileMenu->addAction( emptyTrashAction );
+ fileMenu->addAction( settingsAction );
+ fileMenu->addAction(standardFoldersAction);
+ fileMenu->addAction( workOfflineAction );
+ fileMenu->addAction( notificationAction );
+ fileMenu->addSeparator();
+
+ QAction* quitAction = fileMenu->addAction(Qtmail::icon("quit"),"Quit");
+ quitAction->setMenuRole(QAction::QuitRole);
+ connect(quitAction,SIGNAL(triggered(bool)),
+ this,SLOT(quit()));
+ connect(fileMenu, SIGNAL(aboutToShow()), this, SLOT(updateActions()));
+
+ QToolBar* toolBar = m_toolBar;
+ m_toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ toolBar->addAction( composeButton );
+ toolBar->addAction( getMailButton );
+ toolBar->addAction( cancelButton );
+ toolBar->addAction( searchButton );
+ toolBar->addSeparator();
+ toolBar->addAction( settingsAction );
+ toolBar->addSeparator();
+ toolBar->addAction(replyAction);
+ toolBar->addAction(forwardAction);
+ toolBar->addSeparator();
+ toolBar->addAction(deleteMailAction);
+
+ updateGetMailButton();
+
+ folderView()->addAction(synchronizeAction);
+ folderView()->addAction(createFolderAction);
+ folderView()->addAction(deleteFolderAction);
+ folderView()->addAction(renameFolderAction);
+ folderView()->addAction(emptyTrashAction);
+ folderView()->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ messageListView()->addAction(replyAction);
+ messageListView()->addAction(replyAllAction);
+ messageListView()->addAction(forwardAction);
+ messageListView()->addAction(createSeparator());
+ messageListView()->addAction( copyAction );
+ messageListView()->addAction( moveAction );
+ messageListView()->addAction( deleteMailAction );
+ messageListView()->addAction( restoreAction );
+ messageListView()->addAction(createSeparator());
+ messageListView()->addAction( selectAllAction );
+ messageListView()->addAction(createSeparator());
+ messageListView()->addAction( markAction );
+ messageListView()->addAction( threadAction );
+ messageListView()->addAction( detachThreadAction );
+ messageListView()->addAction(createSeparator());
+ messageListView()->addAction( previousMessageAction );
+ messageListView()->addAction( nextMessageAction );
+ messageListView()->addAction( previousUnreadMessageAction );
+ messageListView()->addAction( nextUnreadMessageAction );
+ messageListView()->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ readMailWidget()->addAction(replyAction);
+ readMailWidget()->addAction(replyAllAction);
+ readMailWidget()->addAction(forwardAction);
+ readMailWidget()->addAction(createSeparator());
+ readMailWidget()->addAction(deleteMailAction);
+ readMailWidget()->addAction(createSeparator());
+ readMailWidget()->addAction(scrollReaderDownAction);
+ readMailWidget()->addAction(scrollReaderUpAction);
+ readMailWidget()->addAction(readerMarkMessageAsUnreadAction);
+ readMailWidget()->addAction(readerMarkMessageAsImportantAction);
+ readMailWidget()->addAction(readerMarkMessageAsNotImportantAction);
+ }
+}
+
+void EmailClient::updateActions()
+{
+ openFiles();
+
+ // Ensure that the actions have been initialised
+ initActions();
+
+ //Enable marking and selectAll actions only if we have messages.
+ int messageCount = messageListView()->rowCount();
+ setActionVisible(markAction, messageCount > 0);
+ setActionVisible(selectAllAction, (messageCount > 1 && messageCount != selectionCount));
+
+ // Only enable empty trash action if the trash has messages in it
+ QMailMessageKey typeFilter(QMailMessageKey::messageType(QMailMessage::Email));
+ QMailMessageKey trashFilter(QMailMessageKey::status(QMailMessage::Trash));
+ setActionVisible(threadAction, (messageCount > 0) && !markingMode);
+
+ messageCount = QMailStore::instance()->countMessages(typeFilter & trashFilter);
+
+ setActionVisible(emptyTrashAction, (messageCount > 0) && !markingMode);
+
+ // Set the visibility for each action to whatever was last configured
+ QMap<QAction*, bool>::iterator it = actionVisibility.begin(), end = actionVisibility.end();
+ for ( ; it != end; ++it)
+ it.key()->setVisible(it.value());
+}
+
+
+void EmailClient::delayedInit()
+{
+ if (moveAction)
+ return; // delayedInit already done
+
+ QMailStore* store = QMailStore::instance();
+
+ // 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
+ connect(store, SIGNAL(messagesUpdated(QMailMessageIdList)), this, SLOT(messagesUpdated(QMailMessageIdList)));
+
+ connect(&fetchTimer, SIGNAL(timeout()), this, SLOT(automaticFetch()) );
+
+ // Ideally would make actions functions methods and delay their
+ // creation until context menu is shown.
+ initActions();
+ updateActions();
+
+ QTimer::singleShot(0, this, SLOT(openFiles()) );
+}
+
+EmailFolderView* EmailClient::createFolderView()
+{
+ EmailFolderView* view = MessageUiBase::createFolderView();
+ return view;
+}
+
+MessageListView* EmailClient::createMessageListView()
+{
+ MessageListView* view = MessageUiBase::createMessageListView();
+ return view;
+}
+
+void EmailClient::init()
+{
+ getMailButton = 0;
+ getAccountButton = 0;
+ cancelButton = 0;
+ composeButton = 0;
+ searchButton = 0;
+ synchronizeAction = 0;
+ settingsAction = 0;
+ standardFoldersAction = 0;
+ workOfflineAction = 0;
+ emptyTrashAction = 0;
+ moveAction = 0;
+ copyAction = 0;
+ restoreAction = 0;
+ selectAllAction = 0;
+ deleteMailAction = 0;
+ m_exportAction = 0;
+
+ // Connect our service action signals
+ m_flagRetrievalAction = new QMailRetrievalAction(this);
+
+ // Use a separate action for flag updates, which are not directed by the user
+ connect(m_flagRetrievalAction, SIGNAL(activityChanged(QMailServiceAction::Activity)), this, SLOT(flagRetrievalActivityChanged(QMailServiceAction::Activity)));
+
+ // We need to load the settings in case they affect our service handlers
+ readSettings();
+}
+
+void EmailClient::cancelOperation()
+{
+ if ( !cancelButton->isEnabled() )
+ return;
+
+ clearStatusText();
+
+ retrievalAccountIds.clear();
+
+ if (isSending()) {
+ if (m_transmitAction->isRunning())
+ m_transmitAction->cancelOperation();
+
+ setSendingInProgress(false);
+ }
+ if (isRetrieving()) {
+ if (m_retrievalAction->isRunning())
+ m_retrievalAction->cancelOperation();
+
+ setRetrievalInProgress(false);
+ }
+
+ if (m_flagRetrievalAction && m_flagRetrievalAction->isRunning())
+ m_flagRetrievalAction->cancelOperation();
+
+
+ if (m_exportAction && m_exportAction->isRunning())
+ m_exportAction->cancelOperation();
+
+ foreach(QMailStorageAction *action, m_outboxActions) {
+ if (action->isRunning())
+ action->cancelOperation();
+ }
+}
+
+/* Enqueue mail must always store the mail in the outbox */
+void EmailClient::beginEnqueueMail(QMailMessage& mail)
+{
+ // Does this account support sending a message by reference from an external sent folder?
+ QMailAccount account(mail.parentAccountId());
+ if ((account.status() & QMailAccount::CanReferenceExternalData) &&
+ (account.status() & QMailAccount::CanTransmitViaReference) &&
+ account.standardFolder(QMailFolder::SentFolder).isValid() &&
+ QMailFolder(account.standardFolder(QMailFolder::SentFolder)).id().isValid()) {
+ mail.setStatus(QMailMessage::TransmitFromExternal, true);
+ }
+
+ mail.setStatus(QMailMessage::Outbox, true);
+ m_outboxingMessages.append(mail);
+
+ QMailStorageAction *outboxAction(new QMailStorageAction());
+ connect(outboxAction, SIGNAL(activityChanged(QMailServiceAction::Activity)),
+ this, SLOT(finishEnqueueMail(QMailServiceAction::Activity)));
+ m_outboxActions.append(outboxAction);
+ if (!mail.id().isValid()) {
+ // This message is present only on the local device until we externalise or send it
+ mail.setStatus(QMailMessage::LocalOnly, true);
+ outboxAction->addMessages(QMailMessageList() << mail);
+ } else {
+ outboxAction->updateMessages(QMailMessageList() << mail);
+ }
+}
+
+void EmailClient::finishEnqueueMail(QMailServiceAction::Activity activity)
+{
+ if ((activity == QMailServiceAction::Successful) ||
+ (activity == QMailServiceAction::Failed)) {
+ QMailStorageAction *serviceAction(qobject_cast<QMailStorageAction*>(sender()));
+ if (serviceAction) {
+ m_outboxActions.removeAll(serviceAction);
+ serviceAction->deleteLater();
+ }
+ }
+
+ if (activity == QMailServiceAction::Successful) {
+ if (workOfflineAction->isChecked()) {
+ AcknowledgmentBox::show(tr("Message queued"), tr("Message has been queued in outbox"));
+ } else {
+ sendAllQueuedMail(true);
+ }
+
+ if (closeAfterWrite) {
+ closeAfterTransmissionsFinished();
+ closeApplication();
+ }
+ } else if (activity == QMailServiceAction::Failed) {
+ QMailStore *store = QMailStore::instance();
+ foreach (QMailMessage mail, m_outboxingMessages) {
+ if (!mail.id().isValid()) {
+ mail.setStatus(QMailMessage::LocalOnly, true);
+ store->addMessage(&mail);
+ } else {
+ store->updateMessage(&mail);
+ }
+ }
+ m_outboxingMessages.clear();
+
+ AcknowledgmentBox::show(tr("Message queuing failure"), tr("Failed to queue message in outbox."));
+ }
+ if (m_outboxActions.isEmpty()) {
+ // No messages left to queue in outbox
+ m_outboxingMessages.clear();
+ }
+}
+
+/* Simple, do nothing */
+void EmailClient::discardMail()
+{
+ // Reset these in case user chose reply but discarded message
+ repliedFromMailId = QMailMessageId();
+ repliedFlags = 0;
+
+ if (closeAfterWrite) {
+ closeAfterTransmissionsFinished();
+ closeApplication();
+ }
+}
+
+void EmailClient::saveAsDraft(QMailMessage& mail)
+{
+ // Mark the message as a draft so that it is presented correctly
+ mail.setStatus(QMailMessage::Draft, true);
+
+ bool inserted(false);
+ if (!mail.id().isValid()) {
+ // This message is present only on the local device until we externalise or send it
+ mail.setStatus(QMailMessage::LocalOnly, true);
+ inserted = QMailStore::instance()->addMessage(&mail);
+ } else {
+ QMailMessageId msgId = mail.id();
+ mail.setId(QMailMessageId());
+ mail.setStatus(QMailMessage::LocalOnly, true);
+ mail.setServerUid(QString());
+ inserted = QMailStore::instance()->addMessage(&mail);
+ QMailStore::instance()->removeMessage(msgId, QMailStore::CreateRemovalRecord);
+ }
+
+ if (inserted) {
+ // Inform the responsible service that it is a draft
+
+ QMailDisconnected::moveToStandardFolder(QMailMessageIdList() << mail.id(),QMailFolder::DraftsFolder);
+ QMailDisconnected::flagMessage(mail.id(),QMailMessage::Draft,0,"Flagging message as draft");
+ exportPendingChanges();
+
+ lastDraftId = mail.id();
+
+ } else {
+ QMailFolder folder(mail.parentFolderId());
+ accessError(folder.displayName());
+ }
+}
+
+/* Mark a message as replied/repliedall/forwarded */
+void EmailClient::mailResponded()
+{
+ if (repliedFromMailId.isValid()) {
+ QMailDisconnected::flagMessage(repliedFromMailId,repliedFlags,0,"Marking message as replied/forwared");
+ exportPendingChanges();
+ repliedFromMailId = QMailMessageId();
+ repliedFlags = 0;
+ }
+}
+
+// each message that belongs to the current found account
+void EmailClient::sendAllQueuedMail(bool userRequest)
+{
+ transmissionFailure = false;
+ QMailMessageKey outboxFilter(QMailMessageKey::status(QMailMessage::Outbox) & ~QMailMessageKey::status(QMailMessage::Trash));
+
+ if (transmitAccountIds.isEmpty()) {
+ // Find which accounts have messages to transmit in the outbox
+ foreach (const QMailMessageMetaData &metaData, QMailStore::instance()->messagesMetaData(outboxFilter, QMailMessageKey::ParentAccountId, QMailStore::ReturnDistinct)) {
+ transmitAccountIds.append(metaData.parentAccountId());
+ }
+ if (transmitAccountIds.isEmpty())
+ return;
+ }
+
+ if (userRequest) {
+ // See if the message viewer wants to suppress the 'Sending messages' notification
+ QMailMessageIdList outgoingIds = QMailStore::instance()->queryMessages(outboxFilter);
+ if (!readMailWidget()->handleOutgoingMessages(outgoingIds)) {
+ // Tell the user we're responding
+ QString detail;
+ if (outgoingIds.count() == 1) {
+ QMailMessageMetaData mail(outgoingIds.first());
+ detail = mailType(mail.messageType());
+ } else {
+ detail = tr("%n message(s)", "%1: number of messages", outgoingIds.count());
+ }
+
+ AcknowledgmentBox::show(tr("Sending"), tr("Sending:") + ' ' + detail);
+ }
+ }
+
+ while (!transmitAccountIds.isEmpty()) {
+ QMailAccountId transmitId(transmitAccountIds.first());
+ transmitAccountIds.removeFirst();
+
+ if (verifyAccount(transmitId, true)) {
+ setSendingInProgress(true);
+ transmitAction("Sending messages")->transmitMessages(transmitId);
+ return;
+ }
+ }
+}
+
+void EmailClient::rollBackUpdates(QMailAccountId accountId)
+{
+ if (!QMailDisconnected::updatesOutstanding(accountId))
+ return;
+ if (QMessageBox::Yes == QMessageBox::question(this,
+ tr("Pending updates"),
+ tr("There are local updates pending synchronization, " \
+ "do you want to revert these changes?"),
+ QMessageBox::Yes | QMessageBox::No)) {
+ QMailDisconnected::rollBackUpdates(accountId);
+ }
+}
+
+void EmailClient::flagMessage(const QMailMessageId& id, quint64 setMask, quint64 unsetMask, const QString& description)
+{
+ QMailDisconnected::flagMessage(id, setMask, unsetMask, description);
+ exportPendingChanges();
+}
+
+bool EmailClient::verifyAccount(const QMailAccountId &accountId, bool outgoing)
+{
+ QMailAccount account(accountId);
+
+ if ((outgoing && ((account.status() & QMailAccount::CanTransmit) == 0)) ||
+ (!outgoing && ((account.status() & QMailAccount::CanRetrieve) == 0))) {
+ QString caption(outgoing ? tr("Cannot transmit") : tr("Cannot retrieve"));
+ QString text(tr("Account configuration is incomplete."));
+ QMessageBox box(caption, text, QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton, QMessageBox::NoButton);
+ box.exec();
+ return false;
+ }
+
+ return true;
+}
+
+void EmailClient::transmitCompleted()
+{
+ // Check for messages that could nto be sent, e.g. due to bad recipients
+ if (transmissionFailure) {
+ transmissionFailure = false;
+ const QMailServiceAction::Status status(m_transmitAction->status());
+ transferFailure(status.accountId,
+ tr("Some messages could not be sent and have been left in the outbox. Verify that recipient addresses are well formed."),
+ QMailServiceAction::Status::ErrInvalidAddress);
+ }
+
+ // If there are more SMTP accounts to service, continue
+ if (!transmitAccountIds.isEmpty()) {
+ sendAllQueuedMail();
+ } else {
+ if (primaryActivity == Sending)
+ clearStatusText();
+
+ setSendingInProgress(false);
+
+ // If the sent message was a response, we have modified the original message's status
+ mailResponded();
+ }
+}
+
+void EmailClient::retrievalCompleted()
+{
+ messageListView()->updateActions(); // update GetMoreMessagesButton
+ if (mailAccountId.isValid()) {
+ // See if there are more accounts to process
+ getNextNewMail();
+ } else {
+ autoGetMail = false;
+
+ if (primaryActivity == Retrieving)
+ clearStatusText();
+
+ setRetrievalInProgress(false);
+ }
+}
+
+void EmailClient::storageActionCompleted()
+{
+ clearStatusText();
+ exportPendingChanges();
+}
+
+void EmailClient::getNewMail()
+{
+ // Try to preserve the message list selection
+ selectedMessageId = messageListView()->current();
+ if (!selectedMessageId.isValid())
+ selectedMessageId = QMailMessageId();
+
+ setRetrievalInProgress(true);
+ retrieveAction("Exporting account updates")->synchronize(mailAccountId, QMailRetrievalAction::defaultMinimum());
+}
+
+void EmailClient::getAllNewMail()
+{
+ if (isRetrieving()) {
+ QString msg(tr("Cannot synchronize accounts because a synchronize operation is currently in progress"));
+ QMessageBox::warning(0, tr("Synchronize in progress"), msg, tr("OK") );
+ return;
+ }
+
+ retrievalAccountIds.clear();
+
+ QMailAccountKey retrieveKey(QMailAccountKey::status(QMailAccount::CanRetrieve, QMailDataComparator::Includes));
+ QMailAccountKey enabledKey(QMailAccountKey::status(QMailAccount::Enabled, QMailDataComparator::Includes));
+ retrievalAccountIds = QMailStore::instance()->queryAccounts(retrieveKey & enabledKey);
+
+ if (!retrievalAccountIds.isEmpty())
+ getNextNewMail();
+}
+
+void EmailClient::getAccountMail()
+{
+ if (isRetrieving()) {
+ QString msg(tr("Cannot synchronize account because a synchronize operation is currently in progress"));
+ QMessageBox::warning(0, tr("Synchronize in progress"), msg, tr("OK") );
+ return;
+ }
+
+ retrievalAccountIds.clear();
+
+ if (const QAction* action = static_cast<const QAction*>(sender())) {
+ QMailAccountId accountId(action->data().value<QMailAccountId>());
+ retrievalAccountIds.append(accountId);
+ getNextNewMail();
+ }
+}
+
+void EmailClient::getSingleMail(const QMailMessageMetaData& message)
+{
+ if (isRetrieving()) {
+ QString msg(tr("Cannot retrieve message because a retrieval operation is currently in progress"));
+ QMessageBox::warning(0, tr("Retrieval in progress"), msg, tr("OK") );
+ return;
+ }
+
+ mailAccountId = QMailAccountId();
+ setRetrievalInProgress(true);
+
+ retrieveAction("Retrieving single message")->retrieveMessages(QMailMessageIdList() << message.id(), QMailRetrievalAction::Content);
+}
+
+void EmailClient::retrieveMessagePortion(const QMailMessageMetaData& message, uint bytes)
+{
+ if (isRetrieving()) {
+ QString msg(tr("Cannot retrieve message portion because a retrieval operation is currently in progress"));
+ QMessageBox::warning(0, tr("Retrieval in progress"), msg, tr("OK") );
+ return;
+ }
+
+ mailAccountId = QMailAccountId();
+ setRetrievalInProgress(true);
+
+ QMailMessage msg(message.id());
+ retrieveAction("Retrieving message range")->retrieveMessageRange(message.id(), msg.body().length() + bytes);
+}
+
+void EmailClient::retrieveMessagePart(const QMailMessagePart::Location &partLocation)
+{
+ if (isRetrieving()) {
+ QString msg(tr("Cannot retrieve message part because a retrieval operation is currently in progress"));
+ QMessageBox::warning(0, tr("Retrieval in progress"), msg, tr("OK") );
+ return;
+ }
+
+ if (!partLocation.isValid(true)) {
+ QString msg(tr("Cannot retrieve message part without a valid message ID"));
+ QMessageBox::warning(0, tr("Invalid part location"), msg, tr("OK") );
+ } else {
+ QMailMessageMetaData metaData(partLocation.containingMessageId());
+
+ mailAccountId = QMailAccountId();
+ setRetrievalInProgress(true);
+
+ retrieveAction("Retreiving message part")->retrieveMessagePart(partLocation);
+ }
+}
+
+void EmailClient::retrieveMessagePartPortion(const QMailMessagePart::Location &partLocation, uint bytes)
+{
+ if (isRetrieving()) {
+ QString msg(tr("Cannot retrieve message part portion because a retrieval operation is currently in progress"));
+ QMessageBox::warning(0, tr("Retrieval in progress"), msg, tr("OK") );
+ return;
+ }
+
+ if (!partLocation.isValid(true)) {
+ QString msg(tr("Cannot retrieve message part without a valid message ID"));
+ QMessageBox::warning(0, tr("Invalid part location"), msg, tr("OK") );
+ } else {
+ QMailMessage messsage(partLocation.containingMessageId());
+
+ mailAccountId = QMailAccountId();
+ setRetrievalInProgress(true);
+
+ const QMailMessagePart &part(messsage.partAt(partLocation));
+ retrieveAction("Retrieving message part portion")->retrieveMessagePartRange(partLocation, part.body().length() + bytes);
+ }
+}
+
+void EmailClient::readReplyRequested(const QMailMessageMetaData& mail)
+{
+ if (mail.messageType() == QMailMessage::Mms) {
+ }
+}
+
+void EmailClient::getNextNewMail()
+{
+ if (!retrievalAccountIds.isEmpty()) {
+ mailAccountId = retrievalAccountIds.takeFirst();
+ getNewMail();
+ } else {
+ // We have processed all accounts
+ autoGetMail = false;
+ mailAccountId = QMailAccountId();
+
+ if (primaryActivity == Retrieving)
+ clearStatusText();
+
+ setRetrievalInProgress(false);
+ retrieveVisibleMessagesFlags();
+ }
+}
+
+void EmailClient::sendFailure(const QMailAccountId &accountId)
+{
+ setSendingInProgress(false);
+
+ Q_UNUSED(accountId)
+}
+
+void EmailClient::receiveFailure(const QMailAccountId &accountId)
+{
+ setRetrievalInProgress(false);
+
+ autoGetMail = false;
+
+ // Try the next account if we're working through a set of accounts
+ if (!retrievalAccountIds.isEmpty())
+ QTimer::singleShot(0, this, SLOT(getNextNewMail()));
+
+ Q_UNUSED(accountId)
+}
+
+void EmailClient::transferFailure(const QMailAccountId& accountId, const QString& text, int code)
+{
+ QString caption, action;
+ if (isSending()) {
+ caption = tr("Send Failure");
+ action = tr("Error sending %1: %2", "%1: message type, %2: error text");
+ } else if (isRetrieving()) {
+ caption = autoGetMail ? tr("Automatic Fetch Failure") : tr("Retrieve Failure");
+ action = tr("Error retrieving %1: %2", "%1: message type, %2: error text");
+ }
+
+ if (!action.isEmpty()) {
+ if (accountId.isValid()) {
+ QMailAccount account(accountId);
+ QMailMessage::MessageType type(account.messageType());
+ action = action.arg(mailType(type)).arg(text);
+
+ // If we could have multiple accounts, name the relevant one
+ if (type == QMailMessage::Email)
+ action.prepend(" - ").prepend(account.name());
+ } else {
+ action = action.arg(tr("message")).arg(text);
+ }
+
+ qMailLog(Messaging) << "transferFailure:" << caption << '-' << action;
+ if (code != QMailServiceAction::Status::ErrCancel) {
+ clearStatusText();
+ QMessageBox::warning(0, caption, action, QMessageBox::Ok);
+ } else {
+ emit updateStatus(tr("Transfer cancelled"));
+ }
+
+ rollBackUpdates(accountId);
+
+ if (isSending()) {
+ sendFailure(accountId);
+ } else {
+ receiveFailure(accountId);
+ }
+ }
+}
+
+void EmailClient::storageActionFailure(const QMailAccountId& accountId, const QString& text)
+{
+ QString caption(tr("Storage Failure"));
+ QString action(tr("Unable to perform requested action %1", "%1: error text"));
+
+ if (accountId.isValid()) {
+ QMailAccount account(accountId);
+ action.prepend(" - ").prepend(account.name());
+ }
+
+ clearStatusText();
+ QMessageBox::warning(0, caption, action.arg(text), QMessageBox::Ok);
+}
+
+QString EmailClient::mailType(QMailMessage::MessageType type)
+{
+ QString key(QMailComposerFactory::defaultKey(type));
+ if (!key.isEmpty())
+ return QMailComposerFactory::displayName(key, type);
+
+ return tr("Message");
+}
+
+void EmailClient::messageActivated()
+{
+ QMailMessageId currentId = messageListView()->current();
+ if(!currentId.isValid())
+ return;
+
+ QMailMessage message(currentId);
+ bool hasNext = false;
+ bool hasPrevious = false;
+ if (readMailWidget()->displayedMessage() != currentId)
+ readMailWidget()->displayMessage(currentId, QMailViewerFactory::AnyPresentation, hasNext, hasPrevious);
+}
+
+void EmailClient::messageOpenRequested()
+{
+ QMailMessageId currentId = messageListView()->current();
+ if(!currentId.isValid())
+ return;
+
+ QMailMessage message(currentId);
+ if (message.status() & QMailMessage::Draft) {
+ modify(message);
+ }
+}
+
+void EmailClient::showSearchResult(const QMailMessageId &id)
+{
+ readMailWidget()->displayMessage(id, QMailViewerFactory::AnyPresentation, false, false);
+}
+
+void EmailClient::accessError(const QString &folderName)
+{
+ QString msg = tr("Cannot access %1. Either there is insufficient space, or another program is accessing the mailbox.").arg(folderName);
+ QMessageBox::critical( 0, tr("Access error"), msg );
+}
+
+void EmailClient::readSettings()
+{
+ QSettings mailconf("QtProject","qtmail");
+ mailconf.beginGroup("qtmailglobal");
+ mailconf.endGroup();
+
+ mailconf.beginGroup("settings");
+ int val = mailconf.value("interval", -1 ).toInt();
+ if ( val == -1 ) {
+ fetchTimer.stop();
+ } else {
+ fetchTimer.start( val * 60 * 1000);
+ }
+ mailconf.endGroup();
+}
+
+bool EmailClient::saveSettings()
+{
+ const int QTMAIL_CONFIG_VERSION = 100;
+ QSettings mailconf("QtProject","qtmail");
+
+ mailconf.beginGroup("qtmailglobal");
+ mailconf.remove("");
+ mailconf.setValue("version", QTMAIL_CONFIG_VERSION );
+ mailconf.endGroup();
+
+ mailconf.beginGroup("qtmailglobal");
+ mailconf.endGroup();
+ return true;
+}
+
+void EmailClient::updateGetMailButton()
+{
+ bool visible(false);
+
+ // We can get only mail if we're currently inactive
+ if (!isTransmitting()) {
+ // At least one account must be able to retrieve mail
+ QMailAccountKey retrieveKey(QMailAccountKey::status(QMailAccount::CanRetrieve, QMailDataComparator::Includes));
+ visible = (QMailStore::instance()->countAccounts(retrieveKey) != 0);
+ }
+
+ setActionVisible(getMailButton, visible);
+
+ updateGetAccountButton();
+}
+
+void EmailClient::updateGetAccountButton()
+{
+ // We can get only mail if we're currently inactive
+ bool inactive(!isTransmitting());
+
+ if (QMailMessageSet* item = folderView()->currentItem()) {
+ QMailAccountId accountId(item->data(EmailFolderModel::ContextualAccountIdRole).value<QMailAccountId>());
+ bool accountContext(accountId.isValid());
+
+ // Only show the get mail for account button if there are multiple accounts to retrieve from
+ bool multipleMailAccounts = (emailAccounts().count() > 1);
+ setActionVisible(getAccountButton, (inactive && accountContext && multipleMailAccounts));
+ }
+}
+
+void EmailClient::updateAccounts()
+{
+ queuedAccountIds.clear();
+ updateGetMailButton();
+}
+
+void EmailClient::deleteSelectedMessages()
+{
+ QMailMessageIdList deleteList;
+ deleteList = messageListView()->selected();
+
+ int deleteCount = deleteList.count();
+ if (deleteCount == 0)
+ return;
+
+ if (isSending()) {
+ // Do not delete messages from the outbox folder while we're sending
+ QMailMessageKey outboxFilter(QMailMessageKey::status(QMailMessage::Outbox));
+ if (QMailStore::instance()->countMessages(QMailMessageKey::id(deleteList) & outboxFilter)) {
+ AcknowledgmentBox::show(tr("Cannot delete"), tr("Message transmission is in progress"));
+ return;
+ }
+ }
+
+ // If any of these messages are not yet trash, then we're only moving to trash
+ QMailMessageKey idFilter(QMailMessageKey::id(deleteList));
+ QMailMessageKey notTrashFilter(QMailMessageKey::status(QMailMessage::Trash, QMailDataComparator::Excludes));
+
+ const bool deleting(QMailStore::instance()->countMessages(idFilter & notTrashFilter) == 0);
+
+ // Tell the user we're doing what they asked for
+ QString action;
+ QString actionDetails;
+ if ( deleting ) {
+ QString item(tr("%n message(s)", "%1: number of messages", deleteCount));
+ if ( !confirmDelete( this, tr("Delete"), item ) )
+ return;
+
+ action = tr("Deleting");
+ actionDetails = tr("Deleting %n message(s)", "%1: number of messages", deleteCount);
+ } else {
+ action = tr("Moving");
+ actionDetails = tr("Moving %n message(s) to Trash", "%1: number of messages", deleteCount);
+ }
+
+ AcknowledgmentBox::show(action, actionDetails);
+
+ clearNewMessageStatus(QMailMessageKey::id(messageListView()->selected()));
+
+ if (deleting)
+ {
+ //delete LocalOnly messages clientside first
+ QMailMessageKey localOnlyKey(QMailMessageKey::id(deleteList) & QMailMessageKey::status(QMailMessage::LocalOnly));
+ QMailMessageIdList localOnlyIds(QMailStore::instance()->queryMessages(localOnlyKey));
+ if(!localOnlyIds.isEmpty())
+ {
+ QMailStore::instance()->removeMessages(QMailMessageKey::id(localOnlyIds));
+ deleteList = (deleteList.toSet().subtract(localOnlyIds.toSet())).toList();
+ }
+ if(!deleteList.isEmpty())
+ storageAction("Deleting messages..")->deleteMessages(deleteList);
+ }
+ else
+ {
+ QMailDisconnected::moveToStandardFolder(deleteList,QMailFolder::TrashFolder);
+ QMailDisconnected::flagMessages(deleteList,QMailMessage::Trash,0,"Marking messages as deleted");
+ exportPendingChanges();
+ }
+
+ if (markingMode) {
+ // After deleting the messages, clear marking mode
+ setMarkingMode(false);
+ }
+}
+
+void EmailClient::moveSelectedMessagesTo(const QMailFolderId &destination)
+{
+ QMailMessageIdList moveList = messageListView()->selected();
+ if (moveList.isEmpty())
+ return;
+
+ clearNewMessageStatus(QMailMessageKey::id(moveList));
+
+ QMailDisconnected::moveToFolder(moveList,destination);
+ exportPendingChanges();
+
+ AcknowledgmentBox::show(tr("Moving"), tr("Moving %n message(s)", "%1: number of messages", moveList.count()));
+}
+
+void EmailClient::copySelectedMessagesTo(const QMailFolderId &destination)
+{
+ QMailMessageIdList copyList = messageListView()->selected();
+ if (copyList.isEmpty())
+ return;
+
+ clearNewMessageStatus(QMailMessageKey::id(copyList));
+
+#if DISCONNECTED_COPY
+ // experimental disconnected copy disabled for now.
+ // retrieveMessageList and retriveMessages(flags) logic doesn't properly
+ // handle copied messages
+ copyToFolder(copyList,destination);
+#else
+ storageAction("Copying messages")->onlineCopyMessages(copyList, destination);
+#endif
+
+ AcknowledgmentBox::show(tr("Copying"), tr("Copying %n message(s)", "%1: number of messages", copyList.count()));
+}
+
+bool EmailClient::applyToSelectedFolder(void (EmailClient::*function)(const QMailFolderId&))
+{
+ locationSet.clear();
+
+ // Find the current locations for each of the selected messages
+ QMailMessageKey key(QMailMessageKey::id(messageListView()->selected()));
+ foreach (const QMailMessageMetaData &message, QMailStore::instance()->messagesMetaData(key, QMailMessageKey::ParentFolderId)) {
+ locationSet.insert(message.parentFolderId());
+ }
+
+ if (!locationSet.isEmpty()) {
+ QSet<QMailAccountId> locationAccountIds;
+ foreach (const QMailFolderId &folderId, locationSet) {
+ QMailFolder folder(folderId);
+ if (folder.parentAccountId().isValid())
+ locationAccountIds.insert(folder.parentAccountId());
+ }
+
+ QMailFolderIdList list;
+
+ if (locationAccountIds.count() == 1) {
+ AccountFolderModel model(*locationAccountIds.begin());
+ model.init();
+
+ QList<QMailMessageSet*> invalidItems;
+ invalidItems.append(model.itemFromIndex(model.indexFromAccountId(*locationAccountIds.begin())));
+
+ // If the message(s) are in a single location, do not permit that as a destination
+ if (locationSet.count() == 1) {
+ invalidItems.append(model.itemFromIndex(model.indexFromFolderId(*locationSet.begin())));
+ }
+
+ SelectFolderDialog selectFolderDialog(&model);
+ selectFolderDialog.setInvalidSelections(invalidItems);
+ selectFolderDialog.exec();
+
+ if (selectFolderDialog.result() == QDialog::Accepted) {
+ // Apply the function to the selected messages, with the selected folder argument
+ (this->*function)(model.folderIdFromIndex(model.indexFromItem(selectFolderDialog.selectedItem())));
+ return true;
+ }
+ } else {
+ // TODO:
+ AcknowledgmentBox::show(tr("Whoops"), tr("Cannot handle messages from multiple accounts..."));
+ }
+
+
+ }
+
+ return false;
+}
+
+void EmailClient::moveSelectedMessages()
+{
+ QMailMessageIdList moveList = messageListView()->selected();
+ if (moveList.isEmpty())
+ return;
+
+ if (isSending()) {
+ // Do not move outbox messages while we're sending
+ QMailMessageKey outboxFilter(QMailMessageKey::status(QMailMessage::Outbox));
+ if (QMailStore::instance()->countMessages(QMailMessageKey::id(moveList) & outboxFilter)) {
+ AcknowledgmentBox::show(tr("Cannot move"), tr("Message transmission is in progress"));
+ return;
+ }
+ }
+
+ if (applyToSelectedFolder(&EmailClient::moveSelectedMessagesTo)) {
+ if (markingMode) {
+ // After moving the messages, clear marking mode
+ setMarkingMode(false);
+ }
+ }
+}
+
+void EmailClient::copySelectedMessages()
+{
+ QMailMessageIdList copyIds = messageListView()->selected();
+
+#if DISCONNECTED_COPY
+ // disabled for now
+ foreach(QMailMessageId id, copyIds) {
+ QMailMessage message(id);
+ bool complete(message.status() & QMailMessage::ContentAvailable);
+ for(uint i = 0; (i < message.partCount()) && complete; ++i) {
+ complete &= message.partAt(i).contentAvailable();
+ }
+
+ if (!complete) {
+ // IMAP limitation
+ AcknowledgmentBox::show(tr("Cannot copy"), tr("Can not copy partial message"));
+ return;
+ }
+ }
+#endif
+
+ if (applyToSelectedFolder(&EmailClient::copySelectedMessagesTo)) {
+ if (markingMode) {
+ // After copying the messages, clear marking mode
+ setMarkingMode(false);
+ }
+ }
+}
+
+void EmailClient::restoreSelectedMessages()
+{
+ QMailMessageKey selectedFilter(QMailMessageKey::id(messageListView()->selected()));
+ QMailMessageKey trashFilter(QMailMessageKey::status(QMailMessage::Trash));
+
+ // Only messages currently in the trash folder should be restored
+ QMailMessageIdList restoreIds = QMailStore::instance()->queryMessages(selectedFilter & trashFilter);
+ if (restoreIds.isEmpty())
+ return;
+
+ AcknowledgmentBox::show(tr("Restoring"), tr("Restoring %n message(s)", "%1: number of messages", restoreIds.count()));
+ QMailDisconnected::restoreToPreviousFolder(QMailMessageKey::id(restoreIds));
+ QMailDisconnected::flagMessages(restoreIds,0,QMailMessage::Trash,"Restoring messages");
+ exportPendingChanges();
+}
+
+void EmailClient::selectAll()
+{
+ if (!markingMode) {
+ // No point selecting messages unless we're in marking mode
+ setMarkingMode(true);
+ }
+
+ messageListView()->selectAll();
+}
+
+void EmailClient::emptyTrashFolder()
+{
+ QMailMessageKey trashFilter(EmailStandardFolderMessageSet::contentKey(QMailFolder::TrashFolder));
+
+ QMailMessageIdList trashIds = QMailStore::instance()->queryMessages(trashFilter);
+ if (trashIds.isEmpty())
+ return;
+
+ if (confirmDelete(this, "Empty trash", tr("all messages in the trash"))) {
+ AcknowledgmentBox::show(tr("Deleting"), tr("Deleting %n message(s)", "%1: number of messages", trashIds.count()));
+ storageAction("Deleting messages")->deleteMessages(trashIds);
+ }
+}
+
+void EmailClient::detachThread()
+{
+ QMailMessageIdList ids(messageListView()->selected());
+ if (ids.count() == 1) {
+ QString caption(tr("Detach"));
+ QString msg(tr("Are you sure you want to detach this message from its current thread?"));
+
+ if (QMessageBox::question(this, caption, msg, QMessageBox::Yes, QMessageBox::No|QMessageBox::Default|QMessageBox::Escape, 0) == QMessageBox::Yes) {
+ QMailMessageMetaData metaData(ids.first());
+ metaData.setInResponseTo(QMailMessageId());
+
+ QMailStore::instance()->updateMessage(&metaData);
+ }
+ }
+}
+
+void EmailClient::connectivityChanged(QMailServiceAction::Connectivity /*connectivity*/)
+{
+}
+
+void EmailClient::activityChanged(QMailServiceAction::Activity activity)
+{
+ if (QMailServiceAction *action = qobject_cast<QMailServiceAction*>(sender())) {
+ if (activity == QMailServiceAction::Successful) {
+ if (action == m_transmitAction) {
+ transmitCompleted();
+ } else if (action == m_retrievalAction) {
+ retrievalCompleted();
+ } else if (action->metaObject()->className() == QString("QMailStorageAction")) {
+ storageActionCompleted();
+ action->deleteLater();
+ } else if (action == m_exportAction) {
+ m_queuedExports.takeFirst(); // finished successfully
+ clearStatusText();
+ runNextPendingExport();
+ }
+ } else if (activity == QMailServiceAction::Failed) {
+ const QMailServiceAction::Status status(action->status());
+ if (action->metaObject()->className() == QString("QMailStorageAction")) {
+ storageActionFailure(status.accountId, status.text);
+ action->deleteLater();
+ } else if (action == m_exportAction) {
+ rollBackUpdates(status.accountId);
+ } else {
+ transferFailure(status.accountId, status.text, status.errorCode);
+ }
+ }
+ }
+}
+
+void EmailClient::statusChanged(const QMailServiceAction::Status &status)
+{
+ if (QMailServiceAction *action = static_cast<QMailServiceAction*>(sender())) {
+ // If we have completed, don't show the status info
+ if (action->activity() == QMailServiceAction::InProgress) {
+ QString text = status.text;
+ if (status.accountId.isValid()) {
+ QMailAccount account(status.accountId);
+ text.prepend(account.name() + " - ");
+ }
+ emit updateStatus(text);
+ }
+ }
+}
+
+void EmailClient::progressChanged(uint progress, uint total)
+{
+ Q_UNUSED(progress);
+ Q_UNUSED(total);
+// emit updateProgress(progress, total);
+}
+
+void EmailClient::messagesFailedTransmission()
+{
+ transmissionFailure = true;
+}
+
+
+void EmailClient::flagRetrievalActivityChanged(QMailServiceAction::Activity activity)
+{
+ if (QMailServiceAction *action = static_cast<QMailServiceAction*>(sender())) {
+ if (activity == QMailServiceAction::Failed) {
+ // Report failure
+ const QMailServiceAction::Status status(action->status());
+ qMailLog(Messaging) << "Failed to update message flags -" << status.text << "(" << status.errorCode << ")";
+ flagMessageIds.clear();
+ } else if (activity != QMailServiceAction::Successful) {
+ return;
+ }
+
+ // Are there pending message IDS to be checked?
+ if (!flagMessageIds.isEmpty()) {
+ m_flagRetrievalAction->retrieveMessages(flagMessageIds.toList(), QMailRetrievalAction::Flags);
+ flagMessageIds.clear();
+ }
+ }
+}
+
+void EmailClient::folderSelected(QMailMessageSet *item)
+{
+ if (item) {
+ initActions();
+ contextStatusUpdate();
+
+ bool atFolder(false);
+ bool showCreate(false);
+ bool showDelete(false);
+ bool showRename(false);
+
+ QMailAccountId accountId(item->data(EmailFolderModel::ContextualAccountIdRole).value<QMailAccountId>());
+ QMailFolderId folderId(item->data(EmailFolderModel::FolderIdRole).value<QMailFolderId>());
+
+ if (accountId.isValid()) {
+ selectedAccountId = accountId;
+
+ QMailAccount account(accountId);
+ getAccountButton->setText(tr("Synchronize %1", "%1:account name").arg(account.name()));
+ getAccountButton->setData(accountId);
+
+ // See if this is a folder that can have a menu
+ if (folderId.isValid()) {
+ atFolder = true;
+ selectedFolderId = folderId;
+
+ if (item->data(EmailFolderModel::FolderSynchronizationEnabledRole).value<bool>())
+ synchronizeAction->setText(tr("Exclude folder"));
+ else
+ synchronizeAction->setText(tr("Include folder"));
+
+ if (item->data(EmailFolderModel::FolderChildCreationPermittedRole).value<bool>())
+ showCreate = true;
+ if (item->data(EmailFolderModel::FolderDeletionPermittedRole).value<bool>())
+ showDelete = true;
+ if (item->data(EmailFolderModel::FolderRenamePermittedRole).value<bool>())
+ showRename = true;
+ } else {
+ //Can still create a root folder
+ selectedFolderId = QMailFolderId(0);
+ //check if account supports creating folders
+ showCreate = (account.status() & QMailAccount::CanCreateFolders);
+ }
+ }
+
+ setActionVisible(synchronizeAction, atFolder);
+ setActionVisible(createFolderAction, showCreate);
+ setActionVisible(deleteFolderAction, showDelete);
+ setActionVisible(renameFolderAction, showRename);
+
+ updateGetAccountButton();
+
+ bool contentsChanged = (item->messageKey() != messageListView()->key());
+ if (contentsChanged)
+ messageListView()->setKey(item->messageKey());
+
+ messageListView()->setFolderId(folderId);
+ messageListView()->updateActions();
+ updateActions();
+ }
+}
+
+void EmailClient::deleteFolder()
+{
+ QString folderName = QMailFolder(selectedFolderId).displayName();
+
+ if(QMessageBox::question(this, tr("Delete"), tr("Are you sure you wish to delete the folder %1 and all its contents?").arg(folderName), QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
+ return;
+ storageAction("Deleting folder ")->onlineDeleteFolder(selectedFolderId);
+}
+
+void EmailClient::createFolder()
+{
+ QString name = QInputDialog::getText(this, tr("New Folder Name"), tr("The name of the new folder should be: "));
+
+ if(name.isEmpty())
+ return;
+
+ storageAction("Creating folder ")->onlineCreateFolder(name, selectedAccountId, selectedFolderId);
+
+}
+
+void EmailClient::renameFolder()
+{
+ if(selectedFolderId.isValid())
+ {
+ QString oldName = QMailFolder(selectedFolderId).displayName();
+ QString newName = QInputDialog::getText(this, tr("Rename Folder"), tr("Rename folder %1 to: ").arg(oldName));
+
+ if(newName.isEmpty())
+ return;
+
+ storageAction("Renaming folder")->onlineRenameFolder(selectedFolderId, newName);
+ }
+}
+
+void EmailClient::search()
+{
+ static bool init = false;
+ if(!init) {
+ connect(searchView(), SIGNAL(searchResultSelected(QMailMessageId)), this, SLOT(showSearchResult(const QMailMessageId &)));
+ init = true;
+ }
+
+ searchView()->raise();
+ searchView()->activateWindow();
+ searchView()->reset();
+ searchView()->show();
+}
+
+void EmailClient::automaticFetch()
+{
+ if (isRetrieving())
+ return;
+
+ // TODO: remove this code - obsoleted by messageserver interval checking
+
+ qWarning("get all new mail automatic");
+ autoGetMail = true;
+ getAllNewMail();
+}
+
+/* TODO: Is external edit still relevant?
+
+ Someone external are making changes to the mailboxes. By this time
+ we won't know what changes has been made (nor is it feasible to try
+ to determine it). Close all actions which can have become
+ invalid due to the external edit. A writemail window will as such close, but
+ the information will be kept in memory (pasted when you reenter the
+ writemail window (hopefully the external edit is done by then)
+*/
+void EmailClient::externalEdit(const QString &mailbox)
+{
+ cancelOperation();
+ QString msg = mailbox + ' '; //no tr
+ msg += tr("was edited externally");
+ emit updateStatus(msg);
+}
+
+bool EmailClient::checkMailConflict(const QString& msg1, const QString& msg2)
+{
+ if ( writeMailWidget()->isVisible()) {
+ QString message = tr("<qt>You are currently editing a message:<br>%1</qt>").arg(msg1);
+ switch( QMessageBox::warning( 0, tr("Messages conflict"), message,
+ tr("Yes"), tr("No"), 0, 0, 1 ) ) {
+
+ case 0:
+ {
+ if ( !writeMailWidget()->saveChangesOnRequest() ) {
+ QMessageBox::warning(0,
+ tr("Autosave failed"),
+ tr("<qt>Autosave failed:<br>%1</qt>").arg(msg2));
+ return true;
+ }
+ break;
+ }
+ case 1: break;
+ }
+ }
+ return false;
+}
+
+void EmailClient::replyClicked()
+{
+ QMailMessageId currentId = readMailWidget()->displayedMessage();
+ if(currentId.isValid())
+ respond(QMailMessage(currentId),QMailMessage::Reply);
+}
+
+void EmailClient::replyAllClicked()
+{
+ QMailMessageId currentId = readMailWidget()->displayedMessage();
+ if(currentId.isValid())
+ respond(QMailMessage(currentId),QMailMessage::ReplyToAll);
+}
+
+void EmailClient::forwardClicked()
+{
+ QMailMessageId currentId = readMailWidget()->displayedMessage();
+ if(currentId.isValid())
+ respond(QMailMessage(currentId),QMailMessage::Forward);
+}
+
+void EmailClient::respond(const QMailMessage& message, QMailMessage::ResponseType type)
+{
+ if ((type == QMailMessage::NoResponse) ||
+ (type == QMailMessage::ForwardPart)) {
+ qWarning() << "Invalid responseType:" << type;
+ return;
+ }
+
+ repliedFromMailId = message.id();
+
+ if (type == QMailMessage::Reply) {
+ repliedFlags = QMailMessage::Replied;
+ } else if (type == QMailMessage::ReplyToAll) {
+ repliedFlags = QMailMessage::RepliedAll;
+ } else if (type == QMailMessage::Forward) {
+ repliedFlags = QMailMessage::Forwarded;
+ }
+
+ writeMailWidget()->respond(message, type);
+ if (!writeMailWidget()->composer().isEmpty()) {
+ viewComposer();
+ }
+}
+
+void EmailClient::respond(const QMailMessagePart::Location& partLocation, QMailMessage::ResponseType type)
+{
+ if (type != QMailMessage::ForwardPart) {
+ qWarning() << "Invalid responseType:" << type;
+ return;
+ }
+
+ repliedFromMailId = partLocation.containingMessageId();
+ repliedFlags = QMailMessage::Forwarded;
+
+ writeMailWidget()->respond(partLocation, type);
+ if (!writeMailWidget()->composer().isEmpty()) {
+ viewComposer();
+ }
+}
+
+void EmailClient::modify(const QMailMessage& message)
+{
+ // Is this type editable?
+ QString key(QMailComposerFactory::defaultKey(message.messageType()));
+ if (!key.isEmpty()) {
+ writeMailWidget()->modify(message);
+ if ( writeMailWidget()->composer().isEmpty() ) {
+ // failed to create new composer, maybe due to no email account
+ // being present.
+ return;
+ }
+ viewComposer();
+ } else {
+ QMessageBox::warning(0,
+ tr("Error"),
+ tr("Cannot edit a message of this type."),
+ tr("OK"));
+ }
+}
+
+void EmailClient::retrieveMoreMessages()
+{
+ if (isRetrieving()) {
+ qWarning() << "retrieveMoreMessages called while retrieval in progress";
+ return;
+ }
+ mailAccountId = QMailAccountId();
+
+ QMailFolderId folderId(messageListView()->folderId());
+ if (folderId.isValid()) {
+ QMailFolder folder(folderId);
+
+ // Find how many messages we have requested for this folder
+ QMailMessageKey countKey(QMailDisconnected::sourceKey(folderId));
+ countKey &= ~QMailSearchAction::temporaryKey();
+ int retrievedMinimum = QMailStore::instance()->countMessages(countKey);
+
+ // Request more messages
+ retrievedMinimum += QMailRetrievalAction::defaultMinimum();
+
+ setRetrievalInProgress(true);
+ retrieveAction("Retrieving message list for folder")->retrieveMessageList(folder.parentAccountId(), folderId, retrievedMinimum);
+ }
+}
+
+void EmailClient::retrieveVisibleMessagesFlags()
+{
+ if (workOfflineAction->isChecked())
+ return;
+
+ // This code to detect flag changes is required to address a limitation
+ // of IMAP servers that do not support NOTIFY+CONDSTORE functionality.
+ QMailMessageIdList ids(messageListView()->visibleMessagesIds());
+ if (ids.isEmpty())
+ return;
+
+ // Ensure that we only ask for flag updates for messages that are retrievable
+ QMailMessageKey idKey(QMailMessageKey::id(ids));
+ QMailMessageKey retrieveKey(QMailMessageKey::parentAccountId(QMailAccountKey::status(QMailAccount::CanRetrieve, QMailDataComparator::Includes)));
+ QMailMessageKey enabledKey(QMailMessageKey::parentAccountId(QMailAccountKey::status(QMailAccount::Enabled, QMailDataComparator::Includes)));
+
+ ids = QMailStore::instance()->queryMessages(idKey & retrieveKey & enabledKey);
+ if (ids.isEmpty())
+ return;
+
+ if (m_flagRetrievalAction->isRunning()) {
+ // There is a flag retrieval already ocurring; save these IDs to be checked afterwards
+ flagMessageIds += ids.toSet();
+ } else {
+ m_flagRetrievalAction->retrieveMessages(ids, QMailRetrievalAction::Flags);
+ }
+}
+
+void EmailClient::composeActivated()
+{
+ delayedInit();
+ if (writeMailWidget()->prepareComposer(QMailMessage::Email))
+ viewComposer();
+}
+
+void EmailClient::sendMessageTo(const QMailAddress &address, QMailMessage::MessageType type)
+{
+ if (type == QMailMessage::AnyType)
+ type = QMailMessage::Email;
+
+ // Some address types imply message types
+ if (address.isEmailAddress() && ((type != QMailMessage::Email) && (type != QMailMessage::Mms))) {
+ type = QMailMessage::Email;
+ }
+
+ if (writeMailWidget()->prepareComposer(type)) {
+ QMailMessage newMessage;
+ newMessage.setTo(QMailAddressList() << address);
+ newMessage.setMessageType(type);
+ writeMailWidget()->create(newMessage);
+ viewComposer();
+ }
+}
+
+void EmailClient::quit()
+{
+ if (writeMailWidget()->hasContent()) {
+
+ // We need to save whatever is currently being worked on
+ writeMailWidget()->forcedClosure();
+
+ if (lastDraftId.isValid()) {
+ // Store this value to remind the user on next startup
+ QSettings mailconf("QtProject", "qtmail");
+ mailconf.beginGroup("restart");
+ mailconf.setValue("lastDraftId", lastDraftId.toULongLong() );
+ mailconf.endGroup();
+ }
+ }
+
+#if defined(SERVER_AS_DLL)
+ if (m_messageServerThread) {
+ m_messageServerThread->quit();
+ QTimer::singleShot(0,qApp,SLOT(quit()));
+ }
+#else
+ if(m_messageServerProcess)
+ {
+ //we started the messageserver, direct it to shut down
+ //before we quit ourselves
+ QMailMessageServer server;
+ server.shutdown();
+ QTimer::singleShot(0,qApp,SLOT(quit()));
+ }
+#endif
+ else QApplication::quit();
+}
+
+void EmailClient::closeEvent(QCloseEvent *e)
+{
+ if (closeImmediately())
+ quit();
+ e->ignore();
+}
+
+void EmailClient::setupUi()
+{
+ QWidget* f = new QWidget(this);
+ setCentralWidget(f);
+ QVBoxLayout* vb = new QVBoxLayout(f);
+ vb->setContentsMargins( 0, 0, 0, 0 );
+ vb->setSpacing( 0 );
+
+ QSplitter* horizontalSplitter = new QSplitter(this);
+ horizontalSplitter->setOrientation(Qt::Vertical);
+
+ QWidget* messageList = new QWidget(this);
+ QVBoxLayout* messageListLayout = new QVBoxLayout(messageList);
+ messageListLayout->setSpacing(0);
+ messageListLayout->setContentsMargins(0,0,0,0);
+
+ horizontalSplitter->addWidget(messageListView());
+ horizontalSplitter->addWidget(readMailWidget());
+
+ QSplitter* verticalSplitter = new QSplitter(this);
+ verticalSplitter->addWidget(folderView());
+ verticalSplitter->addWidget(horizontalSplitter);
+
+ vb->addWidget( verticalSplitter );
+
+ setGeometry(0,0,defaultWidth,defaultHeight);
+ int thirdHeight = height() /3;
+ horizontalSplitter->setSizes(QList<int>() << thirdHeight << (height()- thirdHeight));
+ int quarterWidth = width() /4;
+ verticalSplitter->setSizes(QList<int>() << quarterWidth << (width()- quarterWidth));
+
+ //detailed progress widget
+
+ m_statusMonitorWidget = new StatusMonitorWidget(this, StatusBarHeight,0);
+ m_statusMonitorWidget->hide();
+
+ //status bar
+
+ setStatusBar(new QStatusBar(this));
+ statusBar()->setMaximumHeight(StatusBarHeight);
+ statusBar()->setStyleSheet("QStatusBar::item { border: 0px;}");
+ StatusBar* m_statusBar = new StatusBar(this);
+ statusBar()->addPermanentWidget(m_statusBar,100);
+
+ connect(m_statusBar,SIGNAL(showDetails()),
+ m_statusMonitorWidget,SLOT(show()));
+ connect(m_statusBar,SIGNAL(hideDetails()),
+ m_statusMonitorWidget,SLOT(hide()));
+
+ connect(this, SIGNAL(updateStatus(QString)),
+ m_statusBar,SLOT(setStatus(QString)) );
+
+ connect(StatusMonitor::instance(),SIGNAL(statusChanged(QString)),
+ m_statusBar,SLOT(setStatus(QString)));
+
+// connect(this, SIGNAL(updateProgress(uint,uint)),
+// m_statusBar, SLOT(setProgress(uint,uint)) );
+ connect(StatusMonitor::instance(),SIGNAL(progressChanged(uint,uint)),
+ m_statusBar,SLOT(setProgress(uint,uint)));
+
+ connect(this, SIGNAL(clearStatus()),
+ m_statusBar, SLOT(clearStatus()));
+
+ connect(this, SIGNAL(clearProgress()),
+ m_statusBar, SLOT(clearProgress()));
+
+
+ //main menu
+
+ QMenuBar* mainMenuBar = new QMenuBar(this);
+ QMenu* file = mainMenuBar->addMenu("File");
+ QMenu* help = mainMenuBar->addMenu("Help");
+ QAction* aboutQt = help->addAction("About Qt");
+ aboutQt->setMenuRole(QAction::AboutQtRole);
+ connect(aboutQt,SIGNAL(triggered()),qApp,SLOT(aboutQt()));
+ QWidget* menuWidget = new QWidget(this);
+ QHBoxLayout* menuLayout = new QHBoxLayout(menuWidget);
+ menuLayout->setSpacing(0);
+ menuLayout->setContentsMargins(0,0,5,0);
+#ifdef Q_OS_MAC
+ menuLayout->addStretch();
+#else
+ menuLayout->addWidget(mainMenuBar);
+#endif
+
+ //spinner icon
+
+ QLabel* statusIcon = new ActivityIcon(this);
+ menuLayout->addWidget(statusIcon);
+ setMenuWidget(menuWidget);
+ m_contextMenu = file;
+
+ //toolbar
+
+ m_toolBar = new QToolBar(this);
+ addToolBar(m_toolBar);
+}
+
+void EmailClient::showEvent(QShowEvent* e)
+{
+ Q_UNUSED(e);
+
+ suspendMailCount = false;
+
+ QTimer::singleShot(0, this, SLOT(delayedInit()) );
+}
+
+void EmailClient::setSendingInProgress(bool set)
+{
+ readMailWidget()->setSendingInProgress(set);
+
+ if (set) {
+ if (!isRetrieving())
+ primaryActivity = Sending;
+ } else {
+ if (primaryActivity == Sending)
+ primaryActivity = Inactive;
+ }
+
+ if (isSending() != set) {
+ int newStatus = (set ? transferStatus | Sending : transferStatus & ~Sending);
+ transferStatusUpdate(newStatus);
+ }
+}
+
+void EmailClient::setRetrievalInProgress(bool set)
+{
+ readMailWidget()->setRetrievalInProgress(set);
+
+ if (set) {
+ if (!isSending())
+ primaryActivity = Retrieving;
+ } else {
+ if (primaryActivity == Retrieving)
+ primaryActivity = Inactive;
+ }
+
+ if (isRetrieving() != set) {
+ int newStatus = (set ? transferStatus | Retrieving : transferStatus & ~Retrieving);
+ transferStatusUpdate(newStatus);
+ }
+}
+
+void EmailClient::transferStatusUpdate(int status)
+{
+ if (status != transferStatus) {
+ transferStatus = status;
+
+ if (transferStatus == Inactive) {
+ if (closeAfterTransmissions)
+ close();
+ }
+
+ // UI updates
+ setActionVisible(cancelButton, transferStatus != Inactive);
+ updateGetMailButton();
+ updateActions();
+ }
+}
+
+
+void EmailClient::contextStatusUpdate()
+{
+ if (isTransmitting())
+ return;
+
+ MessageUiBase::contextStatusUpdate();
+}
+
+void EmailClient::settings()
+{
+ clearStatusText();
+ contextStatusUpdate();
+
+ AccountSettings settingsDialog(this);
+ settingsDialog.exec();
+}
+
+void EmailClient::createStandardFolders()
+{
+ QMailAccountKey retrieveKey(QMailAccountKey::status(QMailAccount::CanRetrieve, QMailDataComparator::Includes));
+ QMailAccountKey enabledKey(QMailAccountKey::status(QMailAccount::Enabled, QMailDataComparator::Includes));
+ availableAccounts = QMailStore::instance()->queryAccounts(retrieveKey & enabledKey);
+
+ if (!availableAccounts.isEmpty()) {
+ foreach(QMailAccountId accountId, availableAccounts)
+ retrieveAction("createStandardfolders")->createStandardFolders(accountId);
+ }
+}
+
+void EmailClient::notificationStateChanged()
+{
+#ifndef QT_NO_SYSTEMTRAYICON
+ if (!NotificationTray::isSystemTrayAvailable()) {
+ QMessageBox::warning(this, tr("Unable to enable notification"), tr("System tray was undetected"));
+ notificationAction->setChecked(false);
+ return;
+ }
+
+ if (!NotificationTray::supportsMessages()) {
+ QMessageBox::warning(this, tr("Unable to enable notification"), tr("System tray doesn't support messages"));
+ notificationAction->setChecked(false);
+ return;
+ }
+
+ static QScopedPointer<NotificationTray> tray(new NotificationTray());
+
+ if (notificationAction->isChecked())
+ tray->show();
+ else
+ tray->hide();
+#endif // QT_NO_SYSTEMTRAYICON
+}
+
+void EmailClient::connectionStateChanged()
+{
+ if (workOfflineAction->isChecked())
+ return;
+
+ exportPendingChanges();
+ sendAllQueuedMail();
+}
+
+void EmailClient::exportPendingChanges()
+{
+ if (workOfflineAction->isChecked())
+ return;
+
+ foreach(QMailAccountId accountId, emailAccounts()) {
+ exportPendingChanges(accountId);
+ }
+
+ if (!m_exportAction) {
+ m_exportAction = new QMailRetrievalAction(this);
+ connectServiceAction(m_exportAction);
+ }
+
+ runNextPendingExport();
+}
+
+void EmailClient::exportPendingChanges(const QMailAccountId &accountId)
+{
+ if (workOfflineAction->isChecked())
+ return;
+
+ if (!m_queuedExports.contains(accountId)) {
+ m_queuedExports.append(accountId);
+ }
+}
+
+void EmailClient::runNextPendingExport()
+{
+ if (m_queuedExports.isEmpty()) {
+ m_exportAction->deleteLater();
+ m_exportAction = 0;
+ return;
+ }
+
+ if (!m_exportAction->isRunning()) {
+ QMailAccountId mailAccountId = m_queuedExports.first();
+
+ ServiceActionStatusItem* newItem = new ServiceActionStatusItem(m_exportAction, "Exporting pending updates");
+ StatusMonitor::instance()->add(newItem);
+ m_exportAction->exportUpdates(mailAccountId);
+ return;
+ }
+}
+
+void EmailClient::accountsAdded(const QMailAccountIdList&)
+{
+ updateGetAccountButton();
+ updateAccounts();
+}
+
+void EmailClient::accountsRemoved(const QMailAccountIdList&)
+{
+ updateGetAccountButton();
+ updateAccounts();
+}
+
+void EmailClient::accountsUpdated(const QMailAccountIdList&)
+{
+ updateGetAccountButton();
+ updateAccounts();
+}
+
+void EmailClient::messagesUpdated(const QMailMessageIdList& ids)
+{
+ if (isRetrieving()) {
+ if (ids.contains(readMailWidget()->displayedMessage())) {
+ QMailMessageMetaData updatedMessage(readMailWidget()->displayedMessage());
+ if (updatedMessage.status() & QMailMessage::Removed) {
+ // This message has been removed
+ QMessageBox::warning(0,
+ tr("Message deleted"),
+ tr("Message cannot be downloaded, because it has been deleted from the server."),
+ QMessageBox::Ok);
+ }
+ }
+ }
+}
+
+void EmailClient::messageSelectionChanged()
+{
+ if (!moveAction)
+ return; // initActions hasn't been called yet
+
+ MessageUiBase::messageSelectionChanged();
+
+ const bool messagesSelected(selectionCount != 0);
+
+ // We can delete only if all selected messages are in the Trash folder
+ QMailMessageKey selectedFilter(QMailMessageKey::id(messageListView()->selected()));
+ QMailMessageKey trashFilter(QMailMessageKey::status(QMailMessage::Trash));
+
+ const int trashCount(QMailStore::instance()->countMessages(selectedFilter & trashFilter));
+ const bool deleting(trashCount == selectionCount);
+
+ int count = messageListView()->rowCount();
+ if ((count > 0) && (selectionCount > 0)) {
+ if (deleting) {
+ deleteMailAction->setText(tr("Delete message(s)", "", selectionCount));
+ } else {
+ deleteMailAction->setText(tr("Move to Trash"));
+ }
+ moveAction->setText(tr("Move message(s)...", "", selectionCount));
+ copyAction->setText(tr("Copy message(s)...", "", selectionCount));
+ restoreAction->setText(tr("Restore message(s)", "", selectionCount));
+ }
+
+ // Ensure that the per-message actions are hidden, if not usable
+ setActionVisible(deleteMailAction, messagesSelected);
+
+ // We cannot move/copy messages in the trash
+ setActionVisible(moveAction, (messagesSelected && !(trashCount > 0)));
+ setActionVisible(copyAction, (messagesSelected && !(trashCount > 0)));
+ setActionVisible(restoreAction, (messagesSelected && (trashCount > 0)));
+
+ if(messageListView()->current().isValid())
+ {
+ QMailMessage mail(messageListView()->current());
+ bool incoming(mail.status() & QMailMessage::Incoming);
+ bool downloaded(mail.status() & QMailMessage::ContentAvailable);
+ bool system(mail.messageType() == QMailMessage::System);
+
+ if (!downloaded || system) {
+ // We can't really forward/reply/reply-to-all without the message content
+ setActionVisible(replyAction,false);
+ setActionVisible(replyAllAction,false);
+ setActionVisible(forwardAction,false);
+ } else {
+ bool otherReplyTarget(!mail.cc().isEmpty() || mail.to().count() > 1);
+ setActionVisible(replyAction,incoming);
+ setActionVisible(replyAllAction,incoming & otherReplyTarget);
+ setActionVisible(forwardAction,true);
+ }
+ }
+
+ // We can detach only if a single non-root message is selected
+ setActionVisible(detachThreadAction, ((selectionCount == 1) && messageListView()->hasParent()));
+
+ updateActions();
+}
+
+void EmailClient::noSendAccount(QMailMessage::MessageType type)
+{
+ QString key(QMailComposerFactory::defaultKey(type));
+ QString name(QMailComposerFactory::name(key, type));
+
+ QMessageBox::warning(0,
+ tr("Send Error"),
+ tr("%1 cannot be sent, because no account has been configured to send with.","%1=MMS/Email/TextMessage").arg(name),
+ QMessageBox::Ok);
+}
+
+void EmailClient::setActionVisible(QAction* action, bool visible)
+{
+ if (action)
+ actionVisibility[action] = visible;
+}
+
+QMailFolderId EmailClient::containingFolder(const QMailMessageId& id)
+{
+ QMailMessageMetaData metaData(id);
+ return metaData.parentFolderId();
+}
+
+QMailAccountIdList EmailClient::emailAccounts() const
+{
+ QMailAccountKey typeKey(QMailAccountKey::messageType(QMailMessage::Email));
+ QMailAccountKey enabledKey(QMailAccountKey::status(QMailAccount::Enabled, QMailDataComparator::Includes));
+ return QMailStore::instance()->queryAccounts(typeKey & enabledKey);
+}
+
+void EmailClient::clearNewMessageStatus(const QMailMessageKey& key)
+{
+ QMailMessageKey clearNewKey = key & QMailMessageKey::status(QMailMessage::New, QMailDataComparator::Includes);
+
+ int count = QMailStore::instance()->countMessages(clearNewKey);
+ if (count) {
+ QMailStore::instance()->updateMessagesMetaData(clearNewKey, QMailMessage::New, false);
+ }
+}
+
+QAction* EmailClient::createSeparator()
+{
+ QAction* sep = new QAction(this);
+ sep->setSeparator(true);
+ return sep;
+}
+
+QMailStorageAction* EmailClient::storageAction(const QString& description)
+{
+ QMailStorageAction* storageAction = new QMailStorageAction(this);
+ connectServiceAction(storageAction);
+
+ ServiceActionStatusItem* newItem = new ServiceActionStatusItem(storageAction,description);
+ StatusMonitor::instance()->add(newItem);
+ return storageAction;
+}
+
+QMailRetrievalAction* EmailClient::retrieveAction(const QString& description)
+{
+ if(!m_retrievalAction)
+ {
+ m_retrievalAction = new QMailRetrievalAction(this);
+ connectServiceAction(m_retrievalAction);
+ }
+ ServiceActionStatusItem* newItem = new ServiceActionStatusItem(m_retrievalAction,description);
+ StatusMonitor::instance()->add(newItem);
+ return m_retrievalAction;
+}
+
+QMailTransmitAction* EmailClient::transmitAction(const QString& description)
+{
+ if(!m_transmitAction)
+ {
+ m_transmitAction = new QMailTransmitAction(this);
+ connectServiceAction(m_transmitAction);
+ connect(m_transmitAction, SIGNAL(messagesFailedTransmission(QMailMessageIdList, QMailServiceAction::Status::ErrorCode)),
+ this, SLOT(messagesFailedTransmission()));
+ }
+
+ ServiceActionStatusItem* newItem = new ServiceActionStatusItem(m_transmitAction,description);
+ StatusMonitor::instance()->add(newItem);
+ return m_transmitAction;
+}
+
+void EmailClient::setMarkingMode(bool set)
+{
+ MessageUiBase::setMarkingMode(set);
+
+ if (markingMode) {
+ markAction->setText(tr("Cancel"));
+ } else {
+ markAction->setText(tr("Mark messages"));
+ }
+}
+
+void EmailClient::markMessages()
+{
+ setMarkingMode(!markingMode);
+}
+
+void EmailClient::setThreaded(bool set)
+{
+ MessageUiBase::setThreaded(set);
+
+ if (threaded) {
+ threadAction->setText(tr("Unthread messages"));
+ } else {
+ threadAction->setText(tr("Thread messages"));
+ }
+}
+
+void EmailClient::threadMessages()
+{
+ setThreaded(!threaded);
+}
+
+void EmailClient::synchronizeFolder()
+{
+ if (selectedFolderId.isValid()) {
+ QMailFolder folder(selectedFolderId);
+ bool excludeFolder = (folder.status() & QMailFolder::SynchronizationEnabled);
+
+ if (QMailStore *store = QMailStore::instance()) {
+ // Find any subfolders of this folder
+ QMailFolderKey subfolderKey(QMailFolderKey::ancestorFolderIds(selectedFolderId, QMailDataComparator::Includes));
+ QMailFolderIdList folderIds = QMailStore::instance()->queryFolders(subfolderKey);
+
+ // Mark all of these folders as {un}synchronized
+ folderIds.append(selectedFolderId);
+ foreach (const QMailFolderId &id, folderIds) {
+ QMailFolder folder(id);
+ folder.setStatus(QMailFolder::SynchronizationEnabled, !excludeFolder);
+ store->updateFolder(&folder);
+ }
+ }
+
+ // Update the action to reflect the change
+ folderSelected(folderView()->currentItem());
+ }
+}
+
+void EmailClient::nextMessage()
+{
+ QWidget *list = messageListView()->findChild<QWidget*>("messagelistview");
+ if (list) {
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Down, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, 0));
+ }
+}
+
+void EmailClient::previousMessage()
+{
+ QWidget *list = messageListView()->findChild<QWidget*>("messagelistview");
+ if (list) {
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Up, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, 0));
+ }
+}
+
+void EmailClient::nextUnreadMessage()
+{
+ QWidget *list = messageListView()->findChild<QWidget*>("messagelistview");
+ if (list) {
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Plus, 0, "+"));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Plus, 0, "+"));
+ }
+}
+
+void EmailClient::previousUnreadMessage()
+{
+ QWidget *list = messageListView()->findChild<QWidget*>("messagelistview");
+ if (list) {
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Minus, 0, "-"));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Minus, 0, "-"));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0));
+ QApplication::postEvent(list, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Enter, 0));
+ }
+}
+
+void EmailClient::scrollReaderDown()
+{
+ QWidget *renderer = readMailWidget()->findChild<QWidget*>("renderer");
+
+ if (renderer) {
+ QApplication::postEvent(renderer, new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, 0));
+ QApplication::postEvent(renderer, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Down, 0));
+ }
+}
+
+void EmailClient::scrollReaderUp()
+{
+ QWidget *renderer = readMailWidget()->findChild<QWidget*>("renderer");
+ if (renderer) {
+ QApplication::postEvent(renderer, new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, 0));
+ QApplication::postEvent(renderer, new QKeyEvent(QEvent::KeyRelease, Qt::Key_Up, 0));
+ }
+}
+
+void EmailClient::readerMarkMessageAsUnread()
+{
+ quint64 setMask(0);
+ quint64 unsetMask(QMailMessage::Read);
+ QMailMessageId id(readMailWidget()->displayedMessage());
+ flagMessage(id, setMask, unsetMask);
+}
+
+void EmailClient::readerMarkMessageAsImportant()
+{
+ quint64 setMask(QMailMessage::Important);
+ quint64 unsetMask(0);
+ QMailMessageId id(readMailWidget()->displayedMessage());
+ flagMessage(id, setMask, unsetMask);
+}
+
+void EmailClient::readerMarkMessageAsNotImportant()
+{
+ quint64 setMask(0);
+ quint64 unsetMask(QMailMessage::Important);
+ QMailMessageId id(readMailWidget()->displayedMessage());
+ flagMessage(id, setMask, unsetMask);
+}
+
+#ifndef QT_NO_SYSTEMTRAYICON
+NotificationTray::NotificationTray(QObject *parent)
+ : QSystemTrayIcon(QIcon(":icon/qtmail"), parent)
+{
+ connect(QMailStore::instance(), SIGNAL(messagesAdded(QMailMessageIdList)), this, SLOT(messagesAdded(QMailMessageIdList)));
+}
+
+void NotificationTray::messagesAdded(const QMailMessageIdList &ids)
+{
+ Q_ASSERT(ids.size());
+ Q_ASSERT(!ids.contains(QMailMessageId()));
+ Q_ASSERT(QSystemTrayIcon::supportsMessages());
+
+ if (isVisible()) {
+ if (ids.size() == 1) {
+ QMailMessage msg(ids.first());
+ showMessage(tr("New message from: %1").arg(msg.from().toString()), msg.subject());
+ } else {
+ Q_ASSERT(ids.size() > 1);
+ showMessage(tr("New messages"), tr("Received %1 new messages").arg(ids.size()));
+ }
+ }
+}
+#endif // QT_NO_SYSTEMTRAYICON
+
+#if defined(SERVER_AS_DLL)
+MessageServerThread::MessageServerThread()
+{
+}
+
+MessageServerThread::~MessageServerThread()
+{
+ // Tell the thread's event loop to exit
+ // => thread returns from the call to exec()
+ exit();
+
+ // Wait until this thread has finished execution
+ // <=> waits until thread returns from run()
+ wait();
+}
+
+void MessageServerThread::run()
+{
+ // Start messageserver
+ MessageServer server;
+
+ emit messageServerStarted();
+
+ // Enter the thread event loop
+ (void) exec();
+}
+#endif
+
+#include <emailclient.moc>
+