diff options
Diffstat (limited to 'mailnews/compose/src/nsMsgCompFields.cpp')
-rw-r--r-- | mailnews/compose/src/nsMsgCompFields.cpp | 693 |
1 files changed, 693 insertions, 0 deletions
diff --git a/mailnews/compose/src/nsMsgCompFields.cpp b/mailnews/compose/src/nsMsgCompFields.cpp new file mode 100644 index 000000000..c65e6ca17 --- /dev/null +++ b/mailnews/compose/src/nsMsgCompFields.cpp @@ -0,0 +1,693 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsMsgCompose.h" +#include "nsMsgCompFields.h" +#include "nsMsgI18N.h" +#include "nsMsgCompUtils.h" +#include "nsMsgUtils.h" +#include "prmem.h" +#include "nsIFileChannel.h" +#include "nsIMsgAttachment.h" +#include "nsIMsgMdnGenerator.h" +#include "nsServiceManagerUtils.h" +#include "nsMsgMimeCID.h" +#include "nsArrayEnumerator.h" +#include "nsMemory.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/mailnews/MimeHeaderParser.h" + +using namespace mozilla::mailnews; + +struct HeaderInfo { + /// Header name + const char *mName; + /// If true, nsMsgCompFields should reflect the raw header value instead of + /// the unstructured header value. + bool mStructured; +}; + +// This is a mapping of the m_headers local set to the actual header name we +// store on the structured header object. +static HeaderInfo kHeaders[] = { + { "From", true }, + { "Reply-To", true }, + { "To", true }, + { "Cc", true }, + { "Bcc", true }, + { nullptr, false }, // FCC + { nullptr, false }, // FCC2 + { "Newsgroups", true }, + { "Followup-To", true }, + { "Subject", false }, + { "Organization", false }, + { "References", true }, + { "X-Mozilla-News-Host", false }, + { "X-Priority", false }, + { nullptr, false }, // CHARACTER_SET + { "Message-Id", true }, + { "X-Template", true }, + { nullptr, false }, // DRAFT_ID + { "Content-Language", true }, + { nullptr, false } // CREATOR IDENTITY KEY +}; + +static_assert(MOZ_ARRAY_LENGTH(kHeaders) == + nsMsgCompFields::MSG_MAX_HEADERS, + "These two arrays need to be kept in sync or bad things will happen!"); + +NS_IMPL_ISUPPORTS(nsMsgCompFields, nsIMsgCompFields, msgIStructuredHeaders, + msgIWritableStructuredHeaders) + +nsMsgCompFields::nsMsgCompFields() +: mStructuredHeaders(do_CreateInstance(NS_ISTRUCTUREDHEADERS_CONTRACTID)) +{ + m_body.Truncate(); + + m_attachVCard = false; + m_forcePlainText = false; + m_useMultipartAlternative = false; + m_returnReceipt = false; + m_receiptHeaderType = nsIMsgMdnGenerator::eDntType; + m_DSN = false; + m_bodyIsAsciiOnly = false; + m_forceMsgEncoding = false; + m_needToCheckCharset = true; + m_attachmentReminder = false; + m_deliveryFormat = nsIMsgCompSendFormat::AskUser; + + // Get the default charset from pref, use this as a mail charset. + nsString charset; + NS_GetLocalizedUnicharPreferenceWithDefault(nullptr, "mailnews.send_default_charset", + NS_LITERAL_STRING("UTF-8"), charset); + + LossyCopyUTF16toASCII(charset, m_DefaultCharacterSet); // Charsets better be ASCII + SetCharacterSet(m_DefaultCharacterSet.get()); +} + +nsMsgCompFields::~nsMsgCompFields() +{ +} + +nsresult nsMsgCompFields::SetAsciiHeader(MsgHeaderID header, const char *value) +{ + NS_ASSERTION(header >= 0 && header < MSG_MAX_HEADERS, + "Invalid message header index!"); + + // If we are storing this on the structured header object, we need to set the + // value on that object as well. Note that the value may be null, which we'll + // take as an attempt to delete the header. + const char *headerName = kHeaders[header].mName; + if (headerName) + { + if (!value || !*value) + return mStructuredHeaders->DeleteHeader(headerName); + + return mStructuredHeaders->SetRawHeader(headerName, + nsDependentCString(value), "UTF-8"); + } + + // Not on the structurd header object, so save it locally. + m_headers[header] = value; + + return NS_OK; +} + +const char* nsMsgCompFields::GetAsciiHeader(MsgHeaderID header) +{ + NS_ASSERTION(header >= 0 && header < MSG_MAX_HEADERS, + "Invalid message header index!"); + + const char *headerName = kHeaders[header].mName; + if (headerName) + { + // We may be out of sync with the structured header object. Retrieve the + // header value. + if (kHeaders[header].mStructured) + { + mStructuredHeaders->GetRawHeader(headerName, m_headers[header]); + } + else + { + nsString value; + mStructuredHeaders->GetUnstructuredHeader(headerName, value); + CopyUTF16toUTF8(value, m_headers[header]); + } + } + + return m_headers[header].get(); +} + +nsresult nsMsgCompFields::SetUnicodeHeader(MsgHeaderID header, const nsAString& value) +{ + return SetAsciiHeader(header, NS_ConvertUTF16toUTF8(value).get()); +} + +nsresult nsMsgCompFields::GetUnicodeHeader(MsgHeaderID header, nsAString& aResult) +{ + CopyUTF8toUTF16(nsDependentCString(GetAsciiHeader(header)), aResult); + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetFrom(const nsAString &value) +{ + return SetUnicodeHeader(MSG_FROM_HEADER_ID, value); +} + + +NS_IMETHODIMP nsMsgCompFields::GetFrom(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_FROM_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetReplyTo(const nsAString &value) +{ + return SetUnicodeHeader(MSG_REPLY_TO_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetReplyTo(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_REPLY_TO_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetTo(const nsAString &value) +{ + return SetUnicodeHeader(MSG_TO_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetTo(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_TO_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetCc(const nsAString &value) +{ + return SetUnicodeHeader(MSG_CC_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetCc(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_CC_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetBcc(const nsAString &value) +{ + return SetUnicodeHeader(MSG_BCC_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetBcc(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_BCC_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetFcc(const nsAString &value) +{ + return SetUnicodeHeader(MSG_FCC_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetFcc(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_FCC_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetFcc2(const nsAString &value) +{ + return SetUnicodeHeader(MSG_FCC2_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetFcc2(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_FCC2_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetNewsgroups(const nsAString &aValue) +{ + return SetUnicodeHeader(MSG_NEWSGROUPS_HEADER_ID, aValue); +} + +NS_IMETHODIMP nsMsgCompFields::GetNewsgroups(nsAString &aGroup) +{ + return GetUnicodeHeader(MSG_NEWSGROUPS_HEADER_ID, aGroup); +} + +NS_IMETHODIMP nsMsgCompFields::SetFollowupTo(const nsAString &aValue) +{ + return SetUnicodeHeader(MSG_FOLLOWUP_TO_HEADER_ID, aValue); +} + +NS_IMETHODIMP nsMsgCompFields::GetFollowupTo(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_FOLLOWUP_TO_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::GetHasRecipients(bool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = NS_SUCCEEDED(mime_sanity_check_fields_recipients( + GetTo(), GetCc(), GetBcc(), GetNewsgroups())); + + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetCreatorIdentityKey(const char *value) +{ + return SetAsciiHeader(MSG_CREATOR_IDENTITY_KEY_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetCreatorIdentityKey(char **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = strdup(GetAsciiHeader(MSG_CREATOR_IDENTITY_KEY_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetSubject(const nsAString &value) +{ + return SetUnicodeHeader(MSG_SUBJECT_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetSubject(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_SUBJECT_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetOrganization(const nsAString &value) +{ + return SetUnicodeHeader(MSG_ORGANIZATION_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetOrganization(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_ORGANIZATION_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetReferences(const char *value) +{ + return SetAsciiHeader(MSG_REFERENCES_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetReferences(char **_retval) +{ + *_retval = strdup(GetAsciiHeader(MSG_REFERENCES_HEADER_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetNewspostUrl(const char *value) +{ + return SetAsciiHeader(MSG_NEWSPOSTURL_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetNewspostUrl(char **_retval) +{ + *_retval = strdup(GetAsciiHeader(MSG_NEWSPOSTURL_HEADER_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetPriority(const char *value) +{ + return SetAsciiHeader(MSG_PRIORITY_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetPriority(char **_retval) +{ + *_retval = strdup(GetAsciiHeader(MSG_PRIORITY_HEADER_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetCharacterSet(const char *value) +{ + return SetAsciiHeader(MSG_CHARACTER_SET_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetCharacterSet(char **_retval) +{ + *_retval = strdup(GetAsciiHeader(MSG_CHARACTER_SET_HEADER_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetMessageId(const char *value) +{ + return SetAsciiHeader(MSG_MESSAGE_ID_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetMessageId(char **_retval) +{ + *_retval = strdup(GetAsciiHeader(MSG_MESSAGE_ID_HEADER_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetTemplateName(const nsAString &value) +{ + return SetUnicodeHeader(MSG_X_TEMPLATE_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetTemplateName(nsAString &_retval) +{ + return GetUnicodeHeader(MSG_X_TEMPLATE_HEADER_ID, _retval); +} + +NS_IMETHODIMP nsMsgCompFields::SetDraftId(const char *value) +{ + return SetAsciiHeader(MSG_DRAFT_ID_HEADER_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetDraftId(char **_retval) +{ + *_retval = strdup(GetAsciiHeader(MSG_DRAFT_ID_HEADER_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetReturnReceipt(bool value) +{ + m_returnReceipt = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetReturnReceipt(bool *_retval) +{ + *_retval = m_returnReceipt; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetReceiptHeaderType(int32_t value) +{ + m_receiptHeaderType = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetReceiptHeaderType(int32_t *_retval) +{ + *_retval = m_receiptHeaderType; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetDSN(bool value) +{ + m_DSN = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetDSN(bool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = m_DSN; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetAttachVCard(bool value) +{ + m_attachVCard = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetAttachVCard(bool *_retval) +{ + *_retval = m_attachVCard; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetAttachmentReminder(bool *_retval) +{ + *_retval = m_attachmentReminder; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetAttachmentReminder(bool value) +{ + m_attachmentReminder = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetDeliveryFormat(int32_t value) +{ + switch (value) { + case nsIMsgCompSendFormat::AskUser: + case nsIMsgCompSendFormat::PlainText: + case nsIMsgCompSendFormat::HTML: + case nsIMsgCompSendFormat::Both: + m_deliveryFormat = value; + break; + default: + m_deliveryFormat = nsIMsgCompSendFormat::AskUser; + } + + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetDeliveryFormat(int32_t *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = m_deliveryFormat; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetContentLanguage(const char *value) +{ + return SetAsciiHeader(MSG_CONTENT_LANGUAGE_ID, value); +} + +NS_IMETHODIMP nsMsgCompFields::GetContentLanguage(char **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = strdup(GetAsciiHeader(MSG_CONTENT_LANGUAGE_ID)); + return *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::SetForcePlainText(bool value) +{ + m_forcePlainText = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetForcePlainText(bool *_retval) +{ + *_retval = m_forcePlainText; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetForceMsgEncoding(bool value) +{ + m_forceMsgEncoding = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetForceMsgEncoding(bool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = m_forceMsgEncoding; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetUseMultipartAlternative(bool value) +{ + m_useMultipartAlternative = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetUseMultipartAlternative(bool *_retval) +{ + *_retval = m_useMultipartAlternative; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetBodyIsAsciiOnly(bool value) +{ + m_bodyIsAsciiOnly = value; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetBodyIsAsciiOnly(bool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = m_bodyIsAsciiOnly; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetBody(const nsAString &value) +{ + CopyUTF16toUTF8(value, m_body); + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetBody(nsAString &_retval) +{ + CopyUTF8toUTF16(m_body, _retval); + return NS_OK; +} + +nsresult nsMsgCompFields::SetBody(const char *value) +{ + if (value) + m_body = value; + else + m_body.Truncate(); + return NS_OK; +} + +const char* nsMsgCompFields::GetBody() +{ + return m_body.get(); +} + +/* readonly attribute nsISimpleEnumerator attachmentsArray; */ +NS_IMETHODIMP nsMsgCompFields::GetAttachments(nsISimpleEnumerator * *aAttachmentsEnum) +{ + return aAttachmentsEnum ? NS_NewArrayEnumerator(aAttachmentsEnum, m_attachments) : NS_ERROR_NULL_POINTER; +} + +/* void addAttachment (in nsIMsgAttachment attachment); */ +NS_IMETHODIMP nsMsgCompFields::AddAttachment(nsIMsgAttachment *attachment) +{ + int32_t attachmentCount = m_attachments.Count(); + + //Don't add twice the same attachment. + nsCOMPtr<nsIMsgAttachment> element; + bool sameUrl; + for (int32_t i = 0; i < attachmentCount; i ++) + { + m_attachments[i]->EqualsUrl(attachment, &sameUrl); + if (sameUrl) + return NS_OK; + } + m_attachments.AppendObject(attachment); + + return NS_OK; +} + +/* void removeAttachment (in nsIMsgAttachment attachment); */ +NS_IMETHODIMP nsMsgCompFields::RemoveAttachment(nsIMsgAttachment *attachment) +{ + int32_t attachmentCount = m_attachments.Count(); + + nsCOMPtr<nsIMsgAttachment> element; + bool sameUrl; + for (int32_t i = 0; i < attachmentCount; i ++) + { + m_attachments[i]->EqualsUrl(attachment, &sameUrl); + if (sameUrl) + { + m_attachments.RemoveObjectAt(i); + break; + } + } + + return NS_OK; +} + +/* void removeAttachments (); */ +NS_IMETHODIMP nsMsgCompFields::RemoveAttachments() +{ + m_attachments.Clear(); + + return NS_OK; +} + + +// This method is called during the creation of a new window. +NS_IMETHODIMP +nsMsgCompFields::SplitRecipients(const nsAString &aRecipients, + bool aEmailAddressOnly, + uint32_t *aLength, + char16_t*** aResult) +{ + NS_ENSURE_ARG_POINTER(aLength); + NS_ENSURE_ARG_POINTER(aResult); + + *aLength = 0; + *aResult = nullptr; + + nsCOMArray<msgIAddressObject> header(EncodedHeader(NS_ConvertUTF16toUTF8(aRecipients))); + nsTArray<nsString> results; + if (aEmailAddressOnly) + ExtractEmails(header, results); + else + ExtractDisplayAddresses(header, results); + + uint32_t count = results.Length(); + char16_t **result = (char16_t **)NS_Alloc(sizeof(char16_t *) * count); + for (uint32_t i = 0; i < count; ++i) + result[i] = ToNewUnicode(results[i]); + + *aResult = result; + *aLength = count; + return NS_OK; +} + + +// This method is called during the sending of message from nsMsgCompose::CheckAndPopulateRecipients() +nsresult nsMsgCompFields::SplitRecipientsEx(const nsAString &recipients, + nsTArray<nsMsgRecipient> &aResult) +{ + nsTArray<nsString> names, addresses; + ExtractAllAddresses(EncodedHeader(NS_ConvertUTF16toUTF8(recipients)), names, + addresses); + + uint32_t numAddresses = names.Length(); + for (uint32_t i = 0; i < numAddresses; ++i) + { + nsMsgRecipient msgRecipient; + msgRecipient.mEmail = addresses[i]; + msgRecipient.mName = names[i]; + aResult.AppendElement(msgRecipient); + } + + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::ConvertBodyToPlainText() +{ + nsresult rv = NS_OK; + + if (!m_body.IsEmpty()) + { + nsAutoString body; + rv = GetBody(body); + if (NS_SUCCEEDED(rv)) + { + bool flowed, delsp, formatted, disallowBreaks; + GetSerialiserFlags(GetCharacterSet(), &flowed, &delsp, &formatted, &disallowBreaks); + rv = ConvertBufToPlainText(body, flowed, delsp, formatted, disallowBreaks); + if (NS_SUCCEEDED(rv)) + rv = SetBody(body); + } + } + return rv; +} + +NS_IMETHODIMP nsMsgCompFields::GetSecurityInfo(nsISupports ** aSecurityInfo) +{ + NS_ENSURE_ARG_POINTER(aSecurityInfo); + *aSecurityInfo = mSecureCompFields; + NS_IF_ADDREF(*aSecurityInfo); + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetSecurityInfo(nsISupports * aSecurityInfo) +{ + mSecureCompFields = aSecurityInfo; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::GetDefaultCharacterSet(char * *aDefaultCharacterSet) +{ + NS_ENSURE_ARG_POINTER(aDefaultCharacterSet); + *aDefaultCharacterSet = ToNewCString(m_DefaultCharacterSet); + return *aDefaultCharacterSet ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP nsMsgCompFields::GetNeedToCheckCharset(bool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = m_needToCheckCharset; + return NS_OK; +} + +NS_IMETHODIMP nsMsgCompFields::SetNeedToCheckCharset(bool aCheck) +{ + m_needToCheckCharset = aCheck; + return NS_OK; +} |