diff -r cfcbf08528c4 -r 2b40d63a9c3d qtmobility/src/messaging/qmessage_qmf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtmobility/src/messaging/qmessage_qmf.cpp Fri Apr 16 15:51:22 2010 +0300 @@ -0,0 +1,702 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qmessage.h" +#include "qmessagecontentcontainer_p.h" +#include "qmfhelpers_p.h" +#include "qmessage_p.h" + +#include + +#include +#include +#include + +using namespace QTM_PREPEND_NAMESPACE(QmfHelpers); + +// This class has friend access to QMailMessage +// and hsould not be within QTM_NAMESPACE +struct QMailStorePrivate +{ + static inline void setUnmodified(QMailMessage *msg) + { + msg->setUnmodified(); + } +}; + + + +QTM_BEGIN_NAMESPACE + +Q_SCOPED_STATIC_DEFINE(QMessagePrivate::StandardFolderMap,QMessagePrivate,standardFolderMap); + +QMessageFolderId QMessagePrivate::standardFolderId(QMessage::StandardFolder folder) +{ + StandardFolderMap::const_iterator it = standardFolderMap()->find(folder); + if (it == standardFolderMap()->end()) { + const char *path((folder == QMessage::InboxFolder ? "Inbox" : + (folder == QMessage::OutboxFolder ? "Outbox" : + (folder == QMessage::DraftsFolder ? "Drafts" : + (folder == QMessage::SentFolder ? "Sent" : + (folder == QMessage::TrashFolder ? "Trash" : "")))))); + + // Find the ID for this standard folder + QMessageFolderFilter pathFilter(QMessageFolderFilter::byPath(path)); + QMessageFolderFilter accountFilter(QMessageFolderFilter::byParentAccountId(QMessageAccountId())); + + QMessageFolderId folderId(QMessageManager().queryFolders(pathFilter & accountFilter).first()); + it = standardFolderMap()->insert(folder, folderId); + } + + return *it; +} + +QMessage::StandardFolder QMessagePrivate::standardFolder(QMessageFolderId folderId) +{ + StandardFolderMap::const_iterator it = standardFolderMap()->begin(), end = standardFolderMap()->end(); + for ( ; it != end; ++it) { + if (it.value() == folderId) { + return it.key(); + } + } + + return QMessage::InboxFolder; +} + +QMessage QMessagePrivate::convert(const QMailMessage &message) +{ + QMessage result; + result.d_ptr->_message = message; + return result; +} + +QMailMessage QMessagePrivate::convert(const QMessage &message) +{ + return message.d_ptr->_message; +} + +QMailMessage *QMessagePrivate::convert(QMessage *message) +{ + return &message->d_ptr->_message; +} + +/* +const QMailMessage *QMessagePrivate::convert(const QMessage *message) +{ + return &message->d_ptr->_message; +} +*/ + +void QMessagePrivate::setStandardFolder(QMessage& message, QMessage::StandardFolder sf) +{ + QMessageFolderId folderId(standardFolderId(sf)); + message.d_ptr->_message.setParentFolderId(QmfHelpers::convert(folderId)); +} + +namespace QmfHelpers { + +QMessage convert(const QMailMessage &message) +{ + return QMessagePrivate::convert(message); +} + +QMailMessage convert(const QMessage &message) +{ + return QMessagePrivate::convert(message); +} + +QMailMessage *convert(QMessage *message) +{ + return QMessagePrivate::convert(message); +} + +/* +const QMailMessage *convert(const QMessage *message) +{ + return QMessagePrivate::convert(message); +} +*/ + +} + +namespace { + +struct TextPartLocator +{ + QMailMessagePart::Location _location; + + bool operator()(const QMailMessagePart &part) + { + if (part.contentType().type().toLower() == "text") { + _location = part.location(); + return false; + } + + return true; + } +}; + +struct PartLocator +{ + QMailMessagePart::Location _location; + const QMailMessagePart *_part; + + PartLocator(const QMailMessagePart::Location &location) : _location(location), _part(0) {} + + bool operator()(const QMailMessagePart &part) + { + if (part.location() == _location) { + _part = ∂ + return false; + } + + return true; + } +}; + +struct AttachmentLocator +{ + QList _locations; + bool _foundText; + + AttachmentLocator() : _foundText(false) {} + + bool operator()(const QMailMessagePart &part) + { + if (!_foundText && part.contentType().type().toLower() == "text") { + _foundText = true; + } else if (part.multipartType() == QMailMessagePart::MultipartNone) { + _locations.append(part.location()); + } + + return true; + } +}; + +QByteArray charsetFor(const QString &input) +{ + QByteArray result(QMessage::preferredCharsetFor(input)); + if (result.isEmpty()) { + result = "UTF-8"; + } + + return result; +} + +} + +QMessage::QMessage() + : d_ptr(new QMessagePrivate) +{ + setDerivedMessage(this); + QMailStorePrivate::setUnmodified(&d_ptr->_message); +} + +QMessage::QMessage(const QMessageId& id) + : d_ptr(new QMessagePrivate) +{ + *this = QMessageManager().message(id); + setDerivedMessage(this); + QMailStorePrivate::setUnmodified(&d_ptr->_message); +} + +QMessage::QMessage(const QMessage &other) + : QMessageContentContainer(), + d_ptr(new QMessagePrivate) +{ + this->operator=(other); + setDerivedMessage(this); + QMailStorePrivate::setUnmodified(&d_ptr->_message); +} + +QMessage& QMessage::operator=(const QMessage& other) +{ + if (&other != this) { + QMessageContentContainer::operator=(other); + d_ptr->_message = other.d_ptr->_message; + setDerivedMessage(this); + } + + return *this; +} + +QMessage::~QMessage() +{ + delete d_ptr; +} + +QMessageId QMessage::id() const +{ + return convert(d_ptr->_message.id()); +} + +QMessage::Type QMessage::type() const +{ + return convert(d_ptr->_message.messageType()); +} + +void QMessage::setType(Type t) +{ + d_ptr->_message.setMessageType(convert(t)); +} + +QMessageAccountId QMessage::parentAccountId() const +{ + return convert(d_ptr->_message.parentAccountId()); +} + +void QMessage::setParentAccountId(const QMessageAccountId &accountId) +{ + d_ptr->_message.setParentAccountId(convert(accountId)); +} + +QMessageFolderId QMessage::parentFolderId() const +{ + return convert(d_ptr->_message.parentFolderId()); +} + +QMessage::StandardFolder QMessage::standardFolder() const +{ + return QMessagePrivate::standardFolder(convert(d_ptr->_message.parentFolderId())); +} + +QMessageAddress QMessage::from() const +{ + return convert(d_ptr->_message.from()); +} + +void QMessage::setFrom(const QMessageAddress &address) +{ + d_ptr->_message.setFrom(convert(address)); +} + +QString QMessage::subject() const +{ + return d_ptr->_message.subject(); +} + +void QMessage::setSubject(const QString &s) +{ + d_ptr->_message.setSubject(s); +} + +QDateTime QMessage::date() const +{ + return d_ptr->_message.date().toLocalTime(); +} + +void QMessage::setDate(const QDateTime &d) +{ + d_ptr->_message.setDate(QMailTimeStamp(d)); +} + +QDateTime QMessage::receivedDate() const +{ + return d_ptr->_message.receivedDate().toLocalTime(); +} + +void QMessage::setReceivedDate(const QDateTime &d) +{ + d_ptr->_message.setReceivedDate(QMailTimeStamp(d)); +} + +QMessageAddressList QMessage::to() const +{ + return convert(d_ptr->_message.to()); +} + +void QMessage::setTo(const QMessageAddressList& toList) +{ + d_ptr->_message.setTo(convert(toList)); +} + +void QMessage::setTo(const QMessageAddress& address) +{ + d_ptr->_message.setTo(convert(address)); +} + +QMessageAddressList QMessage::cc() const +{ + return convert(d_ptr->_message.cc()); +} + +void QMessage::setCc(const QMessageAddressList& ccList) +{ + d_ptr->_message.setCc(convert(ccList)); +} + +QMessageAddressList QMessage::bcc() const +{ + return convert(d_ptr->_message.bcc()); +} + +void QMessage::setBcc(const QMessageAddressList& bccList) +{ + d_ptr->_message.setBcc(convert(bccList)); +} + +QMessage::StatusFlags QMessage::status() const +{ + return convert(d_ptr->_message.status()); +} + +void QMessage::setStatus(QMessage::StatusFlags newStatus) +{ + d_ptr->_message.setStatus(convert(newStatus)); +} + +void QMessage::setStatus(QMessage::Status flag, bool set) +{ + d_ptr->_message.setStatus(convert(flag), set); +} + +QMessage::Priority QMessage::priority() const +{ + quint64 status(d_ptr->_message.status()); + + if (status & highPriorityMask()) { + return QMessage::HighPriority; + } else if (status & lowPriorityMask()) { + return QMessage::LowPriority; + } + + return QMessage::NormalPriority; +} + +void QMessage::setPriority(Priority newPriority) +{ + quint64 setMask(0); + quint64 unsetMask(0); + + if (newPriority == QMessage::HighPriority) { + setMask = highPriorityMask(); + unsetMask = lowPriorityMask(); + } else if (newPriority == QMessage::LowPriority) { + unsetMask = highPriorityMask(); + setMask = lowPriorityMask(); + } else { + unsetMask = (highPriorityMask() | lowPriorityMask()); + } + + if (setMask) { + d_ptr->_message.setStatus(setMask, true); + } + if (unsetMask) { + d_ptr->_message.setStatus(unsetMask, false); + } +} + +int QMessage::size() const +{ + if ((d_ptr->_message.status() & QMailMessage::LocalOnly) && + (d_ptr->_message.dataModified() || + d_ptr->_message.contentModified())) { + // We need to update the size estimate for this message + d_ptr->_message.setSize(static_cast(d_ptr->_message.indicativeSize()) * 1024); + } + + return static_cast(d_ptr->_message.size()); +} + +QMessageContentContainerId QMessage::bodyId() const +{ + if (d_ptr->_message.hasBody()) { + return QmfHelpers::bodyId(d_ptr->_message.id()); + } + + // Return the first text part + TextPartLocator locator; + d_ptr->_message.foreachPart(locator); + + return convert(locator._location); +} + +void QMessage::setBody(const QString &bodyText, const QByteArray &mimeType) +{ + QByteArray mainType("text"); + QByteArray subType("plain"); + QByteArray charset; + + int index = mimeType.indexOf("/"); + if (index != -1) { + mainType = mimeType.left(index).trimmed(); + + subType = mimeType.mid(index + 1).trimmed(); + index = subType.indexOf(";"); + if (index != -1) { + QString remainder = subType.mid(index + 1); + subType = subType.left(index).trimmed(); + + QRegExp charsetPattern("charset=(\\S+)"); + index = charsetPattern.indexIn(remainder); + if (index != -1) { + charset = charsetPattern.cap(1).toLatin1(); + } + } + } + + if (charset.isEmpty()) { + charset = charsetFor(bodyText); + } + + QMailMessageContentType ct; + ct.setType(mainType); + ct.setSubType(subType); + ct.setCharset(charset); + + QMailMessageBody textBody(QMailMessageBody::fromData(bodyText, ct, QMailMessageBody::Base64)); + + if (d_ptr->_message.multipartType() == QMailMessage::MultipartNone) { + // Replace the body with this data + d_ptr->_message.setBody(textBody); + } else { + // Replace any existing text with this part + TextPartLocator locator; + d_ptr->_message.foreachPart(locator); + if (locator._location.isValid()) { + // Update the existing body text part to contain the new text + QMailMessagePart &bodyPart = d_ptr->_message.partAt(locator._location); + bodyPart.setBody(textBody); + } else { + // Insert the text as the new first part + QMailMessageContentDisposition cd(QMailMessageContentDisposition::Inline); + QMailMessagePart part(QMailMessagePart::fromData(bodyText, ct, cd, QMailMessageBody::Base64)); + d_ptr->_message.prependPart(part); + } + } +} + +void QMessage::setBody(QTextStream &in, const QByteArray &mimeType) +{ + // Note we have to read the data from the stream, in order to determine the relevant charset + setBody(in.readAll(), mimeType); +} + +QMessageContentContainerIdList QMessage::attachmentIds() const +{ + // Return any non-multipart parts excluding the first text part + AttachmentLocator locator; + d_ptr->_message.foreachPart(locator); + + return convert(locator._locations); +} + +void QMessage::appendAttachments(const QStringList &fileNames) +{ + if (d_ptr->_message.multipartType() == QMailMessage::MultipartNone) { + if (d_ptr->_message.hasBody()) { + // Move the existing body to become the first part + QMailMessageContentType ct(d_ptr->_message.contentType()); + QString bodyText(d_ptr->_message.body().data()); + + QMailMessageContentDisposition cd(QMailMessageContentDisposition::Inline); + cd.setSize(bodyText.length()); + + QMailMessagePart textPart(QMailMessagePart::fromData(bodyText, cd, ct, QMailMessageBody::Base64)); + + d_ptr->_message.setMultipartType(QMailMessage::MultipartMixed); + d_ptr->_message.appendPart(textPart); + } else { + // Just set this message to be multipart + d_ptr->_message.setMultipartType(QMailMessage::MultipartMixed); + } + } + + foreach (const QString &filename, fileNames) { + QString mimeType(QMail::mimeTypeFromFileName(filename)); + if (!mimeType.isEmpty()) { + QFileInfo fi(filename); + + QMailMessageContentDisposition cd(QMailMessageContentDisposition::Attachment); + cd.setFilename(fi.fileName().toAscii()); + cd.setSize(fi.size()); + + QMailMessageContentType ct(mimeType.toAscii()); + + QMailMessagePart part(QMailMessagePart::fromFile(filename, cd, ct, QMailMessageBody::Base64, QMailMessageBody::RequiresEncoding)); + d_ptr->_message.appendPart(part); + } + } +} + +void QMessage::clearAttachments() +{ + QMessageContentContainerId textId(bodyId()); + QMailMessagePart::Location textLocation(convert(textId)); + + for (uint i = d_ptr->_message.partCount(); i > 0; --i) { + QMailMessagePart &part = d_ptr->_message.partAt(i - 1); + if (!(part.location() == textLocation)) { + // Ensure that this part does not contain the text part + PartLocator locator(textLocation); + part.foreachPart(locator); + if (locator._part == 0) { + d_ptr->_message.removePartAt(i - 1); + } + } + } +} + +bool QMessage::isModified() const +{ + return (d_ptr->_message.dataModified() || d_ptr->_message.contentModified()); +} + +QMessage QMessage::createResponseMessage(ResponseType type) const +{ + QMessage response; + + if (type == Forward) { + QString subject(d_ptr->_message.subject()); + response.setSubject("Fwd:" + subject); + + if (d_ptr->_message.contentType().type().toLower() == "text") { + // Forward the text content inline + QString existingText = d_ptr->_message.body().data(); + + QString prefix("\r\n----- Forwarded Message -----\r\n\r\n"); + prefix.append(QString("%1: %2\r\n").arg(qApp->translate("QMessage", "Subject")).arg(subject)); + prefix.append(QString("%1: %2\r\n").arg(qApp->translate("QMessage", "Date")).arg(date().toString())); + prefix.append(QString("%1: %2\r\n").arg(qApp->translate("QMessage", "From")).arg(d_ptr->_message.from().toString())); + + QStringList addresses; + foreach (const QMailAddress &address, d_ptr->_message.to()) { + addresses.append(address.toString()); + } + + prefix.append(QString("%1: %2\r\n").arg(qApp->translate("QMessage", "To")).arg(addresses.join(","))); + + QString postfix("\r\n\r\n-----------------------------\r\n"); + + response.setBody(prefix + existingText + postfix); + } else { + if (QMailMessage *msg = convert(&response)) { + msg->setMultipartType(QMailMessage::MultipartMixed); + + QMailMessageContentDisposition cd(QMailMessageContentDisposition::Inline); + + { + // Add an empty text body to be composed into + QMailMessageContentType ct("text/plain"); + QMailMessagePart part(QMailMessagePart::fromData(QString(), cd, ct, QMailMessageBody::Base64)); + msg->appendPart(part); + } + + { + // Include the entirety of this message as a nested part + QMailMessageContentType ct("message/rfc822"); + QByteArray responseData(d_ptr->_message.toRfc2822(QMailMessage::TransmissionFormat)); + QMailMessagePart part(QMailMessagePart::fromData(responseData, cd, ct, QMailMessageBody::Base64)); + msg->appendPart(part); + } + } + } + } else { + if (QMailMessage *msg = convert(&response)) { + QMailAddress to(d_ptr->_message.replyTo()); + if (to.address().isEmpty()) { + to = d_ptr->_message.from(); + } + response.setTo(convert(to)); + + if (type == ReplyToAll) { + QList cc; + foreach (const QMailAddress &address, d_ptr->_message.to() + d_ptr->_message.cc()) { + cc.append(convert(address)); + } + + response.setCc(cc); + } + + QString subject(d_ptr->_message.subject()); + response.setSubject("Re:" + subject); + + QString messageId(d_ptr->_message.headerFieldText("Message-Id")); + QString references(d_ptr->_message.headerFieldText("References")); + + if (!messageId.isEmpty()) { + if (!references.isEmpty()) { + references.append(' '); + } + references.append(messageId); + + msg->setHeaderField("In-Reply-To", messageId); + } + if (!references.isEmpty()) { + msg->setHeaderField("References", references); + } + + QString existingText; + QMessageContentContainerIdList attachments; + + if (d_ptr->_message.contentType().type().toLower() == "text") { + existingText = d_ptr->_message.body().data(); + } else { + // Is there any text in this message? + QMessageContentContainerId textId(bodyId()); + if (textId.isValid()) { + QMessageContentContainer textPart(find(textId)); + existingText = textPart.textContent(); + } + + // Find the remaining parts of the message + attachments = attachmentIds(); + } + + if (!existingText.isEmpty()) { + existingText = existingText.replace("\n", "\n> "); + + QString prefix(qApp->translate("QMessage", "On %1 you wrote:\n> ")); + prefix = prefix.arg(d_ptr->_message.date().toLocalTime().toString()); + response.setBody(prefix + existingText); + } + + foreach (const QMessageContentContainerId &attachmentId, attachments) { + QMessageContentContainer attachment(find(attachmentId)); + msg->appendPart(attachment.d_ptr->_part); + } + } + } + + return response; +} + + +QTM_END_NAMESPACE