Bug 842632, part 1: Distinguish between building address strings for display or MIME, r=IanN, sr=Neil.

This commit is contained in:
Joshua Cranmer 2013-12-11 13:19:44 -06:00
Родитель 715113a724
Коммит 9899eef9af
23 изменённых файлов: 398 добавлений и 199 удалений

Просмотреть файл

@ -549,7 +549,7 @@ function GenerateAddressFromCard(card)
else
email = card.primaryEmail;
return MailServices.headerParser.makeFullAddress(card.displayName, email);
return MailServices.headerParser.makeMimeAddress(card.displayName, email);
}
function GetDirectoryFromURI(uri)

Просмотреть файл

@ -144,7 +144,12 @@ function Recipients2CompFields(msgCompFields)
case "addr_bcc" :
case "addr_reply" :
try {
recipient = MailServices.headerParser.reformatUnquotedAddresses(fieldValue);
let headerParser = MailServices.headerParser;
recipient = [headerParser.makeMimeAddress(fullValue.name,
fullValue.email) for
(fullValue of
headerParser.makeFromDisplayAddress(fieldValue, {}))]
.join(", ");
} catch (ex) {recipient = fieldValue;}
break;
}
@ -289,18 +294,8 @@ function awSetInputAndPopupFromArray(inputArray, popupValue, parentNode, templat
{
if (popupValue)
{
var recipient;
for (var index = 0; index < inputArray.length; index++)
{
recipient = null;
try {
recipient =
MailServices.headerParser.unquotePhraseOrAddrWString(inputArray[index], true);
} catch (ex) {};
if (!recipient)
recipient = inputArray[index];
for (let recipient of inputArray)
_awSetInputAndPopup(recipient, popupValue, parentNode, templateNode);
}
}
}

Просмотреть файл

@ -112,19 +112,17 @@ function GetListValue(mailList, doAdd)
cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
if (cardproperty)
{
var addresses = {};
var names = {};
var fullNames = {};
var numAddresses = MailServices.headerParser.parseHeadersWithArray(fieldValue, addresses, names, fullNames);
for (var j = 0; j < numAddresses; j++)
let addrObjects = MailServices.headerParser
.makeFromDisplayAddress(fieldValue, {});
for (let j = 0; j < addrObjects.length; j++)
{
if (j > 0)
{
cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
}
cardproperty.primaryEmail = addresses.value[j];
cardproperty.displayName = names.value[j];
cardproperty.primaryEmail = addrObjects[j].email;
cardproperty.displayName = addrObjects[j].name || addrObjects[j].email;
if (doAdd || (doAdd == false && pos >= oldTotal))
mailList.addressLists.appendElement(cardproperty, false);
@ -270,8 +268,8 @@ function OnLoadEditList()
for (let i = 0; i < total; i++)
{
let card = gEditList.addressLists.queryElementAt(i, Components.interfaces.nsIAbCard);
let address = MailServices.headerParser.makeFullAddress(card.displayName,
card.primaryEmail);
let address = MailServices.headerParser.makeMailboxObject(
card.displayName, card.primaryEmail).toString();
SetInputValue(address, newListBoxNode, templateNode);
}
listbox.parentNode.replaceChild(newListBoxNode, listbox);
@ -535,12 +533,22 @@ function DropOnAddressListTree(event)
function DropListAddress(target, address)
{
awClickEmptySpace(target, true); //that will automatically set the focus on a new available row, and make sure is visible
if (top.MAX_RECIPIENTS == 0)
// Set focus on a new available, visible row.
awClickEmptySpace(target, true);
if (top.MAX_RECIPIENTS == 0)
top.MAX_RECIPIENTS = 1;
var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
lastInput.value = address;
// Break apart the MIME-ready header address into individual addressees to
// add to the dialog.
let addresses = {}, names = {}, fullNames = {};
MailServices.headerParser.parseHeadersWithArray(address, addresses, names,
fullNames);
for (let full of fullNames.value)
{
let lastInput = awGetInputElement(top.MAX_RECIPIENTS);
lastInput.value = full;
awAppendNewRow(true);
}
}
/* Allows extensions to register a listener function for

Просмотреть файл

@ -291,16 +291,10 @@ nsAbAutoCompleteSearch.prototype = {
_addToResult: function _addToResult(commentColumn, directory, card,
emailToUse, isPrimaryEmail, result) {
var emailAddress =
this._parser.makeFullAddress(card.displayName,
card.isMailList ?
card.getProperty("Notes", "") || card.displayName :
emailToUse);
// The old code used to try it manually. I think if the parser can't work
// out the address from what we've supplied, then its busted and we're not
// going to do any better doing it manually.
if (!emailAddress)
return;
this._parser.makeMailboxObject(card.displayName,
card.isMailList ?
card.getProperty("Notes", "") || card.displayName :
emailToUse).toString();
// If it is a duplicate, then just return and don't add it. The
// _checkDuplicate function deals with it all for us.

Просмотреть файл

@ -112,15 +112,11 @@ nsAbLDAPAutoCompleteSearch.prototype = {
},
_addToResult: function _addToResult(card) {
var emailAddress =
this._parser.makeFullAddress(card.displayName, card.isMailList ?
card.getProperty("Notes", "") || card.displayName : card.primaryEmail);
// The old code used to try it manually. I think if the parser can't work
// out the address from what we've supplied, then its busted and we're not
// going to do any better doing it manually.
if (!emailAddress)
return;
let emailAddress =
this._parser.makeMailboxObject(card.displayName,
card.isMailList ?
card.getProperty("Notes", "") || card.displayName :
card.primaryEmail).toString();
// If it is a duplicate, then just return and don't add it. The
// _checkDuplicate function deals with it all for us.

Просмотреть файл

@ -16,6 +16,9 @@
#include "nsIMimeConverter.h"
#include "nsArrayEnumerator.h"
#include "nsMemory.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
using namespace mozilla::mailnews;
/* the following macro actually implement addref, release and query interface for our component. */
NS_IMPL_ISUPPORTS1(nsMsgCompFields, nsIMsgCompFields)
@ -540,25 +543,19 @@ nsMsgCompFields::SplitRecipients(const nsAString &aRecipients,
for (i = 0; i < numAddresses; ++i)
{
nsCString fullAddress;
nsAutoString recipient;
if (!aEmailAddressOnly)
{
nsCString decodedName;
converter->DecodeMimeHeaderToUTF8(nsDependentCString(pNames),
GetCharacterSet(), false, true,
decodedName);
rv = parser->MakeFullAddressString((!decodedName.IsEmpty() ?
decodedName.get() : pNames),
pAddresses,
getter_Copies(fullAddress));
nsString decodedName;
converter->DecodeMimeHeader(pNames, GetCharacterSet(), false, true,
decodedName);
if (decodedName.IsEmpty())
CopyUTF8toUTF16(pNames, decodedName);
MakeDisplayAddress(decodedName, NS_ConvertUTF8toUTF16(pAddresses),
recipient);
}
if (NS_SUCCEEDED(rv) && !aEmailAddressOnly)
rv = ConvertToUnicode("UTF-8", fullAddress, recipient);
else
rv = ConvertToUnicode("UTF-8", nsDependentCString(pAddresses), recipient);
if (NS_FAILED(rv))
break;
CopyUTF8toUTF16(pAddresses, recipient);
result[i] = ToNewUnicode(recipient);
if (!result[i])
@ -621,18 +618,13 @@ nsresult nsMsgCompFields::SplitRecipientsEx(const nsAString &recipients,
converter->DecodeMimeHeaderToUTF8(nsDependentCString(pNames),
GetCharacterSet(), false, true,
decodedName);
rv = parser->MakeFullAddressString((!decodedName.IsEmpty() ?
decodedName.get() : pNames),
pAddresses,
getter_Copies(fullAddress));
if (decodedName.IsEmpty())
decodedName.Assign(pNames);
MakeMimeAddress(decodedName, nsDependentCString(pAddresses), fullAddress);
nsMsgRecipient msgRecipient;
rv = ConvertToUnicode("UTF-8",
NS_SUCCEEDED(rv) ? fullAddress.get() : pAddresses,
msgRecipient.mAddress);
if (NS_FAILED(rv))
return rv;
CopyUTF8toUTF16(fullAddress, msgRecipient.mAddress);
rv = ConvertToUnicode("UTF-8", pAddresses, msgRecipient.mEmail);
if (NS_FAILED(rv))

Просмотреть файл

@ -78,8 +78,11 @@
#include "nsIAbManager.h"
#include "nsCRT.h"
#include "mozilla/Services.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
#include "nsISelection.h"
using namespace mozilla::mailnews;
static void GetReplyHeaderInfo(int32_t* reply_header_type,
nsString& reply_header_locale,
nsString& reply_header_authorwrote,
@ -1048,12 +1051,7 @@ nsresult nsMsgCompose::_SendMsg(MSG_DeliverMode deliverMode, nsIMsgIdentity *ide
identity->GetOrganization(organization);
nsCString sender;
nsCOMPtr<nsIMsgHeaderParser> parser (do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID));
if (parser) {
// convert to UTF8 before passing to MakeFullAddressString
parser->MakeFullAddressString(NS_ConvertUTF16toUTF8(fullName).get(),
email.get(), getter_Copies(sender));
}
MakeMimeAddress(NS_ConvertUTF16toUTF8(fullName), email, sender);
m_compFields->SetFrom(sender.IsEmpty() ? email.get() : sender.get());
m_compFields->SetOrganization(organization);
@ -4757,9 +4755,8 @@ nsMsgCompose::CheckAndPopulateRecipients(bool aPopulateMailList,
if (NS_FAILED(rv))
return rv;
if (parser)
parser->MakeFullAddress(pDisplayName, newRecipient.mEmail,
newRecipient.mAddress);
MakeMimeAddress(pDisplayName, newRecipient.mEmail,
newRecipient.mAddress);
if (newRecipient.mAddress.IsEmpty())
{
@ -5412,16 +5409,13 @@ NS_IMETHODIMP nsMsgCompose::CheckCharsetConversion(nsIMsgIdentity *identity, cha
nsMsgMailList::nsMsgMailList(nsIAbDirectory* directory) :
mDirectory(directory)
{
nsCOMPtr<nsIMsgHeaderParser> parser (do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID));
nsString listName, listDescription;
mDirectory->GetDirName(listName);
mDirectory->GetDescription(listDescription);
if (parser)
parser->MakeFullAddress(listName,
listDescription.IsEmpty() ? listName : listDescription,
mFullName);
MakeDisplayAddress(listName,
listDescription.IsEmpty() ? listName : listDescription,
mFullName);
if (mFullName.IsEmpty())
{

Просмотреть файл

@ -44,6 +44,7 @@
#include "nsIMsgWindow.h"
#include "MailNewsTypes2.h" // for nsMsgSocketType and nsMsgAuthMethod
#include "nsIIDNService.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
#include "mozilla/Services.h"
#include "nsINetAddr.h"
@ -55,6 +56,8 @@
static PRLogModuleInfo *SMTPLogModule = nullptr;
using namespace mozilla::mailnews;
/* the output_buffer_size must be larger than the largest possible line
* 2000 seems good for news
*
@ -604,17 +607,9 @@ nsresult nsSmtpProtocol::SendHeloResponse(nsIInputStream * inputStream, uint32_t
return(NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS);
}
nsCOMPtr<nsIMsgHeaderParser> parser = do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID);
nsCString fullAddress;
if (parser)
{
// pass nullptr for the name, since we just want the email.
//
// seems a little weird that we are passing in the emailAddress
// when that's the out parameter
parser->MakeFullAddressString(nullptr, emailAddress.get(),
getter_Copies(fullAddress));
}
// Quote the email address before passing it to the SMTP server.
MakeMimeAddress(EmptyCString(), emailAddress, fullAddress);
buffer = "MAIL FROM:<";
buffer += fullAddress;

Просмотреть файл

@ -18,7 +18,7 @@ const splitRecipientsTests =
{ recipients: '"foo bar" <me@foo.invalid>',
emailAddressOnly: false,
count: 1,
result: [ '"foo bar" <me@foo.invalid>' ]
result: [ 'foo bar <me@foo.invalid>' ]
},
{ recipients: '"foo bar" <me@foo.invalid>',
emailAddressOnly: true,
@ -28,7 +28,7 @@ const splitRecipientsTests =
{ recipients: '"foo bar" <me@foo.invalid>, "bar foo" <me2@foo.invalid>',
emailAddressOnly: false,
count: 2,
result: [ '"foo bar" <me@foo.invalid>', '"bar foo" <me2@foo.invalid>' ]
result: [ 'foo bar <me@foo.invalid>', 'bar foo <me2@foo.invalid>' ]
},
{ recipients: '"foo bar" <me@foo.invalid>, "bar foo" <me2@foo.invalid>',
emailAddressOnly: true,
@ -63,7 +63,7 @@ const splitRecipientsTests =
{ recipients: '"A " <a@xxx.invalid>; b@xxx.invalid',
emailAddressOnly: false,
count: 2,
result: [ '"A " <a@xxx.invalid>', "b@xxx.invalid" ]
result: [ 'A <a@xxx.invalid>', "b@xxx.invalid" ]
},
{ recipients: 'A <a@xxx.invalid>; B <b@xxx.invalid>',
emailAddressOnly: false,
@ -73,12 +73,12 @@ const splitRecipientsTests =
{ recipients: "A (this: is, a comment;) <a.invalid>; g: (this: is, <a> comment;) C <c.invalid>, d.invalid;",
emailAddressOnly: false,
count: 3,
result: [ '"A (this: is, a comment;)" <a.invalid>', '"g: (this: is, <a> comment;) C" <c.invalid>', "d.invalid" ]
result: [ 'A (this: is, a comment;) <a.invalid>', 'g: (this: is, <a> comment;) C <c.invalid>', "d.invalid" ]
},
{ recipients: 'Mary Smith <mary@x.invalid>, extra:;, group:jdoe@example.invalid; Who? <one@y.invalid>; <boss@nil.invalid>, "Giant; \"Big\" Box" <sysservices@example.invalid>, ',
{ recipients: 'Mary Smith <mary@x.invalid>, extra:;, group:jdoe@example.invalid; Who? <one@y.invalid>; <boss@nil.invalid>, "Giant; \\"Big\\" Box" <sysservices@example.invalid>, ',
emailAddressOnly: false,
count: 6,
result: [ "Mary Smith <mary@x.invalid>", "extra:;", "group:jdoe@example.invalid;", "Who? <one@y.invalid>", "boss@nil.invalid", '"Giant; \"Big\" Box" <sysservices@example.invalid>' ]
result: [ "Mary Smith <mary@x.invalid>", "extra:;", "group:jdoe@example.invalid;", "Who? <one@y.invalid>", "boss@nil.invalid", 'Giant; \"Big\" Box <sysservices@example.invalid>' ]
},
{ recipients: 'Undisclosed recipients: a@foo.invalid ;;extra:;',
emailAddressOnly: true,

Просмотреть файл

@ -4,14 +4,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
#include "nsMsgHdr.h"
#include "nsMsgDatabase.h"
#include "nsMsgUtils.h"
#include "nsIMsgHeaderParser.h"
#include "nsIMsgThread.h"
#include "nsMsgMimeCID.h"
#include "nsIMimeConverter.h"
using namespace mozilla::mailnews;
NS_IMPL_ISUPPORTS1(nsMsgHdr, nsIMsgDBHdr)
#define FLAGS_INITED 0x1
@ -404,38 +406,16 @@ nsresult nsMsgHdr::BuildRecipientsFromArray(const char *names, const char *addre
nsresult ret = NS_OK;
const char *curName = names;
const char *curAddress = addresses;
nsIMsgHeaderParser *headerParser = m_mdb->GetHeaderParser();
for (uint32_t i = 0; i < numAddresses; i++, curName += strlen(curName) + 1, curAddress += strlen(curAddress) + 1)
{
if (i > 0)
allRecipients += ", ";
if (headerParser)
{
nsCString fullAddress;
ret = headerParser->MakeFullAddressString(curName, curAddress,
getter_Copies(fullAddress));
if (NS_SUCCEEDED(ret) && !fullAddress.IsEmpty())
{
allRecipients += fullAddress;
continue;
}
}
// Just in case the parser failed...
if (strlen(curName))
{
allRecipients += curName;
allRecipients += ' ';
}
if (strlen(curAddress))
{
allRecipients += '<';
allRecipients += curAddress;
allRecipients += '>';
}
nsCString fullAddress;
MakeMimeAddress(nsDependentCString(curName),
nsDependentCString(curAddress), fullAddress);
allRecipients += fullAddress;
}
return ret;

Просмотреть файл

@ -21,7 +21,6 @@
#include "nsComposeStrings.h"
#include "nsISmtpServer.h"
#include "nsIPrompt.h"
#include "nsIMsgHeaderParser.h"
#include "nsIMsgCompUtils.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
@ -33,6 +32,9 @@
#include "mozilla/Services.h"
#include "nsIArray.h"
#include "nsArrayUtils.h"
#include "mozilla/mailnews/MimeHeaderParser.h"
using namespace mozilla::mailnews;
#define MDN_NOT_IN_TO_CC ((int) 0x0001)
#define MDN_OUTSIDE_DOMAIN ((int) 0x0002)
@ -461,16 +463,10 @@ nsresult nsMsgMdnGenerator::CreateFirstPart()
m_identity->GetFullName(fullName);
nsCString fullAddress;
nsCOMPtr<nsIMsgHeaderParser> parser (do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID));
if (parser)
{
// convert fullName to UTF8 before passing it to MakeFullAddressString
parser->MakeFullAddressString(NS_ConvertUTF16toUTF8(fullName).get(),
m_email.get(), getter_Copies(fullAddress));
}
// convert fullName to UTF8 before passing it to MakeMimeAddress
MakeMimeAddress(NS_ConvertUTF16toUTF8(fullName), m_email, fullAddress);
convbuf = nsMsgI18NEncodeMimePartIIStr(
(!fullAddress.IsEmpty()) ? fullAddress.get(): m_email.get(),
convbuf = nsMsgI18NEncodeMimePartIIStr(fullAddress.get(),
true, m_charset.get(), 0, conformToStandard);
parm = PR_smprintf("From: %s" CRLF, convbuf ? convbuf : m_email.get());

Просмотреть файл

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef MimeHeaderParser_h__
#define MimeHeaderParser_h__
#include "nsStringGlue.h"
namespace mozilla {
namespace mailnews {
/**
* Given a name and an email, both encoded in UTF-8, produce a string suitable
* for writing in an email header by quoting where necessary.
*
* If name is not empty, the output string will be name <email>. If it is empty,
* the output string is just the email. Note that this DOES NOT do any RFC 2047
* encoding.
*/
void MakeMimeAddress(const nsACString &aName, const nsACString &aEmail,
nsACString &full);
/**
* Given a name and an email, produce a string suitable for writing in an email
* header by quoting where necessary.
*
* If name is not empty, the output string will be name <email>. If it is empty,
* the output string is just the email. Note that this DOES NOT do any RFC 2047
* encoding.
*/
void MakeMimeAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full);
/**
* Given a name and an email, both encoded in UTF-8, produce a string suitable
* for displaying in UI.
*
* If name is not empty, the output string will be name <email>. If it is empty,
* the output string is just the email.
*/
void MakeDisplayAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full);
} // namespace mailnews
} // namespace mozilla
#endif

Просмотреть файл

@ -25,4 +25,5 @@ EXPORTS += [
EXPORTS.mozilla.mailnews += [
'MimeEncoder.h',
'MimeHeaderParser.h',
]

Просмотреть файл

@ -14,11 +14,43 @@ interface nsISimpleEnumerator;
"@mozilla.org/messenger/headerparser;1"
%}
/**
* A structured representation of a single address.
*
* This is meant to be correspond to the address production from RFC 5322.
*/
[scriptable, uuid(15f9cc44-afdf-48c8-9de7-3ca0f18fc3b6)]
interface msgIAddressObject : nsISupports {
/// The name of the mailbox.
readonly attribute AString name;
/// The email of the mailbox.
readonly attribute AString email;
/// Return a string form of this object that is suitable for display.
AString toString();
};
/*
* nsIMsgRFCParser Interface declaration
*/
[scriptable, uuid(a67d4d96-e5cb-458d-9311-794d5d1a9832)]
[scriptable, uuid(4da84fa8-bd45-45e7-9c98-3ba2be88343f)]
interface nsIMsgHeaderParser : nsISupports {
/// Return a structured mailbox object having the given name and email.
msgIAddressObject makeMailboxObject(in AString aName, in AString aEmail);
/**
* Return an array of structured mailbox for the given display name string.
*
* The string is expected to be a comma-separated sequence of strings that
* would be produced by msgIAddressObject::toString(). For example, the string
* "Bond, James <agent007@mi5.invalid>" would produce one address object,
* while the string "webmaster@nowhere.invalid, child@nowhere.invalid" would
* produce two address objects.
*/
void makeFromDisplayAddress(in AString aDisplayAddresses,
out unsigned long count,
[retval, array, size_is(count)] out msgIAddressObject addresses);
void parseHeadersWithArray(in wstring aLine,
[array, size_is(count)] out wstring aEmailAddresses,
@ -108,26 +140,6 @@ interface nsIMsgHeaderParser : nsISupports {
AUTF8String removeDuplicateAddresses(in AUTF8String aAddrs,
in AUTF8String aOtherAddrs);
/**
* Given an e-mail address and a person's name, cons them together into a
* single string, doing all the necessary quoting.
*
* @param aName The name of the sender.
* @param aAddress The address of the sender.
* @return A string of the form name <address>.
*/
AString makeFullAddress(in AString aName, in AString aAddress);
/**
* Given an e-mail address and a person's name, cons them together into a
* single string, doing all the necessary quoting (const char* version).
*
* @param aName The name of the sender. This should be in UTF-8.
* @param aAddress The address of the sender. This should be in UTF-8.
* @return A string of the form name <address>.
*/
[noscript] string makeFullAddressString(in string aName, in string aAddress);
/* This function removes the quoting if you want to show the
names to users. e.g. summary file, address book. If preserveIntegrity is set to true,
quote will not be removed in case the name part of the email contains a comma.
@ -137,5 +149,13 @@ interface nsIMsgHeaderParser : nsISupports {
/* Given a string, will make it safe to use by adding missing quote and escaping needed quote */
wstring reformatUnquotedAddresses(in wstring line);
/**
* Given a name and email address, produce a string that is suitable for
* emitting in a MIME header (after applying RFC 2047 encoding).
*
* @note This is a temporary method.
*/
AString makeMimeAddress(in AString aName, in AString aEmail);
};

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/mailnews/MimeHeaderParser.h"
#include "nsCOMPtr.h"
#include "nsIMsgHeaderParser.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace mailnews {
void MakeMimeAddress(const nsACString &aName, const nsACString &aEmail,
nsACString &full)
{
nsAutoString utf16Address;
MakeMimeAddress(NS_ConvertUTF8toUTF16(aName), NS_ConvertUTF8toUTF16(aEmail),
utf16Address);
CopyUTF16toUTF8(utf16Address, full);
}
void MakeMimeAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full)
{
nsCOMPtr<nsIMsgHeaderParser> headerParser =
do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID);
headerParser->MakeMimeAddress(aName, aEmail, full);
}
void MakeDisplayAddress(const nsAString &aName, const nsAString &aEmail,
nsAString &full)
{
nsCOMPtr<nsIMsgHeaderParser> headerParser =
do_GetService(NS_MAILNEWS_MIME_HEADER_PARSER_CONTRACTID);
nsCOMPtr<msgIAddressObject> object;
headerParser->MakeMailboxObject(aName, aEmail, getter_AddRefs(object));
object->ToString(full);
}
} // namespace mailnews
} // namespace mozilla

Просмотреть файл

@ -36,6 +36,7 @@ SOURCES += [
'mimeenc.cpp',
'mimeeobj.cpp',
'mimehdrs.cpp',
'MimeHeaderParser.cpp',
'mimei.cpp',
'mimeiimg.cpp',
'mimeleaf.cpp',

Просмотреть файл

@ -10,6 +10,7 @@
#include "prmem.h"
#include <ctype.h>
#include "nsAlgorithm.h"
#include "nsMsgUtils.h"
#include "nsStringGlue.h"
#include <algorithm>
@ -69,7 +70,6 @@ nsresult FillResultsArray(const char * aName, const char *aAddress, PRUnichar **
PRUnichar ** aOutgoingFullName, nsIMsgHeaderParser *aParser)
{
NS_ENSURE_ARG(aParser);
nsresult rv = NS_OK;
*aOutgoingFullName = nullptr;
*aOutgoingEmailAddress = nullptr;
@ -90,9 +90,8 @@ nsresult FillResultsArray(const char * aName, const char *aAddress, PRUnichar **
nsCString fullAddress;
nsCString unquotedAddress;
rv = aParser->MakeFullAddressString(aName, aAddress,
getter_Copies(fullAddress));
if (NS_SUCCEEDED(rv) && !fullAddress.IsEmpty())
fullAddress.Adopt(msg_make_full_address(aName, aAddress));
if (!fullAddress.IsEmpty())
{
MIME_DecodeMimeHeader(fullAddress.get(), nullptr, false, true, result);
if (!result.IsEmpty())
@ -105,7 +104,7 @@ nsresult FillResultsArray(const char * aName, const char *aAddress, PRUnichar **
else
*aOutgoingFullName = nullptr;
return rv;
return NS_OK;
}
NS_IMETHODIMP nsMsgHeaderParser::ParseHeadersWithArray(const PRUnichar * aLine, PRUnichar *** aEmailAddresses,
@ -195,16 +194,7 @@ nsMsgHeaderParser::RemoveDuplicateAddresses(const nsACString &aAddrs,
}
NS_IMETHODIMP
nsMsgHeaderParser::MakeFullAddressString(const char *aName,
const char *aAddress, char **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = msg_make_full_address(aName, aAddress);
return NS_OK;
}
NS_IMETHODIMP
nsMsgHeaderParser::MakeFullAddress(const nsAString &aName,
nsMsgHeaderParser::MakeMimeAddress(const nsAString &aName,
const nsAString &aAddress, nsAString &aResult)
{
nsCString utf8Str;
@ -1563,3 +1553,117 @@ msg_make_full_address(const char* name, const char* addr)
buf = (char *)PR_Realloc (buf, L);
return buf;
}
class MsgAddressObject MOZ_FINAL : public msgIAddressObject
{
public:
NS_DECL_ISUPPORTS
NS_DECL_MSGIADDRESSOBJECT
MsgAddressObject(const nsAString &aName, const nsAString &aEmail);
private:
nsString mName;
nsString mEmail;
};
MsgAddressObject::MsgAddressObject(const nsAString &aName,
const nsAString &aEmail)
: mName(aName),
mEmail(aEmail)
{
}
NS_IMPL_ISUPPORTS1(MsgAddressObject, msgIAddressObject)
NS_IMETHODIMP MsgAddressObject::GetName(nsAString &name)
{
name = mName;
return NS_OK;
}
NS_IMETHODIMP MsgAddressObject::GetEmail(nsAString &email)
{
email = mEmail;
return NS_OK;
}
NS_IMETHODIMP MsgAddressObject::ToString(nsAString &display)
{
nsMsgHeaderParser headerParser;
nsAutoString quotedString;
headerParser.MakeMimeAddress(mName, mEmail, quotedString);
headerParser.UnquotePhraseOrAddrWString(quotedString.get(), false,
getter_Copies(display));
return NS_OK;
}
NS_IMETHODIMP nsMsgHeaderParser::MakeMailboxObject(const nsAString &aName,
const nsAString &aEmail, msgIAddressObject **retval)
{
nsCOMPtr<msgIAddressObject> object = new MsgAddressObject(aName, aEmail);
object.forget(retval);
return NS_OK;
}
static MsgAddressObject *MakeSingleAddress(
const nsAString &aDisplay)
{
// This is a wasteful copy, but the internal API does not have RFindChar on
// nsAString, only nsString.
nsString display(aDisplay);
// Strip leading/trailing whitespace
MsgCompressWhitespace(display);
nsCOMPtr<msgIAddressObject> object;
int32_t addrstart = display.RFindChar('<');
if (addrstart != -1)
{
// Adjust is used to strip off exactly one space char if it's present.
int32_t adjust = addrstart == 0 ? 0 : 1;
int32_t addrend = display.RFindChar('>');
return new MsgAddressObject(
StringHead(display, addrstart - adjust),
Substring(display, addrstart + 1, addrend - addrstart - 1));
}
else
{
return new MsgAddressObject(EmptyString(), display);
}
}
NS_IMETHODIMP nsMsgHeaderParser::MakeFromDisplayAddress(
const nsAString &aDisplay, uint32_t *count, msgIAddressObject ***retval)
{
// We split on every comma, so long as a @ exists before that comma.
nsCOMArray<msgIAddressObject> addresses;
int32_t lastComma = -1;
while (!aDisplay.IsEmpty() && lastComma < (int32_t)aDisplay.Length())
{
// Find the next , that follows an email address (which must have an @).
int32_t atSign = aDisplay.FindChar('@', lastComma + 1);
// If there is no @, just consume the rest of the string as the "address"
if (atSign == -1)
atSign = aDisplay.Length() - 1;
int32_t nextComma = aDisplay.FindChar(',', atSign + 1);
if (nextComma == -1)
nextComma = aDisplay.Length();
// The substring from [lastComma + 1, nextComma) is an email address.
addresses.AppendElement(MakeSingleAddress(
Substring(aDisplay, lastComma + 1, nextComma - (lastComma + 1))));
// Move lastComma along
lastComma = nextComma;
}
// Add all the elements to the output
msgIAddressObject **out = (msgIAddressObject **)NS_Alloc(
sizeof(msgIAddressObject*) * addresses.Length());
for (uint32_t i = 0; i < addresses.Length(); i++)
NS_IF_ADDREF(out[i] = addresses[i]);
*count = addresses.Length();
*retval = out;
return NS_OK;
}

Просмотреть файл

@ -16,6 +16,7 @@
#include "nsIMsgHeaderParser.h" /* include the interface we are going to support */
#include "nsIMimeConverter.h"
#include "comi18n.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
/*

Просмотреть файл

@ -24,11 +24,11 @@ function run_test() {
// Test - empty strings
do_check_eq(MailServices.headerParser.makeFullAddress("", ""), "");
do_check_eq(MailServices.headerParser.makeMimeAddress("", ""), "");
// Test - makeFullAddressWString
// Test - makeMimeAddress
for (let i = 0; i < checks.length; ++i)
do_check_eq(MailServices.headerParser.makeFullAddress(checks[i][0], checks[i][1]),
do_check_eq(MailServices.headerParser.makeMimeAddress(checks[i][0], checks[i][1]),
checks[i][2]);
}

Просмотреть файл

@ -0,0 +1,39 @@
/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Test suite for nsIMsgHeaderParser::makeFromDisplayAddress
*/
Components.utils.import("resource:///modules/mailServices.js");
function run_test() {
const checks =
[
{ displayString: "",
addresses: [] },
{ displayString: "test@foo.invalid",
addresses: [["", "test@foo.invalid"]] },
{ displayString: "test@foo.invalid, test2@foo.invalid",
addresses: [["", "test@foo.invalid"],
["", "test2@foo.invalid"]] },
{ displayString: "John Doe <test@foo.invalid>",
addresses: [["John Doe", "test@foo.invalid"]] },
{ displayString: "Doe, John <test@foo.invalid>",
addresses: [["Doe, John", "test@foo.invalid"]] },
{ displayString: "Doe, John <test@foo.invalid>, Bond, James <test2@foo.invalid>",
addresses: [["Doe, John", "test@foo.invalid"],
["Bond, James", "test2@foo.invalid"]] },
];
// Test - strings
for (let i = 0; i < checks.length; ++i) {
dump("Test " + i + "\n");
let addrs = MailServices.headerParser.makeFromDisplayAddress(checks[i].displayString, {});
let checkaddrs = checks[i].addresses;
do_check_eq(addrs.length, checkaddrs.length);
for (let j = 0; j < addrs.length; j++) {
do_check_eq(addrs[j].name, checkaddrs[j][0]);
do_check_eq(addrs[j].email, checkaddrs[j][1]);
}
}
}

Просмотреть файл

@ -3,18 +3,19 @@ head = head_mime.js
tail = tail_mime.js
[test_EncodeMimePartIIStr_UTF8.js]
[test_hidden_attachments.js]
[test_alternate_p7m_handling.js]
[test_attachment_size.js]
[test_badContentType.js]
[test_bug493544.js]
[test_hidden_attachments.js]
[test_message_attachment.js]
[test_mimeContentType.js]
[test_mimeStreaming.js]
[test_nsIMsgHeaderParser1.js]
[test_nsIMsgHeaderParser2.js]
[test_nsIMsgHeaderParser3.js]
[test_parser.js]
[test_text_attachment.js]
[test_message_attachment.js]
[test_nsIMsgHeaderParser4.js]
[test_parseHeadersWithArray.js]
[test_parser.js]
[test_rfc822_body.js]
[test_bug493544.js]
[test_alternate_p7m_handling.js]
[test_text_attachment.js]

Просмотреть файл

@ -570,7 +570,7 @@ function GenerateAddressFromCard(card)
}
else
email = card.primaryEmail;
return MailServices.headerParser.makeFullAddress(card.displayName, email);
return MailServices.headerParser.makeMimeAddress(card.displayName, email);
}
function GetDirectoryFromURI(uri)

Просмотреть файл

@ -114,7 +114,8 @@ function Recipients2CompFields(msgCompFields)
case "addr_bcc" :
case "addr_reply" :
try {
recipient = gMimeHeaderParser.reformatUnquotedAddresses(fieldValue);
let headerParser = MailServices.headerParser;
recipient = [headerParser.makeMimeAddress(fullValue.name, fullValue.email) for (fullValue of headerParser.makeFromDisplayAddress(fieldValue, {}))].join(", ");
} catch (ex) {recipient = fieldValue;}
break;
}
@ -152,8 +153,6 @@ function Recipients2CompFields(msgCompFields)
function CompFields2Recipients(msgCompFields)
{
if (msgCompFields) {
gMimeHeaderParser = Components.classes["@mozilla.org/messenger/headerparser;1"].getService(Components.interfaces.nsIMsgHeaderParser);
var listbox = document.getElementById('addressingWidget');
var newListBoxNode = listbox.cloneNode(false);
var listBoxColsClone = listbox.firstChild.cloneNode(true);
@ -207,8 +206,6 @@ function CompFields2Recipients(msgCompFields)
// CompFields2Recipients is called whenever a user replies or edits an existing message.
// We want to add all of the recipients for this message to the ignore list for spell check
addRecipientsToIgnoreList((gCurrentIdentity ? gCurrentIdentity.identityName + ', ' : '') + msgTo + ', ' + msgCC + ', ' + msgBCC);
gMimeHeaderParser = null; //Release the mime parser
}
}
@ -265,19 +262,8 @@ function awSetInputAndPopupFromArray(inputArray, popupValue, parentNode, templat
{
if (popupValue)
{
var recipient;
for (var index = 0; index < inputArray.length; index++)
{
recipient = null;
if (gMimeHeaderParser)
try {
recipient =
gMimeHeaderParser.unquotePhraseOrAddrWString(inputArray[index], true);
} catch (ex) {};
if (!recipient)
recipient = inputArray[index];
for (let recipient of inputArray)
_awSetInputAndPopup(recipient, popupValue, parentNode, templateNode);
}
}
}