mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 10:52:52 +00:00
997 lines
41 KiB
C++
997 lines
41 KiB
C++
/* -*- mode: C++; c-file-style: "gnu" -*-
|
|
Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
|
|
Copyright (c) 2010 Leo Franchi <lfranchi@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "messagefactory.h"
|
|
|
|
#include "settings/messagecomposersettings.h"
|
|
#include "messagecomposer/utils/util.h"
|
|
|
|
#include <akonadi/item.h>
|
|
#ifndef QT_NO_CURSOR
|
|
#include <messageviewer/utils/kcursorsaver.h>
|
|
#endif
|
|
#include <kpimidentities/identitymanager.h>
|
|
#include <kpimidentities/identity.h>
|
|
|
|
#include <akonadi/kmime/messagestatus.h>
|
|
#include <kmime/kmime_dateformatter.h>
|
|
#include <KPIMUtils/Email>
|
|
#include <messagecore/misc/mailinglist.h>
|
|
#include <messagecore/helpers/messagehelpers.h>
|
|
#include <messagecore/utils/stringutil.h>
|
|
#include "helper/messagehelper.h"
|
|
#include "templateparser/templateparser.h"
|
|
#include <KLocalizedString>
|
|
#include <kcharsets.h>
|
|
#include <QTextCodec>
|
|
|
|
using namespace MessageComposer;
|
|
|
|
namespace KMime {
|
|
namespace Types {
|
|
static bool operator==( const KMime::Types::Mailbox &left, const KMime::Types::Mailbox &right )
|
|
{
|
|
return (left.addrSpec().asString() == right.addrSpec().asString());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Strips all the user's addresses from an address list. This is used
|
|
* when replying.
|
|
*/
|
|
static KMime::Types::Mailbox::List stripMyAddressesFromAddressList( const KMime::Types::Mailbox::List& list, const KPIMIdentities::IdentityManager *manager )
|
|
{
|
|
KMime::Types::Mailbox::List addresses( list );
|
|
for ( KMime::Types::Mailbox::List::Iterator it = addresses.begin(); it != addresses.end(); ) {
|
|
if ( manager->thatIsMe( MessageCore::StringUtil::mailboxListToUnicodeString( KMime::Types::Mailbox::List() << *it ) ) ) {
|
|
it = addresses.erase( it );
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
return addresses;
|
|
}
|
|
|
|
MessageFactory::MessageFactory( const KMime::Message::Ptr& origMsg, Akonadi::Item::Id id, const Akonadi::Collection& col )
|
|
: m_identityManager( 0 )
|
|
, m_origMsg( origMsg )
|
|
, m_origId( 0 )
|
|
, m_parentFolderId( 0 )
|
|
, m_collection( col )
|
|
, m_replyStrategy( MessageComposer::ReplySmart )
|
|
, m_quote( true )
|
|
, m_allowDecryption( true )
|
|
, m_id ( id )
|
|
{
|
|
|
|
}
|
|
|
|
MessageFactory::~MessageFactory()
|
|
{
|
|
}
|
|
|
|
MessageFactory::MessageReply MessageFactory::createReply()
|
|
{
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
QString mailingListStr;
|
|
QByteArray refStr, headerName;
|
|
bool replyAll = true;
|
|
KMime::Types::Mailbox::List toList;
|
|
KMime::Types::Mailbox::List replyToList;
|
|
|
|
const uint originalIdentity = identityUoid( m_origMsg );
|
|
MessageHelper::initFromMessage( msg, m_origMsg, m_identityManager, originalIdentity );
|
|
MessageCore::MailingList::name( m_origMsg, headerName, mailingListStr );
|
|
replyToList = m_origMsg->replyTo()->mailboxes();
|
|
|
|
msg->contentType()->setCharset( "utf-8" );
|
|
|
|
if ( m_origMsg->headerByType( "List-Post" ) &&
|
|
m_origMsg->headerByType( "List-Post" )->asUnicodeString().contains( QLatin1String( "mailto:" ), Qt::CaseInsensitive ) ) {
|
|
|
|
const QString listPost = m_origMsg->headerByType( "List-Post" )->asUnicodeString();
|
|
QRegExp rx( QLatin1String( "<mailto:([^@>]+)@([^>]+)>" ), Qt::CaseInsensitive );
|
|
if ( rx.indexIn( listPost, 0 ) != -1 ) // matched
|
|
m_mailingListAddresses << MessageCore::StringUtil::mailboxFromUnicodeString( rx.cap( 1 ) + QLatin1Char( '@' ) + rx.cap( 2 ) );
|
|
}
|
|
|
|
switch ( m_replyStrategy ) {
|
|
case MessageComposer::ReplySmart:
|
|
{
|
|
if ( m_origMsg->headerByType( "Mail-Followup-To" ) ) {
|
|
toList << MessageCore::StringUtil::mailboxListFrom7BitString( m_origMsg->headerByType( "Mail-Followup-To" )->as7BitString( false ) );
|
|
} else if ( !replyToList.isEmpty() ) {
|
|
toList = replyToList;
|
|
// use the ReplyAll template only when it's a reply to a mailing list
|
|
if ( m_mailingListAddresses.isEmpty() )
|
|
replyAll = false;
|
|
} else if ( !m_mailingListAddresses.isEmpty() ) {
|
|
toList = (KMime::Types::Mailbox::List() << m_mailingListAddresses.at( 0 ));
|
|
} else {
|
|
|
|
// doesn't seem to be a mailing list, reply to From: address
|
|
toList = m_origMsg->from()->mailboxes();
|
|
|
|
if ( m_identityManager->thatIsMe( MessageCore::StringUtil::mailboxListToUnicodeString( toList ) ) ) {
|
|
// sender seems to be one of our own identities, so we assume that this
|
|
// is a reply to a "sent" mail where the users wants to add additional
|
|
// information for the recipient.
|
|
toList = m_origMsg->to()->mailboxes();
|
|
}
|
|
|
|
replyAll = false;
|
|
}
|
|
// strip all my addresses from the list of recipients
|
|
const KMime::Types::Mailbox::List recipients = toList;
|
|
|
|
toList = stripMyAddressesFromAddressList( recipients, m_identityManager );
|
|
|
|
// ... unless the list contains only my addresses (reply to self)
|
|
if ( toList.isEmpty() && !recipients.isEmpty() )
|
|
toList << recipients.first();
|
|
}
|
|
break;
|
|
case MessageComposer::ReplyList:
|
|
{
|
|
if ( m_origMsg->headerByType( "Mail-Followup-To" ) ) {
|
|
toList << MessageCore::StringUtil::mailboxFrom7BitString( m_origMsg->headerByType( "Mail-Followup-To" )->as7BitString( false ) );
|
|
} else if ( !m_mailingListAddresses.isEmpty() ) {
|
|
toList << m_mailingListAddresses[ 0 ];
|
|
} else if ( !replyToList.isEmpty() ) {
|
|
// assume a Reply-To header mangling mailing list
|
|
toList = replyToList;
|
|
}
|
|
|
|
// strip all my addresses from the list of recipients
|
|
const KMime::Types::Mailbox::List recipients = toList;
|
|
|
|
toList = stripMyAddressesFromAddressList( recipients, m_identityManager );
|
|
}
|
|
break;
|
|
case MessageComposer::ReplyAll:
|
|
{
|
|
KMime::Types::Mailbox::List recipients;
|
|
KMime::Types::Mailbox::List ccRecipients;
|
|
|
|
// add addresses from the Reply-To header to the list of recipients
|
|
if ( !replyToList.isEmpty() ) {
|
|
recipients = replyToList;
|
|
|
|
// strip all possible mailing list addresses from the list of Reply-To addresses
|
|
foreach ( const KMime::Types::Mailbox &mailbox, m_mailingListAddresses ) {
|
|
foreach ( const KMime::Types::Mailbox &recipient, recipients ) {
|
|
if ( mailbox == recipient )
|
|
recipients.removeAll( recipient );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !m_mailingListAddresses.isEmpty() ) {
|
|
// this is a mailing list message
|
|
if ( recipients.isEmpty() && !m_origMsg->from()->asUnicodeString().isEmpty() ) {
|
|
// The sender didn't set a Reply-to address, so we add the From
|
|
// address to the list of CC recipients.
|
|
ccRecipients += m_origMsg->from()->mailboxes();
|
|
kDebug() << "Added" << m_origMsg->from()->asUnicodeString() << "to the list of CC recipients";
|
|
}
|
|
|
|
// if it is a mailing list, add the posting address
|
|
recipients.prepend( m_mailingListAddresses[ 0 ] );
|
|
} else {
|
|
// this is a normal message
|
|
if ( recipients.isEmpty() && !m_origMsg->from()->asUnicodeString().isEmpty() ) {
|
|
// in case of replying to a normal message only then add the From
|
|
// address to the list of recipients if there was no Reply-to address
|
|
recipients += m_origMsg->from()->mailboxes();
|
|
kDebug() << "Added" << m_origMsg->from()->asUnicodeString() << "to the list of recipients";
|
|
}
|
|
}
|
|
|
|
// strip all my addresses from the list of recipients
|
|
toList = stripMyAddressesFromAddressList( recipients, m_identityManager );
|
|
|
|
// merge To header and CC header into a list of CC recipients
|
|
if ( !m_origMsg->cc()->asUnicodeString().isEmpty() || !m_origMsg->to()->asUnicodeString().isEmpty() ) {
|
|
KMime::Types::Mailbox::List list;
|
|
if ( !m_origMsg->to()->asUnicodeString().isEmpty() )
|
|
list += m_origMsg->to()->mailboxes();
|
|
if ( !m_origMsg->cc()->asUnicodeString().isEmpty() )
|
|
list += m_origMsg->cc()->mailboxes();
|
|
|
|
foreach ( const KMime::Types::Mailbox &mailbox, list ) {
|
|
if ( !recipients.contains( mailbox ) &&
|
|
!ccRecipients.contains( mailbox ) ) {
|
|
ccRecipients += mailbox;
|
|
kDebug() << "Added" << mailbox.prettyAddress() <<"to the list of CC recipients";
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !ccRecipients.isEmpty() ) {
|
|
// strip all my addresses from the list of CC recipients
|
|
ccRecipients = stripMyAddressesFromAddressList( ccRecipients, m_identityManager );
|
|
|
|
// in case of a reply to self, toList might be empty. if that's the case
|
|
// then propagate a cc recipient to To: (if there is any).
|
|
if ( toList.isEmpty() && !ccRecipients.isEmpty() ) {
|
|
toList << ccRecipients[ 0 ];
|
|
ccRecipients.pop_front();
|
|
}
|
|
|
|
foreach ( const KMime::Types::Mailbox &mailbox, ccRecipients )
|
|
msg->cc()->addAddress( mailbox );
|
|
}
|
|
|
|
if ( toList.isEmpty() && !recipients.isEmpty() ) {
|
|
// reply to self without other recipients
|
|
toList << recipients[ 0 ];
|
|
}
|
|
}
|
|
break;
|
|
case MessageComposer::ReplyAuthor:
|
|
{
|
|
if ( !replyToList.isEmpty() ) {
|
|
KMime::Types::Mailbox::List recipients = replyToList;
|
|
|
|
// strip the mailing list post address from the list of Reply-To
|
|
// addresses since we want to reply in private
|
|
foreach ( const KMime::Types::Mailbox &mailbox, m_mailingListAddresses ) {
|
|
foreach ( const KMime::Types::Mailbox &recipient, recipients ) {
|
|
if ( mailbox == recipient )
|
|
recipients.removeAll( recipient );
|
|
}
|
|
}
|
|
|
|
if ( !recipients.isEmpty() ) {
|
|
toList = recipients;
|
|
} else {
|
|
// there was only the mailing list post address in the Reply-To header,
|
|
// so use the From address instead
|
|
toList = m_origMsg->from()->mailboxes();
|
|
}
|
|
} else if ( !m_origMsg->from()->asUnicodeString().isEmpty() ) {
|
|
toList = m_origMsg->from()->mailboxes();
|
|
}
|
|
|
|
replyAll = false;
|
|
}
|
|
break;
|
|
case MessageComposer::ReplyNone:
|
|
// the addressees will be set by the caller
|
|
break;
|
|
}
|
|
|
|
foreach ( const KMime::Types::Mailbox &mailbox, toList )
|
|
msg->to()->addAddress( mailbox );
|
|
|
|
refStr = getRefStr( m_origMsg );
|
|
if ( !refStr.isEmpty() )
|
|
msg->references()->fromUnicodeString( QString::fromLocal8Bit( refStr ), "utf-8" );
|
|
|
|
//In-Reply-To = original msg-id
|
|
msg->inReplyTo()->from7BitString( m_origMsg->messageID()->as7BitString( false ) );
|
|
|
|
msg->subject()->fromUnicodeString( MessageHelper::replySubject( m_origMsg ), "utf-8" );
|
|
|
|
// If the reply shouldn't be blank, apply the template to the message
|
|
if ( m_quote ) {
|
|
TemplateParser::TemplateParser parser( msg, (replyAll ? TemplateParser::TemplateParser::ReplyAll : TemplateParser::TemplateParser::Reply ) );
|
|
parser.setIdentityManager( m_identityManager );
|
|
parser.setCharsets( MessageComposerSettings::self()->preferredCharsets() );
|
|
parser.setWordWrap( MessageComposerSettings::wordWrap(), MessageComposerSettings::lineWrapWidth() );
|
|
if ( MessageComposer::MessageComposerSettings::quoteSelectionOnly() ) {
|
|
parser.setSelection( m_selection );
|
|
}
|
|
parser.setAllowDecryption( m_allowDecryption );
|
|
if ( !m_template.isEmpty() )
|
|
parser.process( m_template, m_origMsg );
|
|
else
|
|
parser.process( m_origMsg, m_collection );
|
|
}
|
|
|
|
applyCharset( msg );
|
|
|
|
MessageCore::Util::addLinkInformation( msg, m_id, Akonadi::MessageStatus::statusReplied() );
|
|
if ( m_parentFolderId > 0 ) {
|
|
KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), QString::number( m_parentFolderId ), "utf-8" );
|
|
msg->setHeader( header );
|
|
}
|
|
|
|
if ( m_origMsg->hasHeader( "X-KMail-EncryptActionEnabled" ) &&
|
|
m_origMsg->headerByType( "X-KMail-EncryptActionEnabled" )->as7BitString().contains( "true" ) ) {
|
|
msg->setHeader( new KMime::Headers::Generic( "X-KMail-EncryptActionEnabled", msg.get(), QLatin1String( "true" ), "utf-8" ) );
|
|
}
|
|
msg->assemble();
|
|
|
|
MessageReply reply;
|
|
reply.msg = msg;
|
|
reply.replyAll = replyAll;
|
|
return reply;
|
|
}
|
|
|
|
|
|
|
|
KMime::Message::Ptr MessageFactory::createForward()
|
|
{
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
|
|
// This is a non-multipart, non-text mail (e.g. text/calendar). Construct
|
|
// a multipart/mixed mail and add the original body as an attachment.
|
|
if ( !m_origMsg->contentType()->isMultipart() &&
|
|
( !m_origMsg->contentType()->isText() ||
|
|
( m_origMsg->contentType()->isText() && m_origMsg->contentType()->subType() != "html"
|
|
&& m_origMsg->contentType()->subType() != "plain" ) ) ) {
|
|
const uint originalIdentity = identityUoid( m_origMsg );
|
|
MessageHelper::initFromMessage( msg, m_origMsg, m_identityManager, originalIdentity );
|
|
msg->removeHeader("Content-Type");
|
|
msg->removeHeader("Content-Transfer-Encoding");
|
|
|
|
msg->contentType()->setMimeType( "multipart/mixed" );
|
|
|
|
//TODO: Andras: somebody should check if this is correct. :)
|
|
// empty text part
|
|
KMime::Content *msgPart = new KMime::Content;
|
|
msgPart->contentType()->setMimeType("text/plain");
|
|
msg->addContent( msgPart );
|
|
|
|
// the old contents of the mail
|
|
KMime::Content *secondPart = new KMime::Content;
|
|
secondPart->contentType()->setMimeType( m_origMsg->contentType()->mimeType() );
|
|
secondPart->setBody( m_origMsg->body() );
|
|
// use the headers of the original mail
|
|
secondPart->setHead( m_origMsg->head() );
|
|
msg->addContent( secondPart );
|
|
msg->assemble();
|
|
}
|
|
|
|
// Normal message (multipart or text/plain|html)
|
|
// Just copy the message, the template parser will do the hard work of
|
|
// replacing the body text in TemplateParser::addProcessedBodyToMessage()
|
|
else {
|
|
//TODO Check if this is ok
|
|
msg->setHead( m_origMsg->head() );
|
|
msg->setBody( m_origMsg->body() );
|
|
QString oldContentType = msg->contentType()->asUnicodeString();
|
|
const uint originalIdentity = identityUoid( m_origMsg );
|
|
MessageHelper::initFromMessage( msg, m_origMsg, m_identityManager, originalIdentity );
|
|
|
|
// restore the content type, MessageHelper::initFromMessage() sets the contents type to
|
|
// text/plain, via initHeader(), for unclear reasons
|
|
msg->contentType()->fromUnicodeString( oldContentType, "utf-8" );
|
|
msg->assemble();
|
|
}
|
|
|
|
msg->subject()->fromUnicodeString( MessageHelper::forwardSubject( m_origMsg ), "utf-8" );
|
|
|
|
TemplateParser::TemplateParser parser( msg, TemplateParser::TemplateParser::Forward );
|
|
parser.setIdentityManager( m_identityManager );
|
|
parser.setCharsets( MessageComposerSettings::self()->preferredCharsets() );
|
|
if ( !m_template.isEmpty() )
|
|
parser.process( m_template, m_origMsg );
|
|
else
|
|
parser.process( m_origMsg, m_collection );
|
|
|
|
applyCharset( msg );
|
|
|
|
MessageCore::Util::addLinkInformation( msg, m_id, Akonadi::MessageStatus::statusForwarded() );
|
|
msg->assemble();
|
|
return msg;
|
|
}
|
|
|
|
QPair< KMime::Message::Ptr, QList< KMime::Content* > > MessageFactory::createAttachedForward(const QList< Akonadi::Item >& items)
|
|
{
|
|
|
|
// create forwarded message with original message as attachment
|
|
// remove headers that shouldn't be forwarded
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
QList< KMime::Content* > attachments;
|
|
|
|
const int numberOfItems( items.count() );
|
|
if( numberOfItems >= 2 ) {
|
|
// don't respect X-KMail-Identity headers because they might differ for
|
|
// the selected mails
|
|
MessageHelper::initHeader( msg, m_identityManager, m_origId );
|
|
} else if( numberOfItems == 1 ) {
|
|
KMime::Message::Ptr firstMsg = MessageCore::Util::message( items.first() );
|
|
const uint originalIdentity = identityUoid( firstMsg );
|
|
MessageHelper::initFromMessage( msg, firstMsg, m_identityManager, originalIdentity );
|
|
msg->subject()->fromUnicodeString( MessageHelper::forwardSubject( firstMsg ),"utf-8" );
|
|
}
|
|
|
|
MessageHelper::setAutomaticFields( msg, true );
|
|
#ifndef QT_NO_CURSOR
|
|
MessageViewer::KCursorSaver busy( MessageViewer::KBusyPtr::busy() );
|
|
#endif
|
|
if ( numberOfItems == 0 ) {
|
|
attachments << createForwardAttachmentMessage( m_origMsg );
|
|
MessageCore::Util::addLinkInformation( msg, m_id, Akonadi::MessageStatus::statusForwarded() );
|
|
}
|
|
else {
|
|
// iterate through all the messages to be forwarded
|
|
foreach ( const Akonadi::Item& item, items ) {
|
|
attachments << createForwardAttachmentMessage(MessageCore::Util::message( item ));
|
|
MessageCore::Util::addLinkInformation( msg, item.id(), Akonadi::MessageStatus::statusForwarded() );
|
|
}
|
|
}
|
|
|
|
applyCharset( msg );
|
|
|
|
//msg->assemble();
|
|
return QPair< KMime::Message::Ptr, QList< KMime::Content* > >( msg, QList< KMime::Content* >() << attachments );
|
|
}
|
|
|
|
KMime::Content *MessageFactory::createForwardAttachmentMessage(const KMime::Message::Ptr& fwdMsg)
|
|
{
|
|
// remove headers that shouldn't be forwarded
|
|
MessageCore::StringUtil::removePrivateHeaderFields( fwdMsg );
|
|
fwdMsg->removeHeader("Bcc");
|
|
fwdMsg->assemble();
|
|
// set the part
|
|
KMime::Content *msgPart = new KMime::Content( fwdMsg.get() );
|
|
msgPart->contentType()->setMimeType( "message/rfc822" );
|
|
|
|
msgPart->contentDisposition()->setParameter( QLatin1String( "filename" ), i18n( "forwarded message" ) );
|
|
msgPart->contentDisposition()->setDisposition( KMime::Headers::CDinline );
|
|
msgPart->contentDescription()->fromUnicodeString( fwdMsg->from()->asUnicodeString() + QLatin1String( ": " ) + fwdMsg->subject()->asUnicodeString(), "utf-8" );
|
|
msgPart->setBody( fwdMsg->encodedContent() );
|
|
msgPart->assemble();
|
|
|
|
#if 0
|
|
// THIS HAS TO BE AFTER setCte()!!!!
|
|
msgPart->setCharset( "" );
|
|
#else
|
|
kDebug() << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO;
|
|
#endif
|
|
MessageCore::Util::addLinkInformation( fwdMsg, m_origId, Akonadi::MessageStatus::statusForwarded() );
|
|
return msgPart;
|
|
}
|
|
|
|
|
|
|
|
KMime::Message::Ptr MessageFactory::createResend()
|
|
{
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
msg->setContent( m_origMsg->encodedContent() );
|
|
msg->parse();
|
|
msg->removeHeader( "Message-Id" );
|
|
uint originalIdentity = identityUoid( m_origMsg );
|
|
|
|
// Set the identity from above
|
|
KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-Identity", msg.get(), QString::number( originalIdentity ), "utf-8" );
|
|
msg->setHeader( header );
|
|
|
|
// Restore the original bcc field as this is overwritten in applyIdentity
|
|
msg->bcc( m_origMsg->bcc() );
|
|
return msg;
|
|
}
|
|
|
|
KMime::Message::Ptr MessageFactory::createRedirect( const QString &toStr, const QString &ccStr, const QString &bccStr, int transportId, const QString& fcc, int identity )
|
|
{
|
|
if ( !m_origMsg )
|
|
return KMime::Message::Ptr();
|
|
|
|
// copy the message 1:1
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
msg->setContent( m_origMsg->encodedContent() );
|
|
msg->parse();
|
|
|
|
uint id = identity;
|
|
if(identity == -1) {
|
|
const QString strId = msg->headerByType( "X-KMail-Identity" ) ? msg->headerByType( "X-KMail-Identity" )->asUnicodeString().trimmed() : QString::fromLocal8Bit("");
|
|
if ( !strId.isEmpty())
|
|
id = strId.toUInt();
|
|
}
|
|
const KPIMIdentities::Identity & ident =
|
|
m_identityManager->identityForUoidOrDefault( id );
|
|
|
|
// X-KMail-Redirect-From: content
|
|
QString strByWayOf = QString::fromLocal8Bit("%1 (by way of %2 <%3>)")
|
|
.arg( m_origMsg->from()->asUnicodeString() )
|
|
.arg( ident.fullName() )
|
|
.arg( ident.primaryEmailAddress() );
|
|
|
|
// Resent-From: content
|
|
QString strFrom = QString::fromLocal8Bit("%1 <%2>")
|
|
.arg( ident.fullName() )
|
|
.arg( ident.primaryEmailAddress() );
|
|
|
|
// format the current date to be used in Resent-Date:
|
|
QString newDate = KDateTime::currentLocalDateTime().toString( KDateTime::RFCDateDay );
|
|
|
|
// Clean up any resent headers
|
|
msg->removeHeader( "Resent-Cc" );
|
|
msg->removeHeader( "Resent-Bcc" );
|
|
msg->removeHeader( "Resent-Sender" );
|
|
// date, from to and id will be set anyway
|
|
|
|
// prepend Resent-*: headers (c.f. RFC2822 3.6.6)
|
|
QString msgIdSuffix;
|
|
if ( MessageComposer::MessageComposerSettings::useCustomMessageIdSuffix() ) {
|
|
msgIdSuffix = MessageComposer::MessageComposerSettings::customMsgIDSuffix();
|
|
}
|
|
KMime::Headers::Generic *header =
|
|
new KMime::Headers::Generic( "Resent-Message-ID", msg.get(),
|
|
MessageCore::StringUtil::generateMessageId(
|
|
msg->sender()->asUnicodeString(), msgIdSuffix ), "utf-8" );
|
|
msg->setHeader( header );
|
|
|
|
header = new KMime::Headers::Generic( "Resent-Date", msg.get(), newDate, "utf-8" );
|
|
msg->setHeader( header );
|
|
|
|
header = new KMime::Headers::Generic( "Resent-From", msg.get(), strFrom, "utf-8" );
|
|
msg->setHeader( header );
|
|
|
|
if ( msg->to(false) ) {
|
|
KMime::Headers::To* headerT = new KMime::Headers::To( msg.get(), m_origMsg->to()->asUnicodeString(), "utf-8" );
|
|
msg->setHeader( headerT );
|
|
}
|
|
|
|
header = new KMime::Headers::Generic( "Resent-To", msg.get(), toStr, "utf-8" );
|
|
msg->setHeader( header );
|
|
|
|
if (!ccStr.isEmpty()) {
|
|
header = new KMime::Headers::Generic( "Resent-Cc", msg.get(), ccStr, "utf-8" );
|
|
msg->setHeader( header );
|
|
}
|
|
|
|
if (!bccStr.isEmpty()) {
|
|
header = new KMime::Headers::Generic( "Resent-Bcc", msg.get(), bccStr, "utf-8" );
|
|
msg->setHeader( header );
|
|
}
|
|
|
|
header = new KMime::Headers::Generic( "X-KMail-Redirect-From", msg.get(), strByWayOf, "utf-8" );
|
|
msg->setHeader( header );
|
|
|
|
if ( transportId != -1 ) {
|
|
header = new KMime::Headers::Generic( "X-KMail-Transport", msg.get(), QString::number( transportId ), "utf-8" );
|
|
msg->setHeader( header );
|
|
}
|
|
|
|
if ( !fcc.isEmpty() ) {
|
|
header = new KMime::Headers::Generic( "X-KMail-Fcc", msg.get(), fcc, "utf-8" );
|
|
msg->setHeader( header );
|
|
}
|
|
|
|
const bool fccIsDisabled = ident.disabledFcc();
|
|
if (fccIsDisabled) {
|
|
KMime::Headers::Generic *header = new KMime::Headers::Generic( "X-KMail-FccDisabled", msg.get(), QLatin1String("true"), "utf-8" );
|
|
msg->setHeader( header );
|
|
} else {
|
|
msg->removeHeader( "X-KMail-FccDisabled" );
|
|
}
|
|
|
|
|
|
msg->assemble();
|
|
|
|
MessageCore::Util::addLinkInformation( msg, m_id, Akonadi::MessageStatus::statusForwarded() );
|
|
return msg;
|
|
}
|
|
|
|
|
|
KMime::Message::Ptr MessageFactory::createDeliveryReceipt()
|
|
{
|
|
QString str, receiptTo;
|
|
KMime::Message::Ptr receipt;
|
|
|
|
receiptTo = m_origMsg->headerByType("Disposition-Notification-To") ? m_origMsg->headerByType("Disposition-Notification-To")->asUnicodeString() : QString::fromLatin1("");
|
|
if ( receiptTo.trimmed().isEmpty() )
|
|
return KMime::Message::Ptr();
|
|
receiptTo.remove( QChar::fromLatin1('\n') );
|
|
|
|
receipt = KMime::Message::Ptr( new KMime::Message );
|
|
const uint originalIdentity = identityUoid( m_origMsg );
|
|
MessageHelper::initFromMessage( receipt, m_origMsg, m_identityManager, originalIdentity );
|
|
receipt->to()->fromUnicodeString( receiptTo, QString::fromLatin1("utf-8").toLatin1() );
|
|
receipt->subject()->fromUnicodeString( i18n("Receipt: ") + m_origMsg->subject()->asUnicodeString(), "utf-8");
|
|
|
|
str = QString::fromLatin1("Your message was successfully delivered.");
|
|
str += QString::fromLatin1("\n\n---------- Message header follows ----------\n");
|
|
str += QString::fromLatin1(m_origMsg->head());
|
|
str += QString::fromLatin1("--------------------------------------------\n");
|
|
// Conversion to toLatin1 is correct here as Mail headers should contain
|
|
// ascii only
|
|
receipt->setBody(str.toLatin1());
|
|
MessageHelper::setAutomaticFields( receipt );
|
|
receipt->assemble();
|
|
|
|
return receipt;
|
|
}
|
|
|
|
KMime::Message::Ptr MessageFactory::createMDN( KMime::MDN::ActionMode a,
|
|
KMime::MDN::DispositionType d,
|
|
KMime::MDN::SendingMode s,
|
|
int mdnQuoteOriginal,
|
|
const QList<KMime::MDN::DispositionModifier>& m )
|
|
{
|
|
// extract where to send to:
|
|
QString receiptTo = m_origMsg->headerByType("Disposition-Notification-To") ? m_origMsg->headerByType("Disposition-Notification-To")->asUnicodeString() : QString::fromLatin1("");
|
|
if( receiptTo.trimmed().isEmpty() ) return KMime::Message::Ptr( new KMime::Message );
|
|
receiptTo.remove( QChar::fromLatin1('\n') );
|
|
|
|
|
|
QString special; // fill in case of error, warning or failure
|
|
|
|
// extract where to send from:
|
|
QString finalRecipient = m_identityManager->identityForUoidOrDefault( identityUoid( m_origMsg ) ).fullEmailAddr();
|
|
|
|
//
|
|
// Generate message:
|
|
//
|
|
|
|
KMime::Message::Ptr receipt( new KMime::Message() );
|
|
const uint originalIdentity = identityUoid( m_origMsg );
|
|
MessageHelper::initFromMessage( receipt, m_origMsg, m_identityManager, originalIdentity );
|
|
receipt->contentType()->from7BitString( "multipart/report" );
|
|
receipt->contentType()->setBoundary( KMime::multiPartBoundary() );
|
|
receipt->contentType()->setCharset( "us-ascii" );
|
|
receipt->removeHeader("Content-Transfer-Encoding");
|
|
// Modify the ContentType directly (replaces setAutomaticFields(true))
|
|
receipt->contentType()->setParameter( QString::fromLatin1("report-type"), QString::fromLatin1("disposition-notification") );
|
|
|
|
|
|
QString description = replaceHeadersInString( m_origMsg, KMime::MDN::descriptionFor( d, m ) );
|
|
|
|
// text/plain part:
|
|
KMime::Content* firstMsgPart = new KMime::Content( m_origMsg.get() );
|
|
firstMsgPart->contentType()->setMimeType( "text/plain" );
|
|
firstMsgPart->contentType()->setCharset( "utf-8" );
|
|
firstMsgPart->contentTransferEncoding()->from7BitString( "7bit" );
|
|
firstMsgPart->setBody( description.toUtf8() );
|
|
receipt->addContent( firstMsgPart );
|
|
|
|
// message/disposition-notification part:
|
|
KMime::Content* secondMsgPart = new KMime::Content( m_origMsg.get() );
|
|
secondMsgPart->contentType()->setMimeType( "message/disposition-notification" );
|
|
//secondMsgPart.setCharset( "us-ascii" );
|
|
|
|
secondMsgPart->contentTransferEncoding()->from7BitString( "7bit" );
|
|
secondMsgPart->setBody( KMime::MDN::dispositionNotificationBodyContent(
|
|
finalRecipient,
|
|
m_origMsg->headerByType("Original-Recipient") ? m_origMsg->headerByType("Original-Recipient")->as7BitString() : "",
|
|
m_origMsg->messageID()->as7BitString(), /* Message-ID */
|
|
d, a, s, m, special ) );
|
|
receipt->addContent( secondMsgPart );
|
|
|
|
if ( mdnQuoteOriginal < 0 || mdnQuoteOriginal > 2 ) mdnQuoteOriginal = 0;
|
|
/* 0=> Nothing, 1=>Full Message, 2=>HeadersOnly*/
|
|
|
|
KMime::Content* thirdMsgPart = new KMime::Content( m_origMsg.get() );
|
|
switch ( mdnQuoteOriginal ) {
|
|
case 1:
|
|
thirdMsgPart->contentType()->setMimeType( "message/rfc822" );
|
|
thirdMsgPart->setBody( MessageCore::StringUtil::asSendableString( m_origMsg ) );
|
|
receipt->addContent( thirdMsgPart );
|
|
break;
|
|
case 2:
|
|
thirdMsgPart->contentType()->setMimeType( "text/rfc822-headers" );
|
|
thirdMsgPart->setBody( MessageCore::StringUtil::headerAsSendableString( m_origMsg ) );
|
|
receipt->addContent( thirdMsgPart );
|
|
break;
|
|
case 0:
|
|
default:
|
|
break;
|
|
};
|
|
|
|
receipt->to()->fromUnicodeString( receiptTo, "utf-8" );
|
|
//Laurent: We don't translate subject ?
|
|
receipt->subject()->from7BitString( "Message Disposition Notification" );
|
|
KMime::Headers::InReplyTo *header = new KMime::Headers::InReplyTo( receipt.get(), m_origMsg->messageID()->asUnicodeString(), "utf-8" );
|
|
receipt->setHeader( header );
|
|
|
|
receipt->references()->from7BitString( getRefStr( m_origMsg ) );
|
|
|
|
receipt->assemble();
|
|
|
|
|
|
kDebug() << "final message:" + receipt->encodedContent();
|
|
|
|
receipt->assemble();
|
|
return receipt;
|
|
}
|
|
|
|
QPair< KMime::Message::Ptr, KMime::Content* > MessageFactory::createForwardDigestMIME( const QList< Akonadi::Item >& items )
|
|
{
|
|
KMime::Message::Ptr msg( new KMime::Message );
|
|
KMime::Content* digest = new KMime::Content( msg.get() );
|
|
|
|
QString mainPartText = i18n("\nThis is a MIME digest forward. The content of the"
|
|
" message is contained in the attachment(s).\n\n\n");
|
|
|
|
digest->contentType()->setMimeType( "multipart/digest" );
|
|
digest->contentType()->setBoundary( KMime::multiPartBoundary() );
|
|
digest->contentDescription()->fromUnicodeString( QString::fromLatin1("Digest of %1 messages.").arg( items.count() ), "utf8" );
|
|
digest->contentDisposition()->setFilename( QLatin1String( "digest" ) );
|
|
digest->fromUnicodeString( mainPartText );
|
|
|
|
int id = 0;
|
|
foreach ( const Akonadi::Item& item, items ) {
|
|
KMime::Message::Ptr fMsg = MessageCore::Util::message( item );
|
|
if( id == 0 && fMsg->hasHeader( "X-KMail-Identity" ) )
|
|
id = fMsg->headerByType( "X-KMail-Identity" )->asUnicodeString().toInt();
|
|
|
|
MessageCore::StringUtil::removePrivateHeaderFields( fMsg );
|
|
fMsg->removeHeader("Bcc");
|
|
fMsg->assemble();
|
|
KMime::Content* part = new KMime::Content( digest );
|
|
|
|
part->contentType()->setMimeType( "message/rfc822" );
|
|
part->contentType()->setCharset( fMsg->contentType()->charset() );
|
|
part->contentID()->setIdentifier( fMsg->contentID()->identifier() );
|
|
part->contentDescription()->fromUnicodeString( fMsg->contentDescription()->asUnicodeString(), "utf8" );
|
|
part->contentDisposition()->setParameter( QLatin1String( "name" ), i18n( "forwarded message" ) );
|
|
part->fromUnicodeString( QString::fromLatin1( fMsg->encodedContent() ) );
|
|
part->assemble();
|
|
MessageCore::Util::addLinkInformation( msg, item.id(), Akonadi::MessageStatus::statusForwarded() );
|
|
digest->addContent( part );
|
|
}
|
|
digest->assemble();
|
|
|
|
id = m_folderId;
|
|
MessageHelper::initHeader( msg, m_identityManager, id );
|
|
|
|
// kDebug() << "digest:" << digest->contents().size() << digest->encodedContent();
|
|
|
|
return QPair< KMime::Message::Ptr, KMime::Content* >( msg, digest );
|
|
}
|
|
|
|
|
|
void MessageFactory::setIdentityManager( KPIMIdentities::IdentityManager* ident)
|
|
{
|
|
m_identityManager = ident;
|
|
}
|
|
|
|
void MessageFactory::setMessageItemID( Akonadi::Entity::Id id )
|
|
{
|
|
m_origId = id;
|
|
}
|
|
|
|
void MessageFactory::setReplyStrategy( MessageComposer::ReplyStrategy replyStrategy )
|
|
{
|
|
m_replyStrategy = replyStrategy;
|
|
}
|
|
|
|
void MessageFactory::setSelection( const QString& selection )
|
|
{
|
|
m_selection = selection;
|
|
}
|
|
|
|
void MessageFactory::setQuote( bool quote )
|
|
{
|
|
m_quote = quote;
|
|
}
|
|
|
|
void MessageFactory::setAllowDecryption( bool allowD )
|
|
{
|
|
m_allowDecryption = allowD;
|
|
}
|
|
|
|
void MessageFactory::setTemplate( const QString& templ )
|
|
{
|
|
m_template = templ;
|
|
}
|
|
|
|
void MessageFactory::setMailingListAddresses( const KMime::Types::Mailbox::List& listAddresses )
|
|
{
|
|
m_mailingListAddresses << listAddresses;
|
|
}
|
|
|
|
void MessageFactory::setFolderIdentity( Akonadi::Entity::Id folderIdentityId )
|
|
{
|
|
m_folderId = folderIdentityId;
|
|
}
|
|
|
|
void MessageFactory::putRepliesInSameFolder( Akonadi::Entity::Id parentColId )
|
|
{
|
|
m_parentFolderId = parentColId;
|
|
}
|
|
|
|
bool MessageFactory::MDNRequested(const KMime::Message::Ptr& msg)
|
|
{
|
|
// extract where to send to:
|
|
QString receiptTo = msg->headerByType("Disposition-Notification-To") ? msg->headerByType("Disposition-Notification-To")->asUnicodeString() : QString::fromLatin1("");
|
|
if ( receiptTo.trimmed().isEmpty() ) return false;
|
|
receiptTo.remove( QChar::fromLatin1('\n') );
|
|
return !receiptTo.isEmpty();
|
|
}
|
|
|
|
|
|
bool MessageFactory::MDNConfirmMultipleRecipients( const KMime::Message::Ptr& msg )
|
|
{
|
|
// extract where to send to:
|
|
QString receiptTo = msg->headerByType("Disposition-Notification-To") ? msg->headerByType("Disposition-Notification-To")->asUnicodeString() : QString::fromLatin1("");
|
|
if ( receiptTo.trimmed().isEmpty() ) return false;
|
|
receiptTo.remove( QChar::fromLatin1('\n') );
|
|
|
|
// RFC 2298: [ Confirmation from the user SHOULD be obtained (or no
|
|
// MDN sent) ] if there is more than one distinct address in the
|
|
// Disposition-Notification-To header.
|
|
kDebug() << "KPIMUtils::splitAddressList(receiptTo):" // krazy:exclude=kdebug
|
|
<< KPIMUtils::splitAddressList(receiptTo).join(QString::fromLatin1("\n"));
|
|
|
|
return KPIMUtils::splitAddressList(receiptTo).count() > 1;
|
|
}
|
|
|
|
bool MessageFactory::MDNReturnPathEmpty( const KMime::Message::Ptr& msg )
|
|
{
|
|
// extract where to send to:
|
|
QString receiptTo = msg->headerByType("Disposition-Notification-To") ? msg->headerByType("Disposition-Notification-To")->asUnicodeString() : QString::fromLatin1("");
|
|
if ( receiptTo.trimmed().isEmpty() ) return false;
|
|
receiptTo.remove( QChar::fromLatin1('\n') );
|
|
|
|
// RFC 2298: MDNs SHOULD NOT be sent automatically if the address in
|
|
// the Disposition-Notification-To header differs from the address
|
|
// in the Return-Path header. [...] Confirmation from the user
|
|
// SHOULD be obtained (or no MDN sent) if there is no Return-Path
|
|
// header in the message [...]
|
|
KMime::Types::AddrSpecList returnPathList = MessageHelper::extractAddrSpecs( msg, "Return-Path");
|
|
QString returnPath = returnPathList.isEmpty() ? QString()
|
|
: returnPathList.front().localPart + QChar::fromLatin1('@') + returnPathList.front().domain;
|
|
kDebug() << "clean return path:" << returnPath;
|
|
return returnPath.isEmpty();
|
|
}
|
|
|
|
bool MessageFactory::MDNReturnPathNotInRecieptTo( const KMime::Message::Ptr& msg )
|
|
{
|
|
// extract where to send to:
|
|
QString receiptTo = msg->headerByType("Disposition-Notification-To") ? msg->headerByType("Disposition-Notification-To")->asUnicodeString() : QString::fromLatin1("");
|
|
if ( receiptTo.trimmed().isEmpty() ) return false;
|
|
receiptTo.remove( QChar::fromLatin1('\n') );
|
|
|
|
// RFC 2298: MDNs SHOULD NOT be sent automatically if the address in
|
|
// the Disposition-Notification-To header differs from the address
|
|
// in the Return-Path header. [...] Confirmation from the user
|
|
// SHOULD be obtained (or no MDN sent) if there is no Return-Path
|
|
// header in the message [...]
|
|
KMime::Types::AddrSpecList returnPathList = MessageHelper::extractAddrSpecs( msg, QString::fromLatin1("Return-Path").toLatin1());
|
|
QString returnPath = returnPathList.isEmpty() ? QString()
|
|
: returnPathList.front().localPart + QChar::fromLatin1('@') + returnPathList.front().domain;
|
|
kDebug() << "clean return path:" << returnPath;
|
|
return !receiptTo.contains( returnPath, Qt::CaseSensitive );
|
|
}
|
|
|
|
bool MessageFactory::MDNMDNUnknownOption( const KMime::Message::Ptr& msg )
|
|
{
|
|
|
|
// RFC 2298: An importance of "required" indicates that
|
|
// interpretation of the parameter is necessary for proper
|
|
// generation of an MDN in response to this request. If a UA does
|
|
// not understand the meaning of the parameter, it MUST NOT generate
|
|
// an MDN with any disposition type other than "failed" in response
|
|
// to the request.
|
|
QString notificationOptions = msg->headerByType("Disposition-Notification-Options") ? msg->headerByType("Disposition-Notification-Options")->asUnicodeString() : QString::fromLatin1("");
|
|
if ( notificationOptions.contains( QString::fromLatin1("required"), Qt::CaseSensitive ) ) {
|
|
// ### hacky; should parse...
|
|
// There is a required option that we don't understand. We need to
|
|
// ask the user what we should do:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
uint MessageFactory::identityUoid( const KMime::Message::Ptr &msg )
|
|
{
|
|
QString idString;
|
|
if ( msg->headerByType("X-KMail-Identity") )
|
|
idString = msg->headerByType("X-KMail-Identity")->asUnicodeString().trimmed();
|
|
bool ok = false;
|
|
int id = idString.toUInt( &ok );
|
|
|
|
if ( !ok || id == 0 )
|
|
id = m_identityManager->identityForAddress( msg->to()->asUnicodeString() + QString::fromLatin1(", ") + msg->cc()->asUnicodeString() ).uoid();
|
|
|
|
if ( id == 0 && m_folderId > 0 ) {
|
|
id = m_folderId;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
|
|
QString MessageFactory::replaceHeadersInString( const KMime::Message::Ptr &msg, const QString & s )
|
|
{
|
|
QString result = s;
|
|
QRegExp rx( QString::fromLatin1("\\$\\{([a-z0-9-]+)\\}"), Qt::CaseInsensitive );
|
|
Q_ASSERT( rx.isValid() );
|
|
|
|
QRegExp rxDate( QString::fromLatin1("\\$\\{date\\}") );
|
|
Q_ASSERT( rxDate.isValid() );
|
|
|
|
kDebug() << "creating mdn date:" << msg->date()->dateTime().dateTime().toTime_t() << KMime::DateFormatter::formatDate(
|
|
KMime::DateFormatter::Localized, msg->date()->dateTime().dateTime().toTime_t() );
|
|
QString sDate = KMime::DateFormatter::formatDate(
|
|
KMime::DateFormatter::Localized, msg->date()->dateTime().dateTime().toTime_t() );
|
|
|
|
int idx = 0;
|
|
if( ( idx = rxDate.indexIn( result, idx ) ) != -1 ) {
|
|
result.replace( idx, rxDate.matchedLength(), sDate );
|
|
}
|
|
|
|
idx = 0;
|
|
while ( ( idx = rx.indexIn( result, idx ) ) != -1 ) {
|
|
QString replacement = msg->headerByType( rx.cap(1).toLatin1() ) ? msg->headerByType( rx.cap(1).toLatin1() )->asUnicodeString() : QString::fromLatin1("");
|
|
result.replace( idx, rx.matchedLength(), replacement );
|
|
idx += replacement.length();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void MessageFactory::applyCharset( const KMime::Message::Ptr msg )
|
|
{
|
|
if ( MessageComposer::MessageComposerSettings::forceReplyCharset() ) {
|
|
// first convert the body from its current encoding to unicode representation
|
|
QTextCodec *bodyCodec = KGlobal::charsets()->codecForName( QString::fromLatin1( msg->contentType()->charset() ) );
|
|
if ( !bodyCodec )
|
|
bodyCodec = KGlobal::charsets()->codecForName( QLatin1String( "UTF-8" ) );
|
|
|
|
const QString body = bodyCodec->toUnicode( msg->body() );
|
|
|
|
// then apply the encoding of the original message
|
|
msg->contentType()->setCharset( m_origMsg->contentType()->charset() );
|
|
|
|
QTextCodec *codec = KGlobal::charsets()->codecForName( QString::fromLatin1( msg->contentType()->charset() ) );
|
|
if ( !codec ) {
|
|
kError() << "Could not get text codec for charset" << msg->contentType()->charset();
|
|
} else if ( !codec->canEncode( body ) ) { // charset can't encode body, fall back to preferred
|
|
const QStringList charsets = MessageComposer::MessageComposerSettings::preferredCharsets();
|
|
|
|
QList<QByteArray> chars;
|
|
foreach ( const QString &charset, charsets )
|
|
chars << charset.toLatin1();
|
|
|
|
QByteArray fallbackCharset = MessageComposer::Util::selectCharset( chars, body );
|
|
if ( fallbackCharset.isEmpty() ) // UTF-8 as fall-through
|
|
fallbackCharset = "UTF-8";
|
|
|
|
codec = KGlobal::charsets()->codecForName( QString::fromLatin1( fallbackCharset ) );
|
|
msg->setBody( codec->fromUnicode( body ) );
|
|
} else {
|
|
msg->setBody( codec->fromUnicode( body ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
QByteArray MessageFactory::getRefStr( const KMime::Message::Ptr &msg )
|
|
{
|
|
QByteArray firstRef, lastRef, refStr, retRefStr;
|
|
int i, j;
|
|
|
|
refStr = msg->headerByType("References") ? msg->headerByType("References")->as7BitString().trimmed() : "";
|
|
|
|
if (refStr.isEmpty())
|
|
return msg->messageID()->as7BitString( false );
|
|
|
|
i = refStr.indexOf('<');
|
|
j = refStr.indexOf('>');
|
|
firstRef = refStr.mid(i, j-i+1);
|
|
if (!firstRef.isEmpty())
|
|
retRefStr = firstRef + ' ';
|
|
|
|
i = refStr.lastIndexOf('<');
|
|
j = refStr.lastIndexOf('>');
|
|
|
|
lastRef = refStr.mid(i, j-i+1);
|
|
if (!lastRef.isEmpty() && lastRef != firstRef)
|
|
retRefStr += lastRef + ' ';
|
|
|
|
retRefStr += msg->messageID()->as7BitString( false );
|
|
return retRefStr;
|
|
}
|