Commit 0d0c6814 authored by Karan Luthra's avatar Karan Luthra
Browse files

Support for forwarding messages as attachments

Allow forwarding of a message as an attachment by means of menu actions.
Forwarding takes care of mangling the subject line and marking the
original message as "$Forwarded".

Thanks to paalsteek for his initial work on this.

BUG: 321378
REVIEW: 118606
parent fcfa205b
......@@ -810,4 +810,31 @@ QModelIndex MessageComposer::replyingToMessage() const
return m_replyingTo;
}
QModelIndex MessageComposer::forwardingMessage() const
{
return m_forwarding;
}
void MessageComposer::prepareForwarding(const QModelIndex &index, const ForwardMode mode)
{
m_forwarding = index;
switch (mode) {
case Composer::ForwardMode::FORWARD_AS_ATTACHMENT:
{
beginInsertRows(QModelIndex(), m_attachments.size(), m_attachments.size());
QString mailbox = m_forwarding.data(Imap::Mailbox::RoleMailboxName).toString();
uint uidValidity = m_forwarding.data(Imap::Mailbox::RoleMailboxUidValidity).toUInt();
uint uid = m_forwarding.data(Imap::Mailbox::RoleMessageUid).toUInt();
QScopedPointer<AttachmentItem> attachment(new ImapMessageAttachmentItem(m_model, mailbox, uidValidity, uid));
if (m_shouldPreload) {
attachment->preload();
}
attachment->setContentDispositionMode(CDN_INLINE);
m_attachments << attachment.take();
endInsertRows();
break;
}
}
}
}
......@@ -67,6 +67,7 @@ public:
void setOrganization(const QString &organization);
void setText(const QString &text);
void setReplyingToMessage(const QModelIndex &index);
void prepareForwarding(const QModelIndex &index, const ForwardMode mode);
bool isReadyForSerialization() const;
bool asRawMessage(QIODevice *target, QString *errorMessage) const;
......@@ -78,6 +79,7 @@ public:
QByteArray rawFromAddress() const;
QList<QByteArray> rawRecipientAddresses() const;
QModelIndex replyingToMessage() const;
QModelIndex forwardingMessage() const;
bool addFileAttachment(const QString &path);
void removeAttachment(const QModelIndex &index);
......@@ -112,6 +114,7 @@ private:
QString m_organization;
QString m_text;
QPersistentModelIndex m_replyingTo;
QPersistentModelIndex m_forwarding;
QList<AttachmentItem *> m_attachments;
QPointer<Imap::Mailbox::Model> m_model;
......
......@@ -36,6 +36,10 @@ typedef enum {
REPLY_LIST /**< @short Reply to the mailing list */
} ReplyMode;
enum class ForwardMode {
FORWARD_AS_ATTACHMENT, /**< @short Forward the message as an attachment */
};
/** @short Recipients */
typedef enum {
ADDRESS_TO,
......
......@@ -71,6 +71,13 @@ QString replySubject(const QString &subject)
}
}
/** @short Prepare a subject to be used in a message to be forwarded */
QString forwardSubject(const QString &subject)
{
QLatin1String forwardPrefix("Fwd: ");
return forwardPrefix + subject;
}
}
}
......
......@@ -29,6 +29,7 @@ namespace Composer {
namespace Util {
QString replySubject(const QString &subject);
QString forwardSubject(const QString &subject);
}
}
......
......@@ -74,7 +74,8 @@ Submission::Submission(QObject *parent, Imap::Mailbox::Model *model, MSA::MSAFac
m_appendUidReceived(false), m_appendUidValidity(0), m_appendUid(0), m_genUrlAuthReceived(false),
m_saveToSentFolder(false), m_useBurl(false), m_useImapSubmit(false), m_state(STATE_INIT),
m_msaMaximalProgress(0),
m_composer(0), m_model(model), m_msaFactory(msaFactory), m_updateReplyingToMessageFlagsTask(0)
m_composer(0), m_model(model), m_msaFactory(msaFactory), m_updateReplyingToMessageFlagsTask(0),
m_updateForwardingMessageFlagsTask(0)
{
m_composer = new Composer::MessageComposer(model, this);
m_composer->setPreloadEnabled(shouldBuildMessageLocally());
......@@ -312,6 +313,14 @@ void Submission::sent()
connect(m_updateReplyingToMessageFlagsTask, SIGNAL(failed(QString)),
this, SLOT(onUpdatingFlagsOfReplyingToFailed()));
changeConnectionState(STATE_UPDATING_FLAGS);
} else if (m_composer->forwardingMessage().isValid()) {
m_updateForwardingMessageFlagsTask = m_model->setMessageFlags(QModelIndexList() << m_composer->forwardingMessage(),
QLatin1String("$Forwarded"), Imap::Mailbox::FLAG_ADD);
connect(m_updateForwardingMessageFlagsTask, SIGNAL(completed(Imap::Mailbox::ImapTask*)),
this, SLOT(onUpdatingFlagsOfForwardingSucceeded()));
connect(m_updateForwardingMessageFlagsTask, SIGNAL(failed(QString)),
this, SLOT(onUpdatingFlagsOfForwardingFailed()));
changeConnectionState(STATE_UPDATING_FLAGS);
} else {
changeConnectionState(STATE_SENT);
emit succeeded();
......@@ -409,6 +418,22 @@ void Submission::onUpdatingFlagsOfReplyingToFailed()
emit succeeded();
}
void Submission::onUpdatingFlagsOfForwardingSucceeded()
{
m_updateForwardingMessageFlagsTask = 0;
changeConnectionState(STATE_SENT);
emit succeeded();
}
void Submission::onUpdatingFlagsOfForwardingFailed()
{
m_updateForwardingMessageFlagsTask = 0;
m_model->logTrace(0, Common::LOG_OTHER, QLatin1String("Submission"),
QLatin1String("Cannot update flags of the message we forwarded -- interesting, but we cannot do anything at this point anyway"));
changeConnectionState(STATE_SENT);
emit succeeded();
}
void Submission::onMsaProgressCurrentChanged(const int value)
{
if (m_msaMaximalProgress > 0) {
......
......@@ -88,6 +88,8 @@ private slots:
void slotAppendFailed(const QString &error);
void onUpdatingFlagsOfReplyingToSucceded();
void onUpdatingFlagsOfReplyingToFailed();
void onUpdatingFlagsOfForwardingSucceeded();
void onUpdatingFlagsOfForwardingFailed();
void slotMessageDataAvailable();
void slotAskForUrl();
......@@ -136,6 +138,7 @@ private:
MSA::MSAFactory *m_msaFactory;
Imap::Mailbox::ImapTask *m_updateReplyingToMessageFlagsTask;
Imap::Mailbox::ImapTask *m_updateForwardingMessageFlagsTask;
Submission(const Submission &); // don't implement
Submission &operator=(const Submission &); // don't implement
......
......@@ -364,6 +364,30 @@ ComposeWidget *ComposeWidget::createReply(MainWindow *mainWindow, const Composer
return w;
}
/** @short Create a composer window for a mail-forward action */
ComposeWidget *ComposeWidget::createForward(MainWindow *mainWindow, const Composer::ForwardMode mode, const QModelIndex &forwardingMessage,
const QString &subject, const QList<QByteArray> &inReplyTo, const QList<QByteArray> &references)
{
MSA::MSAFactory *msaFactory = mainWindow->msaFactory();
if (!msaFactory)
return 0;
ComposeWidget *w = new ComposeWidget(mainWindow, msaFactory);
w->setResponseData(QList<QPair<Composer::RecipientKind, QString>>(), subject, QString(), inReplyTo, references, QModelIndex());
// We don't need to expose any UI here, but we want the in-reply-to and references information to be carried with this message
w->m_actionInReplyTo->setChecked(true);
// Only those changes that are made to the composer's fields *after* it has been created should qualify as "edits"
w->m_messageEverEdited = false;
// Prepare the message to be forwarded and add it to the attachments view
w->m_submission->composer()->prepareForwarding(forwardingMessage, mode);
Util::centerWidgetOnScreen(w);
w->show();
return w;
}
void ComposeWidget::updateReplyMode()
{
if (m_actionHandPickedRecipients->isChecked())
......
......@@ -75,6 +75,8 @@ public:
static ComposeWidget *createReply(MainWindow *mainWindow, const Composer::ReplyMode &mode, const QModelIndex &replyingToMessage,
const QList<QPair<Composer::RecipientKind, QString> > &recipients, const QString &subject,
const QString &body, const QList<QByteArray> &inReplyTo, const QList<QByteArray> &references);
static ComposeWidget *createForward(MainWindow *mainWindow, const Composer::ForwardMode mode, const QModelIndex &forwardingMessage,
const QString &subject, const QList<QByteArray> &inReplyTo, const QList<QByteArray> &references);
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *ce);
......
......@@ -354,6 +354,24 @@ void MessageView::reply(MainWindow *mainWindow, Composer::ReplyMode mode)
mainWindow);
}
void MessageView::forward(MainWindow *mainWindow, const Composer::ForwardMode mode)
{
if (!message.isValid())
return;
// The Message-Id of the original message might have been empty; be sure we can handle that
QByteArray messageId = message.data(Imap::Mailbox::RoleMessageMessageId).toByteArray();
QList<QByteArray> messageIdList;
if (!messageId.isEmpty()) {
messageIdList.append(messageId);
}
ComposeWidget::warnIfMsaNotConfigured(
ComposeWidget::createForward(mainWindow, mode, message, Composer::Util::forwardSubject(message.data(Imap::Mailbox::RoleMessageSubject).toString()),
messageIdList, message.data(Imap::Mailbox::RoleMessageHeaderReferences).value<QList<QByteArray>>() + messageIdList),
mainWindow);
}
void MessageView::externalsRequested(const QUrl &url)
{
Q_UNUSED(url);
......
......@@ -72,6 +72,7 @@ public:
void setNetworkWatcher(Imap::Mailbox::NetworkWatcher *netWatcher);
void reply(MainWindow *mainWindow, Composer::ReplyMode mode);
void forward(MainWindow *mainWindow, const Composer::ForwardMode mode);
QModelIndex currentMessage() const;
public slots:
void setMessage(const QModelIndex &index);
......
......@@ -197,6 +197,7 @@ void MainWindow::defineActions()
shortcutHandler->defineAction(QLatin1String("action_reply_all"), QLatin1String("mail-reply-all"), tr("Reply to &All"), tr("Ctrl+Alt+Shift+R"));
shortcutHandler->defineAction(QLatin1String("action_reply_list"), QLatin1String("mail-reply-list"), tr("Reply to &Mailing List"), tr("Ctrl+L"));
shortcutHandler->defineAction(QLatin1String("action_reply_guess"), QString(), tr("Reply by &Guess"), tr("Ctrl+R"));
shortcutHandler->defineAction(QLatin1String("action_forward_attachment"), QLatin1String("mail-forward"), tr("&Forward"), tr("Ctrl+Shift+F"));
shortcutHandler->defineAction(QLatin1String("action_contact_editor"), QLatin1String("contact-unknown"), tr("Address Book..."));
shortcutHandler->defineAction(QLatin1String("action_network_offline"), QLatin1String("network-offline"), tr("&Offline"));
shortcutHandler->defineAction(QLatin1String("action_network_expensive"), QLatin1String("network-expensive"), tr("&Expensive Connection"));
......@@ -319,6 +320,7 @@ void MainWindow::createActions()
expunge = ShortcutHandler::instance()->createAction(QLatin1String("action_expunge"), this, SLOT(slotExpunge()), this);
m_forwardAsAttachment = ShortcutHandler::instance()->createAction(QLatin1String("action_forward_attachment"), this, SLOT(slotForwardAsAttachment()), this);
markAsRead = ShortcutHandler::instance()->createAction(QLatin1String("action_mark_as_read"), this);
markAsRead->setCheckable(true);
msgListWidget->tree->addAction(markAsRead);
......@@ -487,6 +489,7 @@ void MainWindow::createActions()
m_mainToolbar->addWidget(m_composeButton);
m_mainToolbar->addWidget(m_replyButton);
m_mainToolbar->addAction(m_forwardAsAttachment);
m_mainToolbar->addAction(expunge);
m_mainToolbar->addSeparator();
m_mainToolbar->addAction(markAsRead);
......@@ -522,6 +525,9 @@ void MainWindow::createMenus()
ADD_ACTION(imapMenu, m_replyAll);
ADD_ACTION(imapMenu, m_replyAllButMe);
ADD_ACTION(imapMenu, m_replyList);
imapMenu->addSeparator();
ADD_ACTION(imapMenu, m_forwardAsAttachment);
imapMenu->addSeparator();
ADD_ACTION(imapMenu, expunge);
imapMenu->addSeparator()->setText(tr("Network Access"));
QMenu *netPolicyMenu = imapMenu->addMenu(tr("&Network Access"));
......@@ -1467,6 +1473,7 @@ void MainWindow::updateActionsOnlineOffline(bool online)
m_replyAll->setEnabled(false);
m_replyAllButMe->setEnabled(false);
m_replyList->setEnabled(false);
m_forwardAsAttachment->setEnabled(false);
}
}
......@@ -1493,6 +1500,8 @@ void MainWindow::slotUpdateMessageActions()
} else {
m_replyButton->setDefaultAction(m_replyPrivate);
}
m_forwardAsAttachment->setEnabled(m_messageWidget->messageView->currentMessage().isValid());
}
void MainWindow::scrollMessageUp()
......@@ -1533,6 +1542,11 @@ void MainWindow::slotReplyGuess()
}
}
void MainWindow::slotForwardAsAttachment()
{
m_messageWidget->messageView->forward(this, Composer::ForwardMode::FORWARD_AS_ATTACHMENT);
}
void MainWindow::slotComposeMailUrl(const QUrl &url)
{
ComposeWidget::warnIfMsaNotConfigured(ComposeWidget::createFromUrl(this, url), this);
......
......@@ -144,6 +144,7 @@ private slots:
void slotReplyAll();
void slotReplyList();
void slotReplyGuess();
void slotForwardAsAttachment();
void slotUpdateMessageActions();
void handleMarkAsRead(bool);
void handleMarkAsDeleted(bool);
......@@ -281,6 +282,7 @@ private:
QAction *m_replyAll;
QAction *m_replyList;
QAction *m_replyGuess;
QAction *m_forwardAsAttachment;
QAction *expunge;
QAction *createChildMailbox;
QAction *createTopMailbox;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment