зеркало из https://github.com/mozilla/pjs.git
bug 167265 : add to necko Content-Disposition header handling per RFC 2231 (with
fallbacks to RFC 2047 and raw 8bit chars in |aOriginCharset| ) necessary for i18nized filename support (when downloading files via http) : r=cbiesinger, sr=alecf
This commit is contained in:
Родитель
fccaeaf76c
Коммит
ecc35790fe
|
@ -34,6 +34,7 @@ XPIDLSRCS = \
|
|||
nsICurrentCharsetListener.idl \
|
||||
nsICharsetConverterManager.idl \
|
||||
nsIScriptableUConv.idl \
|
||||
nsIUTF8ConverterService.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
*/
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Jungshik Shin <jshin@mailaps.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s:
|
||||
* Naoki Hotta <nhotta@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(249f52a3-2599-4b00-ba40-0481364831a2)]
|
||||
interface nsIUTF8ConverterService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Ensure that |aString| is encoded in UTF-8. If not,
|
||||
* convert to UTF-8 assuming it's encoded in |aCharset|
|
||||
* and return the converted string in UTF-8.
|
||||
*
|
||||
* @param aString a string to ensure its UTF8ness
|
||||
* @param aCharset the charset to convert from if |aString| is not in UTF-8
|
||||
* @param aSkipCheck determines whether or not to skip 'ASCIIness' and
|
||||
* 'UTF8ness' check. Set this to PR_TRUE only if you suspect that
|
||||
* aString can be mistaken for ASCII / UTF-8 but is actually NOT
|
||||
* in ASCII / UTF-8 so that aString has to go through the conversion.
|
||||
* skipping ASCIIness/UTF8ness check.
|
||||
* The most common case is the input is in 7bit non-ASCII charsets
|
||||
* like ISO-2022-JP, HZ or UTF-7 (in its original form or
|
||||
* a modified form used in IMAP folder names).
|
||||
* @return the converted string in UTF-8.
|
||||
* @throws NS_ERROR_UCONV_NOCONV when there is no decoder for aCharset
|
||||
* or error code of nsIUnicodeDecoder in case of conversion failure
|
||||
*/
|
||||
|
||||
AUTF8String convertStringToUTF8(in ACString aString,
|
||||
in string aCharset,
|
||||
in boolean aSkipCheck);
|
||||
|
||||
/* XXX : To-be-added. convertStringFromUTF8 */
|
||||
|
||||
/**
|
||||
* Ensure that |aSpec| (after URL-unescaping it) is encoded in UTF-8.
|
||||
* If not, convert it to UTF-8, assuming it's encoded in |aCharset|,
|
||||
* and return the result.
|
||||
*
|
||||
* <p>Make sure that all characters outside US-ASCII in your input spec
|
||||
* are url-escaped if your spec is not in UTF-8 (before url-escaping)
|
||||
* because the presence of non-ASCII characters is <strong>blindly</strong>
|
||||
* regarded as an indication that your input spec is in unescaped UTF-8
|
||||
* and it will be returned without further processing. No valid spec
|
||||
* going around in Mozilla code would break this assumption.
|
||||
*
|
||||
* <p>XXX The above may change in the future depending on the usage pattern.
|
||||
*
|
||||
* @param aSpec an url-escaped URI spec to ensure its UTF8ness
|
||||
* @param aCharset the charset to convert from if |aSpec| is not in UTF-8
|
||||
* @return the converted spec in UTF-8.
|
||||
* @throws NS_ERROR_UCONV_NOCONV when there is no decoder for aCharset
|
||||
* or error code of nsIUnicodeDecoder in case of conversion failure
|
||||
*/
|
||||
|
||||
AUTF8String convertURISpecToUTF8(in ACString aSpec,
|
||||
in string aCharset);
|
||||
};
|
||||
|
|
@ -40,6 +40,7 @@ EXPORTS = \
|
|||
nsIConverterInputStream.h \
|
||||
uconvutil.h \
|
||||
nsEncoderDecoderUtils.h \
|
||||
nsUConvCID.h \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=2:
|
||||
**/
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Jungshik Shin <jshin@mailaps.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// I am taking the first step in the hope that this file will become 'the'
|
||||
// repository of #defines for CID's and CONTRACTID's of implementations of
|
||||
// all interfaces in nsUConvModule and be included by any file that wants
|
||||
// to refers to one or more of implementations by CID/CONTRACTID.
|
||||
// see bug 162765 comment #33.
|
||||
|
||||
// {2b026890-5a2e-4981-ada2-a600358947b4}
|
||||
#define NS_UTF8CONVERTERSERVICE_CID { 0x2b026890, 0x5a2e, 0x4981, \
|
||||
{ 0xad, 0xa2, 0xa6, 0x00, 0x35, 0x89, 0x47, 0xb4 } }
|
||||
#define NS_UTF8CONVERTERSERVICE_CONTRACTID "@mozilla.org/intl/utf8converterservice;1"
|
||||
|
|
@ -61,6 +61,7 @@ CPPSRCS = \
|
|||
nsTextToSubURI.cpp \
|
||||
nsURLProperties.cpp \
|
||||
nsCharsetConverterManager.cpp \
|
||||
nsUTF8ConverterService.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifndef MOZ_USE_NATIVE_UCONV
|
||||
|
|
|
@ -50,9 +50,11 @@
|
|||
#include "nsIServiceManager.h"
|
||||
|
||||
|
||||
#include "nsUConvCID.h"
|
||||
#include "nsCharsetConverterManager.h"
|
||||
#include "nsCharsetAlias.h"
|
||||
#include "nsTextToSubURI.h"
|
||||
#include "nsUTF8ConverterService.h"
|
||||
#include "nsConverterInputStream.h"
|
||||
#include "nsPlatformCharset.h"
|
||||
|
||||
|
@ -677,6 +679,7 @@ nsConverterManagerDataRegister(nsIComponentManager* aCompMgr,
|
|||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCharsetConverterManager)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextToSubURI)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUTF8ConverterService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCharsetAlias2)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsConverterInputStream)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPlatformCharset, Init)
|
||||
|
@ -726,6 +729,11 @@ static const nsModuleComponentInfo components[] =
|
|||
NS_UNICODEENCODEHELPER_CONTRACTID,
|
||||
nsUnicodeEncodeHelperConstructor
|
||||
},
|
||||
{
|
||||
"Converter to/from UTF8 with charset", NS_UTF8CONVERTERSERVICE_CID,
|
||||
NS_UTF8CONVERTERSERVICE_CONTRACTID,
|
||||
nsUTF8ConverterServiceConstructor
|
||||
},
|
||||
{
|
||||
"Unicode Encoder / Decoder for Script", NS_ISCRIPTABLEUNICODECONVERTER_CID,
|
||||
NS_ISCRIPTABLEUNICODECONVERTER_CONTRACTID,
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=4:
|
||||
*/
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developers of the Original Code are
|
||||
* Naoki Hotta <nhotta@netscape.com> and Jungshik Shin <jshin@mailaps.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002, 2003
|
||||
* the Initial Developers. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsString.h"
|
||||
#include "nsIUnicodeEncoder.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsUConvDll.h"
|
||||
#include "prmem.h"
|
||||
#include "nsUTF8ConverterService.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsUTF8ConverterService, nsIUTF8ConverterService)
|
||||
|
||||
static nsresult
|
||||
ToUTF8(const nsACString &aString, const char *aCharset, nsACString &aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
if (!aCharset || !*aCharset)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsICharsetConverterManager> ccm;
|
||||
|
||||
ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder;
|
||||
rv = ccm->GetUnicodeDecoder(aCharset,
|
||||
getter_AddRefs(unicodeDecoder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 srcLen = aString.Length();
|
||||
PRInt32 dstLen;
|
||||
const nsAFlatCString& inStr = PromiseFlatCString(aString);
|
||||
rv = unicodeDecoder->GetMaxLength(inStr.get(), srcLen, &dstLen);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoPtr<PRUnichar> ustr(new PRUnichar[dstLen]);
|
||||
NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = unicodeDecoder->Convert(inStr.get(), &srcLen, ustr, &dstLen);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
CopyUTF16toUTF8(nsDependentString(ustr, dstLen), aResult);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUTF8ConverterService::ConvertStringToUTF8(const nsACString &aString,
|
||||
const char *aCharset,
|
||||
PRBool aSkipCheck,
|
||||
nsACString &aUTF8String)
|
||||
{
|
||||
aUTF8String.Truncate();
|
||||
|
||||
// return if ASCII only or valid UTF-8 providing that the ASCII/UTF-8
|
||||
// check is requested. It may not be asked for if a caller suspects
|
||||
// that the input is in non-ASCII 7bit charset (ISO-2022-xx, HZ) or
|
||||
// it's in a charset other than UTF-8 that can be mistaken for UTF-8.
|
||||
if (!aSkipCheck && (IsASCII(aString) || IsUTF8(aString))) {
|
||||
aUTF8String = aString;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = ToUTF8(aString, aCharset, aUTF8String);
|
||||
|
||||
// additional protection for cases where check is skipped and the input
|
||||
// is actually in UTF-8 as opposed to aCharset. (i.e. caller's hunch
|
||||
// was wrong.) We don't check ASCIIness assuming there's no charset
|
||||
// incompatible with ASCII (we don't support EBCDIC).
|
||||
if (aSkipCheck && NS_FAILED(rv) && IsUTF8(aString)) {
|
||||
aUTF8String = aString;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUTF8ConverterService::ConvertURISpecToUTF8(const nsACString &aSpec,
|
||||
const char *aCharset,
|
||||
nsACString &aUTF8Spec)
|
||||
{
|
||||
aUTF8Spec.Truncate();
|
||||
|
||||
// assume UTF-8 if the spec contains unescaped non-ASCII characters.
|
||||
// No valid spec in Mozilla would break this assumption.
|
||||
if (!IsASCII(aSpec)) {
|
||||
aUTF8Spec = aSpec;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCAutoString unescapedSpec;
|
||||
NS_UnescapeURL(PromiseFlatCString(aSpec).get(), aSpec.Length(),
|
||||
esc_OnlyNonASCII, unescapedSpec);
|
||||
|
||||
// return if ASCII only or escaped UTF-8
|
||||
if (IsASCII(unescapedSpec) || IsUTF8(unescapedSpec)) {
|
||||
aUTF8Spec = unescapedSpec;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return ToUTF8(unescapedSpec, aCharset, aUTF8Spec);
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Jungshik Shin <jshin@mailaps.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef nsUTF8ConverterService_h__
|
||||
#define nsUTF8ConverterService_h__
|
||||
|
||||
#include "nsIUTF8ConverterService.h"
|
||||
|
||||
//==============================================================
|
||||
|
||||
class nsUTF8ConverterService: public nsIUTF8ConverterService {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIUTF8CONVERTERSERVICE
|
||||
|
||||
public:
|
||||
nsUTF8ConverterService() {};
|
||||
virtual ~nsUTF8ConverterService() {};
|
||||
};
|
||||
|
||||
#endif // nsUTF8ConverterService_h__
|
||||
|
|
@ -60,7 +60,8 @@
|
|||
#include "nsIPrompt.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsMsgSimulateError.h"
|
||||
#include "nsICharsetConverterManager.h"
|
||||
#include "nsIUTF8ConverterService.h"
|
||||
#include "nsUConvCID.h"
|
||||
|
||||
#define SERVER_DELIMITER ","
|
||||
#define APPEND_SERVERS_VERSION_PREF_NAME "append_preconfig_smtpservers.version"
|
||||
|
@ -83,60 +84,6 @@ static NS_DEFINE_CID(kCSmtpUrlCID, NS_SMTPURL_CID);
|
|||
static NS_DEFINE_CID(kCMailtoUrlCID, NS_MAILTOURL_CID);
|
||||
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
|
||||
|
||||
// function to ensure the spec is encoded in UTF-8
|
||||
// if not then use Unicode converter and apply conversions
|
||||
// output string is empty if no conversion is necessary
|
||||
static nsresult
|
||||
EnsureUTF8Spec(const nsACString &aSpec, const char *aCharset,
|
||||
nsACString &aUTF8Spec)
|
||||
{
|
||||
aUTF8Spec.Truncate(0);
|
||||
|
||||
// assume UTF-8 if the spec contains unescaped non ASCII
|
||||
if (!nsCRT::IsAscii(PromiseFlatCString(aSpec).get()))
|
||||
return NS_OK;
|
||||
|
||||
nsCAutoString unescapedSpec;
|
||||
NS_UnescapeURL(PromiseFlatCString(aSpec).get(), aSpec.Length(),
|
||||
esc_OnlyNonASCII, unescapedSpec);
|
||||
|
||||
// return if ASCII only or escaped UTF-8
|
||||
if (IsASCII(unescapedSpec) ||
|
||||
unescapedSpec.Equals(NS_ConvertUCS2toUTF8(NS_ConvertUTF8toUCS2(unescapedSpec))))
|
||||
return NS_OK;
|
||||
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsICharsetConverterManager> charsetConverterManager;
|
||||
|
||||
charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIUnicodeDecoder> unicodeDecoder;
|
||||
rv = charsetConverterManager->GetUnicodeDecoder(aCharset,
|
||||
getter_AddRefs(unicodeDecoder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 srcLen = unescapedSpec.Length();
|
||||
PRInt32 dstLen;
|
||||
rv = unicodeDecoder->GetMaxLength(unescapedSpec.get(), srcLen, &dstLen);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUnichar *ustr = (PRUnichar *) nsMemory::Alloc(dstLen * sizeof(PRUnichar));
|
||||
NS_ENSURE_TRUE(ustr, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = unicodeDecoder->Convert(unescapedSpec.get(), &srcLen, ustr, &dstLen);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
NS_ConvertUCS2toUTF8 rawUTF8Spec(ustr, dstLen);
|
||||
NS_EscapeURL(rawUTF8Spec, esc_AlwaysCopy | esc_OnlyNonASCII, aUTF8Spec);
|
||||
}
|
||||
nsMemory::Free(ustr);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// foward declarations...
|
||||
nsresult
|
||||
NS_MsgBuildSmtpUrl(nsIFileSpec * aFilePath,
|
||||
|
@ -370,9 +317,14 @@ NS_IMETHODIMP nsSmtpService::NewURI(const nsACString &aSpec,
|
|||
{
|
||||
nsCAutoString utf8Spec;
|
||||
if (aOriginCharset)
|
||||
rv = EnsureUTF8Spec(aSpec, aOriginCharset, utf8Spec);
|
||||
{
|
||||
nsCOMPtr<nsIUTF8ConverterService>
|
||||
utf8Converter(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = utf8Converter->ConvertURISpecToUTF8(aSpec, aOriginCharset, utf8Spec);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !utf8Spec.IsEmpty())
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mailtoUrl->SetSpec(utf8Spec);
|
||||
else
|
||||
mailtoUrl->SetSpec(aSpec);
|
||||
|
|
|
@ -62,6 +62,8 @@
|
|||
#include "nsHankakuToZenkakuCID.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "mimehdrs.h"
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -69,30 +71,6 @@
|
|||
static char basis_64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
#define XX 127
|
||||
/*
|
||||
* Table for decoding base64
|
||||
*/
|
||||
static char index_64[256] = {
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
|
||||
XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
|
||||
XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
};
|
||||
#define CHAR64(c) (index_64[(unsigned char)(c)])
|
||||
|
||||
#define NO_Q_ENCODING_NEEDED(ch) \
|
||||
(((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
|
||||
((ch) >= '0' && (ch) <= '9') || (ch) == '!' || (ch) == '*' || \
|
||||
|
@ -178,72 +156,6 @@ intlmime_encode_b(const unsigned char* input, PRInt32 inlen, char* output)
|
|||
return (output - head);
|
||||
}
|
||||
|
||||
static char *intlmime_decode_b (const char *in, unsigned length)
|
||||
{
|
||||
char *out, *dest = 0;
|
||||
PRInt32 c1, c2, c3, c4;
|
||||
|
||||
out = dest = (char *)PR_Malloc(length+1);
|
||||
if (dest == NULL)
|
||||
return NULL;
|
||||
|
||||
while (length > 0) {
|
||||
while (length > 0 && CHAR64(*in) == XX) {
|
||||
if (*in == '=') goto badsyntax;
|
||||
in++;
|
||||
length--;
|
||||
}
|
||||
if (length == 0) break;
|
||||
c1 = *in++;
|
||||
length--;
|
||||
|
||||
while (length > 0 && CHAR64(*in) == XX) {
|
||||
if (*in == '=') goto badsyntax;
|
||||
in++;
|
||||
length--;
|
||||
}
|
||||
if (length == 0) goto badsyntax;
|
||||
c2 = *in++;
|
||||
length--;
|
||||
|
||||
while (length > 0 && *in != '=' && CHAR64(*in) == XX) {
|
||||
in++;
|
||||
length--;
|
||||
}
|
||||
if (length == 0) goto badsyntax;
|
||||
c3 = *in++;
|
||||
length--;
|
||||
|
||||
while (length > 0 && *in != '=' && CHAR64(*in) == XX) {
|
||||
in++;
|
||||
length--;
|
||||
}
|
||||
if (length == 0) goto badsyntax;
|
||||
c4 = *in++;
|
||||
length--;
|
||||
|
||||
c1 = CHAR64(c1);
|
||||
c2 = CHAR64(c2);
|
||||
*out++ = ((c1<<2) | ((c2&0x30)>>4));
|
||||
if (c3 == '=') {
|
||||
if (c4 != '=') goto badsyntax;
|
||||
break; /* End of data */
|
||||
}
|
||||
c3 = CHAR64(c3);
|
||||
*out++ = (((c2&0x0F) << 4) | ((c3&0x3C) >> 2));
|
||||
if (c4 == '=') {
|
||||
break; /* End of data */
|
||||
}
|
||||
c4 = CHAR64(c4);
|
||||
*out++ = (((c3&0x03) << 6) | c4);
|
||||
}
|
||||
*out++ = '\0';
|
||||
return dest;
|
||||
|
||||
badsyntax:
|
||||
PR_Free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* some utility function used by this file */
|
||||
static PRBool intlmime_only_ascii_str(const char *s)
|
||||
|
@ -803,329 +715,6 @@ char * apply_rfc2047_encoding(const char *_src, PRBool structured, const char *c
|
|||
return output;
|
||||
}
|
||||
|
||||
/*
|
||||
* Table for decoding hexadecimal in quoted-printable
|
||||
*/
|
||||
static char index_hex[256] = {
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX,
|
||||
XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
};
|
||||
#define HEXCHAR(c) (index_hex[(unsigned char)(c)])
|
||||
|
||||
static void convert_htab(char *s)
|
||||
{
|
||||
for (; *s; ++s) {
|
||||
if (*s == TAB)
|
||||
*s = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
static char *intlmime_decode_q(const char *in, unsigned length)
|
||||
{
|
||||
char *out, *dest = 0;
|
||||
|
||||
out = dest = (char *)PR_Malloc(length+1);
|
||||
if (dest == NULL)
|
||||
return NULL;
|
||||
memset(out, 0, length+1);
|
||||
while (length > 0) {
|
||||
switch (*in) {
|
||||
case '=':
|
||||
if (length < 3 || HEXCHAR(in[1]) == XX ||
|
||||
HEXCHAR(in[2]) == XX) goto badsyntax;
|
||||
*out++ = (HEXCHAR(in[1]) << 4) + HEXCHAR(in[2]);
|
||||
in += 3;
|
||||
length -= 3;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
*out++ = ' ';
|
||||
in++;
|
||||
length--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (*in & 0x80) goto badsyntax;
|
||||
*out++ = *in++;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
*out++ = '\0';
|
||||
convert_htab(dest);
|
||||
return dest;
|
||||
|
||||
badsyntax:
|
||||
PR_Free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PRBool intl_is_utf8(const char *input, unsigned len)
|
||||
{
|
||||
PRInt32 c;
|
||||
/*
|
||||
* Input which contains legal HZ sequences should not be detected
|
||||
* as UTF-8.
|
||||
*/
|
||||
enum { hz_initial, /* No HZ seen yet */
|
||||
hz_escaped, /* Inside an HZ ~{ escape sequence */
|
||||
hz_seen, /* Have seen at least one complete HZ sequence */
|
||||
hz_notpresent /* Have seen something that is not legal HZ */
|
||||
} hz_state;
|
||||
|
||||
hz_state = hz_initial;
|
||||
while (len) {
|
||||
c = (unsigned char)*input++;
|
||||
len--;
|
||||
if (c == 0x1B) return PR_FALSE;
|
||||
if (c == '~') {
|
||||
switch (hz_state) {
|
||||
case hz_initial:
|
||||
case hz_seen:
|
||||
if (*input == '{') {
|
||||
hz_state = hz_escaped;
|
||||
} else if (*input == '~') {
|
||||
/* ~~ is the HZ encoding of ~. Skip over second ~ as well */
|
||||
hz_state = hz_seen;
|
||||
input++;
|
||||
len--;
|
||||
} else {
|
||||
hz_state = hz_notpresent;
|
||||
}
|
||||
break;
|
||||
|
||||
case hz_escaped:
|
||||
if (*input == '}') hz_state = hz_seen;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((c & 0x80) == 0) continue;
|
||||
hz_state = hz_notpresent;
|
||||
if ((c & 0xE0) == 0xC0) {
|
||||
if (len < 1 || (*input & 0xC0) != 0x80 ||
|
||||
((c & 0x1F)<<6) + (*input & 0x3f) < 0x80) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
input++;
|
||||
len--;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
if (len < 2 || (input[0] & 0xC0) != 0x80 ||
|
||||
(input[1] & 0xC0) != 0x80) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
input += 2;
|
||||
len -= 2;
|
||||
} else if ((c & 0xF8) == 0xF0) {
|
||||
if (len < 3 || (input[0] & 0xC0) != 0x80 ||
|
||||
(input[1] & 0xC0) != 0x80 || (input[2] & 0xC0) != 0x80) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
input += 2;
|
||||
len -= 2;
|
||||
} else {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (hz_state == hz_seen) return PR_FALSE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static void intl_copy_uncoded_header(char **output, const char *input,
|
||||
unsigned len, const char *default_charset)
|
||||
{
|
||||
PRInt32 c;
|
||||
char *dest = *output;
|
||||
|
||||
if (!default_charset) {
|
||||
memcpy(dest, input, len);
|
||||
*output = dest + len;
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy as long as it's US-ASCII. An ESC may indicate ISO 2022
|
||||
// A ~ may indicate it is HZ
|
||||
while (len && (c = (unsigned char)*input++) != 0x1B && c != '~' && !(c & 0x80)) {
|
||||
*dest++ = c;
|
||||
len--;
|
||||
}
|
||||
if (!len) {
|
||||
*output = dest;
|
||||
return;
|
||||
}
|
||||
input--;
|
||||
|
||||
// If not UTF-8, treat as default charset
|
||||
nsAutoString tempUnicodeString;
|
||||
if (!intl_is_utf8(input, len)) {
|
||||
if (NS_FAILED(ConvertToUnicode(default_charset, nsCAutoString(input, len).get(), tempUnicodeString))) {
|
||||
// Failed to convert. Populate the outString with Unicode Replacement Char
|
||||
tempUnicodeString.Truncate();
|
||||
for (unsigned i = 0; i < len; i++) {
|
||||
tempUnicodeString.Append((PRUnichar)0xFFFD);
|
||||
}
|
||||
}
|
||||
NS_ConvertUCS2toUTF8 utf8_text(tempUnicodeString);
|
||||
PRInt32 output_len = utf8_text.Length();
|
||||
memcpy(dest, utf8_text.get(), output_len);
|
||||
*output = dest + output_len;
|
||||
} else {
|
||||
memcpy(dest, input, len);
|
||||
*output = dest + len;
|
||||
}
|
||||
}
|
||||
|
||||
static const char especials[] = "()<>@,;:\\\"/[]?.=";
|
||||
|
||||
static
|
||||
char *intl_decode_mime_part2_str(const char *header,
|
||||
const char *default_charset, PRBool override_charset)
|
||||
{
|
||||
char *output_p = NULL;
|
||||
char *retbuff = NULL;
|
||||
const char *p, *q, *r;
|
||||
char *decoded_text;
|
||||
const char *begin; /* tracking pointer for where we are in the input buffer */
|
||||
PRInt32 last_saw_encoded_word = 0;
|
||||
const char *charset_start, *charset_end;
|
||||
char charset[80];
|
||||
nsAutoString tempUnicodeString;
|
||||
|
||||
// initialize charset name to an empty string
|
||||
charset[0] = '\0';
|
||||
|
||||
/* Assume no more than 3X expansion due to UTF-8 conversion */
|
||||
retbuff = (char *)PR_Malloc(3*strlen(header)+1);
|
||||
|
||||
if (retbuff == NULL)
|
||||
return NULL;
|
||||
|
||||
output_p = retbuff;
|
||||
begin = header;
|
||||
|
||||
while ((p = PL_strstr(begin, "=?")) != 0) {
|
||||
if (last_saw_encoded_word) {
|
||||
/* See if it's all whitespace. */
|
||||
for (q = begin; q < p; q++) {
|
||||
if (!PL_strchr(" \t\r\n", *q)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_saw_encoded_word || q < p) {
|
||||
/* copy the part before the encoded-word */
|
||||
intl_copy_uncoded_header(&output_p, begin, p - begin, default_charset);
|
||||
begin = p;
|
||||
}
|
||||
|
||||
p += 2;
|
||||
|
||||
/* Get charset info */
|
||||
charset_start = p;
|
||||
charset_end = 0;
|
||||
for (q = p; *q != '?'; q++) {
|
||||
if (*q <= ' ' || PL_strchr(especials, *q)) {
|
||||
goto badsyntax;
|
||||
}
|
||||
|
||||
/* RFC 2231 section 5 */
|
||||
if (!charset_end && *q == '*') {
|
||||
charset_end = q;
|
||||
}
|
||||
}
|
||||
if (!charset_end) {
|
||||
charset_end = q;
|
||||
}
|
||||
|
||||
/* Check for too-long charset name */
|
||||
if ((unsigned)(charset_end - charset_start) >= sizeof(charset)) goto badsyntax;
|
||||
|
||||
memcpy(charset, charset_start, charset_end - charset_start);
|
||||
charset[charset_end - charset_start] = 0;
|
||||
|
||||
q++;
|
||||
if (*q != 'Q' && *q != 'q' && *q != 'B' && *q != 'b')
|
||||
goto badsyntax;
|
||||
|
||||
if (q[1] != '?')
|
||||
goto badsyntax;
|
||||
|
||||
r = q;
|
||||
for (r = q + 2; *r != '?'; r++) {
|
||||
if (*r < ' ') goto badsyntax;
|
||||
}
|
||||
if (r[1] != '=')
|
||||
goto badsyntax;
|
||||
else if (r == q + 2) {
|
||||
// it's empty, skip
|
||||
begin = r + 2;
|
||||
last_saw_encoded_word = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if(*q == 'Q' || *q == 'q')
|
||||
decoded_text = intlmime_decode_q(q+2, r - (q+2));
|
||||
else
|
||||
decoded_text = intlmime_decode_b(q+2, r - (q+2));
|
||||
|
||||
if (decoded_text == NULL)
|
||||
goto badsyntax;
|
||||
|
||||
// Override charset if requested. Never override labeled UTF-8.
|
||||
// Use default charset instead of UNKNOWN-8BIT
|
||||
if ((override_charset && 0 != nsCRT::strcasecmp(charset, "UTF-8")) ||
|
||||
(default_charset && 0 == nsCRT::strcasecmp(charset, "UNKNOWN-8BIT"))) {
|
||||
PL_strncpy(charset, default_charset, sizeof(charset)-1);
|
||||
charset[sizeof(charset)-1] = '\0';
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(ConvertToUnicode(charset, decoded_text, tempUnicodeString))) {
|
||||
NS_ConvertUCS2toUTF8 utf8_text(tempUnicodeString.get());
|
||||
PRInt32 utf8_len = utf8_text.Length();
|
||||
|
||||
memcpy(output_p, utf8_text.get(), utf8_len);
|
||||
output_p += utf8_len;
|
||||
} else {
|
||||
PL_strcpy(output_p, "\347\277\275"); /* UTF-8 encoding of U+FFFD */
|
||||
output_p += 3;
|
||||
}
|
||||
|
||||
PR_Free(decoded_text);
|
||||
|
||||
begin = r + 2;
|
||||
last_saw_encoded_word = 1;
|
||||
continue;
|
||||
|
||||
badsyntax:
|
||||
/* copy the part before the encoded-word */
|
||||
PL_strncpy(output_p, begin, p - begin);
|
||||
output_p += p - begin;
|
||||
begin = p;
|
||||
last_saw_encoded_word = 0;
|
||||
}
|
||||
|
||||
/* put the tail back */
|
||||
intl_copy_uncoded_header(&output_p, begin, strlen(begin), default_charset);
|
||||
*output_p = '\0';
|
||||
convert_htab(retbuff);
|
||||
|
||||
return retbuff;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// BEGIN PUBLIC INTERFACE
|
||||
extern "C" {
|
||||
|
@ -1137,25 +726,16 @@ extern "C" char *MIME_DecodeMimeHeader(const char *header,
|
|||
PRBool override_charset,
|
||||
PRBool eatContinuations)
|
||||
{
|
||||
char *result = nsnull;
|
||||
|
||||
if (header == 0)
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
// If no MIME encoded then do nothing otherwise decode the input.
|
||||
if (PL_strstr(header, "=?") ||
|
||||
(default_charset && !intl_is_utf8(header, strlen(header)))) {
|
||||
result = intl_decode_mime_part2_str(header, default_charset, override_charset);
|
||||
} else if (eatContinuations &&
|
||||
(PL_strchr(header, '\n') || PL_strchr(header, '\r'))) {
|
||||
result = nsCRT::strdup(header);
|
||||
} else {
|
||||
eatContinuations = PR_FALSE;
|
||||
}
|
||||
if (eatContinuations)
|
||||
result = MIME_StripContinuations(result);
|
||||
|
||||
return result;
|
||||
nsCAutoString result;
|
||||
rv = mimehdrpar->DecodeRFC2047Header(header, default_charset, override_charset,
|
||||
eatContinuations, result);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return nsCRT::strdup(result.get());
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
char *MIME_EncodeMimePartIIStr(const char* header, PRBool structured, const char* mailCharset, const PRInt32 fieldNameLen, const PRInt32 encodedWordSize)
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
#include "mimemoz2.h"
|
||||
#include "nsMsgI18N.h"
|
||||
#include "mimehdrs.h"
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
// Forward declares...
|
||||
PRInt32 MimeHeaders_build_heads_list(MimeHeaders *hdrs);
|
||||
|
@ -481,190 +483,22 @@ MimeHeaders_get (MimeHeaders *hdrs, const char *header_name,
|
|||
|
||||
char *
|
||||
MimeHeaders_get_parameter (const char *header_value, const char *parm_name,
|
||||
char **charset, char **language)
|
||||
char **charset, char **language)
|
||||
{
|
||||
const char *str;
|
||||
char *s = NULL; /* parm value to be returned */
|
||||
PRInt32 parm_len;
|
||||
if (!header_value || !parm_name || !*header_value || !*parm_name)
|
||||
return 0;
|
||||
return nsnull;
|
||||
|
||||
/* The format of these header lines is
|
||||
<token> [ ';' <token> '=' <token-or-quoted-string> ]*
|
||||
*/
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar =
|
||||
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
||||
|
||||
if (charset) *charset = NULL;
|
||||
if (language) *language = NULL;
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
str = header_value;
|
||||
parm_len = strlen(parm_name);
|
||||
|
||||
/* Skip forward to first ';' */
|
||||
for (; *str && *str != ';' && *str != ','; str++)
|
||||
;
|
||||
if (*str)
|
||||
str++;
|
||||
/* Skip over following whitespace */
|
||||
for (; *str && nsCRT::IsAsciiSpace(*str); str++)
|
||||
;
|
||||
if (!*str)
|
||||
return 0;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
const char *token_start = str;
|
||||
const char *token_end = 0;
|
||||
const char *value_start = str;
|
||||
const char *value_end = 0;
|
||||
|
||||
NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "1.1 <rhp@netscape.com> 19 Mar 1999 12:00"); /* should be after whitespace already */
|
||||
|
||||
/* Skip forward to the end of this token. */
|
||||
for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++)
|
||||
;
|
||||
token_end = str;
|
||||
|
||||
/* Skip over whitespace, '=', and whitespace */
|
||||
while (nsCRT::IsAsciiSpace (*str)) str++;
|
||||
if (*str == '=') str++;
|
||||
while (nsCRT::IsAsciiSpace (*str)) str++;
|
||||
|
||||
if (*str != '"')
|
||||
{
|
||||
/* The value is a token, not a quoted string. */
|
||||
value_start = str;
|
||||
for (value_end = str;
|
||||
*value_end && !nsCRT::IsAsciiSpace (*value_end) && *value_end != ';';
|
||||
value_end++)
|
||||
;
|
||||
str = value_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The value is a quoted string. */
|
||||
str++;
|
||||
value_start = str;
|
||||
for (value_end = str; *value_end; value_end++)
|
||||
{
|
||||
if (*value_end == '\\')
|
||||
value_end++;
|
||||
else if (*value_end == '"')
|
||||
break;
|
||||
}
|
||||
str = value_end+1;
|
||||
}
|
||||
|
||||
/* See if this is the parameter we're looking for.
|
||||
If so, copy it and return.
|
||||
*/
|
||||
if (token_end - token_start == parm_len &&
|
||||
!nsCRT::strncasecmp(token_start, parm_name, parm_len))
|
||||
{
|
||||
s = (char *) PR_MALLOC ((value_end - value_start) + 1);
|
||||
if (! s) return 0; /* MIME_OUT_OF_MEMORY */
|
||||
memcpy (s, value_start, value_end - value_start);
|
||||
s [value_end - value_start] = 0;
|
||||
/* if the parameter spans across multiple lines we have to strip out the
|
||||
line continuatio -- jht 4/29/98 */
|
||||
MIME_StripContinuations(s);
|
||||
return s;
|
||||
}
|
||||
else if (token_end - token_start > parm_len &&
|
||||
!nsCRT::strncasecmp(token_start, parm_name, parm_len) &&
|
||||
*(token_start+parm_len) == '*')
|
||||
{
|
||||
/* RFC2231 - The legitimate parm format can be:
|
||||
title*=us-ascii'en-us'This%20is%20weired.
|
||||
or
|
||||
title*0*=us-ascii'en'This%20is%20weired.%20We
|
||||
title*1*=have%20to%20support%20this.
|
||||
title*3="Else..."
|
||||
or
|
||||
title*0="Hey, what you think you are doing?"
|
||||
title*1="There is no charset and language info."
|
||||
*/
|
||||
const char *cp = token_start+parm_len+1; /* 1st char pass '*' */
|
||||
PRBool needUnescape = *(token_end-1) == '*';
|
||||
if ((*cp == '0' && needUnescape) || (token_end-token_start == parm_len+1))
|
||||
{
|
||||
const char *s_quote1 = PL_strchr(value_start, 0x27);
|
||||
const char *s_quote2 = (char *) (s_quote1 ? PL_strchr(s_quote1+1, 0x27) : NULL);
|
||||
NS_ASSERTION(s_quote1 && s_quote2, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
|
||||
if (charset && s_quote1 > value_start && s_quote1 < value_end)
|
||||
{
|
||||
*charset = (char *) PR_MALLOC(s_quote1-value_start+1);
|
||||
if (*charset)
|
||||
{
|
||||
memcpy(*charset, value_start, s_quote1-value_start);
|
||||
*(*charset+(s_quote1-value_start)) = 0;
|
||||
}
|
||||
}
|
||||
if (language && s_quote1 && s_quote2 && s_quote2 > s_quote1+1 &&
|
||||
s_quote2 < value_end)
|
||||
{
|
||||
*language = (char *) PR_MALLOC(s_quote2-(s_quote1+1)+1);
|
||||
if (*language)
|
||||
{
|
||||
memcpy(*language, s_quote1+1, s_quote2-(s_quote1+1));
|
||||
*(*language+(s_quote2-(s_quote1+1))) = 0;
|
||||
}
|
||||
}
|
||||
if (s_quote2 && s_quote2+1 < value_end)
|
||||
{
|
||||
NS_ASSERTION(!s, "1.1 <rhp@netscape.com> 19 Mar 1999 12:00");
|
||||
s = (char *) PR_MALLOC(value_end-(s_quote2+1)+1);
|
||||
if (s)
|
||||
{
|
||||
memcpy(s, s_quote2+1, value_end-(s_quote2+1));
|
||||
*(s+(value_end-(s_quote2+1))) = 0;
|
||||
if (needUnescape)
|
||||
{
|
||||
nsUnescape(s);
|
||||
if (token_end-token_start == parm_len+1)
|
||||
return s; /* we done; this is the simple case of
|
||||
encoding charset and language info
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IS_DIGIT(*cp))
|
||||
{
|
||||
PRInt32 len = 0;
|
||||
char *ns = NULL;
|
||||
if (s)
|
||||
{
|
||||
len = strlen(s);
|
||||
ns = (char *) PR_Realloc(s, len+(value_end-value_start)+1);
|
||||
if (!ns)
|
||||
{
|
||||
PR_FREEIF(s);
|
||||
}
|
||||
else if (ns != s)
|
||||
s = ns;
|
||||
}
|
||||
else if (*cp == '0') /* must be; otherwise something is wrong */
|
||||
{
|
||||
s = (char *) PR_MALLOC(value_end-value_start+1);
|
||||
}
|
||||
/* else {} something is really wrong; out of memory */
|
||||
if (s)
|
||||
{
|
||||
memcpy(s+len, value_start, value_end-value_start);
|
||||
*(s+len+(value_end-value_start)) = 0;
|
||||
if (needUnescape)
|
||||
nsUnescape(s+len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* str now points after the end of the value.
|
||||
skip over whitespace, ';', whitespace. */
|
||||
while (nsCRT::IsAsciiSpace (*str)) str++;
|
||||
if (*str == ';') str++;
|
||||
while (nsCRT::IsAsciiSpace (*str)) str++;
|
||||
}
|
||||
return s;
|
||||
nsXPIDLCString result;
|
||||
rv = mimehdrpar->GetParameterInternal(header_value, parm_name, charset,
|
||||
language, getter_Copies(result));
|
||||
return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nsnull;
|
||||
}
|
||||
|
||||
#define MimeHeaders_write(OPT,DATA,LENGTH) \
|
||||
|
@ -848,40 +682,17 @@ char *
|
|||
mime_decode_filename(char *name, const char *charset,
|
||||
MimeDisplayOptions *opt)
|
||||
{
|
||||
char *s = name, *d = name;
|
||||
char *cvt, *returnVal = NULL;
|
||||
|
||||
// If charset parameter is used, this is RFC2231 encoding.
|
||||
if (charset)
|
||||
{
|
||||
nsAutoString tempUnicodeString;
|
||||
if (NS_SUCCEEDED(ConvertToUnicode(charset, name, tempUnicodeString)))
|
||||
{
|
||||
if (returnVal = nsCRT::strdup(NS_ConvertUCS2toUTF8(tempUnicodeString.get()).get()))
|
||||
return returnVal;
|
||||
}
|
||||
}
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMIMEHeaderParam> mimehdrpar =
|
||||
do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
||||
|
||||
while (*s)
|
||||
{
|
||||
/* Remove backslashes when they are used to escape special characters. */
|
||||
if ((*s == '\\') &&
|
||||
((*(s+1) == nsCRT::CR) || (*(s+1) == nsCRT::LF) || (*(s+1) == '"') || (*(s+1) == '\\')))
|
||||
s++; /* take whatever char follows the backslash */
|
||||
if (*s)
|
||||
*d++ = *s++;
|
||||
}
|
||||
*d = 0;
|
||||
returnVal = name;
|
||||
|
||||
cvt = MIME_DecodeMimeHeader(returnVal, opt->default_charset,
|
||||
opt->override_charset, PR_TRUE);
|
||||
|
||||
if (cvt && cvt != returnVal) {
|
||||
returnVal = cvt;
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
nsCAutoString result;
|
||||
rv = mimehdrpar->DecodeParameter(nsDependentCString(name), charset,
|
||||
opt->default_charset,
|
||||
opt->override_charset, result);
|
||||
return NS_SUCCEEDED(rv) ? PL_strdup(result.get()) : nsnull;
|
||||
}
|
||||
|
||||
/* Pull the name out of some header or another. Order is:
|
||||
|
@ -898,50 +709,50 @@ MimeHeaders_get_name(MimeHeaders *hdrs, MimeDisplayOptions *opt)
|
|||
|
||||
s = MimeHeaders_get(hdrs, HEADER_CONTENT_DISPOSITION, PR_FALSE, PR_FALSE);
|
||||
if (s)
|
||||
{
|
||||
name = MimeHeaders_get_parameter(s, HEADER_PARM_FILENAME, &charset, NULL);
|
||||
PR_Free(s);
|
||||
}
|
||||
|
||||
if (! name)
|
||||
{
|
||||
s = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
|
||||
if (s)
|
||||
{
|
||||
PR_FREEIF(charset);
|
||||
|
||||
name = MimeHeaders_get_parameter(s, HEADER_PARM_NAME, &charset, NULL);
|
||||
PR_Free(s);
|
||||
}
|
||||
name = MimeHeaders_get_parameter(s, HEADER_PARM_FILENAME, &charset, NULL);
|
||||
PR_Free(s);
|
||||
}
|
||||
|
||||
if (! name)
|
||||
name = MimeHeaders_get (hdrs, HEADER_CONTENT_NAME, PR_FALSE, PR_FALSE);
|
||||
{
|
||||
s = MimeHeaders_get(hdrs, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
|
||||
if (s)
|
||||
{
|
||||
nsMemory::Free(charset);
|
||||
|
||||
name = MimeHeaders_get_parameter(s, HEADER_PARM_NAME, &charset, NULL);
|
||||
PR_Free(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (! name)
|
||||
name = MimeHeaders_get (hdrs, HEADER_CONTENT_NAME, PR_FALSE, PR_FALSE);
|
||||
|
||||
if (! name)
|
||||
name = MimeHeaders_get (hdrs, HEADER_X_SUN_DATA_NAME, PR_FALSE, PR_FALSE);
|
||||
name = MimeHeaders_get (hdrs, HEADER_X_SUN_DATA_NAME, PR_FALSE, PR_FALSE);
|
||||
|
||||
if (name)
|
||||
{
|
||||
/* First remove continuation delimiters (CR+LF+space), then
|
||||
remove escape ('\\') characters, then attempt to decode
|
||||
mime-2 encoded-words. The latter two are done in
|
||||
mime_decode_filename.
|
||||
*/
|
||||
MIME_StripContinuations(name);
|
||||
/* First remove continuation delimiters (CR+LF+space), then
|
||||
remove escape ('\\') characters, then attempt to decode
|
||||
mime-2 encoded-words. The latter two are done in
|
||||
mime_decode_filename.
|
||||
*/
|
||||
MIME_StripContinuations(name);
|
||||
|
||||
/* Argh. What we should do if we want to be robust is to decode qtext
|
||||
in all appropriate headers. Unfortunately, that would be too scary
|
||||
at this juncture. So just decode qtext/mime2 here. */
|
||||
cvt = mime_decode_filename(name, charset, opt);
|
||||
/* Argh. What we should do if we want to be robust is to decode qtext
|
||||
in all appropriate headers. Unfortunately, that would be too scary
|
||||
at this juncture. So just decode qtext/mime2 here. */
|
||||
cvt = mime_decode_filename(name, charset, opt);
|
||||
|
||||
PR_FREEIF(charset);
|
||||
nsMemory::Free(charset);
|
||||
|
||||
if (cvt && cvt != name)
|
||||
{
|
||||
PR_Free(name);
|
||||
name = cvt;
|
||||
}
|
||||
if (cvt && cvt != name)
|
||||
{
|
||||
PR_Free(name);
|
||||
name = cvt;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
|
|
|
@ -156,7 +156,7 @@ ProcessBodyAsAttachment(MimeObject *obj, nsMsgAttachmentData **data)
|
|||
{
|
||||
char *fname = NULL;
|
||||
fname = mime_decode_filename(tmp->real_name, charset, obj->options);
|
||||
PR_FREEIF(charset);
|
||||
nsMemory::Free(charset);
|
||||
if (fname && fname != tmp->real_name)
|
||||
{
|
||||
PR_Free(tmp->real_name);
|
||||
|
@ -367,7 +367,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO
|
|||
for (i = 0; i < 2 && !tmp->real_name; i ++)
|
||||
{
|
||||
PR_FREEIF(disp);
|
||||
PR_FREEIF(charset);
|
||||
nsMemory::Free(charset);
|
||||
disp = MimeHeaders_get(((MimeContainer *)object)->children[i]->headers, HEADER_CONTENT_DISPOSITION, PR_FALSE, PR_FALSE);
|
||||
tmp->real_name = MimeHeaders_get_parameter(disp, "filename", &charset, nsnull);
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO
|
|||
|
||||
char *fname = nsnull;
|
||||
fname = mime_decode_filename(tmp->real_name, charset, options);
|
||||
PR_FREEIF(charset);
|
||||
nsMemory::Free(charset);
|
||||
|
||||
if (fname && fname != tmp->real_name)
|
||||
{
|
||||
|
@ -408,7 +408,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO
|
|||
for (i = 0; i < 2 && !tmp->real_name; i ++)
|
||||
{
|
||||
PR_FREEIF(disp);
|
||||
PR_FREEIF(charset);
|
||||
nsMemory::Free(charset);
|
||||
disp = MimeHeaders_get(((MimeContainer *)object)->children[i]->headers, HEADER_CONTENT_TYPE, PR_FALSE, PR_FALSE);
|
||||
tmp->real_name = MimeHeaders_get_parameter(disp, "name", &charset, nsnull);
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO
|
|||
|
||||
char *fname = nsnull;
|
||||
fname = mime_decode_filename(tmp->real_name, charset, options);
|
||||
PR_FREEIF(charset);
|
||||
nsMemory::Free(charset);
|
||||
|
||||
if (fname && fname != tmp->real_name)
|
||||
{
|
||||
|
|
|
@ -118,15 +118,18 @@ extern char *MimeHeaders_get(MimeHeaders *hdrs,
|
|||
|
||||
Returns NULL if there is no match, or if there is an allocation failure.
|
||||
|
||||
RFC2231 - MIME Parameter Value and Encoded Word Extensions: Character Sets,
|
||||
Languages, and Continuations
|
||||
RFC2231 - MIME Parameter Value and Encoded Word Extensions: Character Sets,
|
||||
Languages, and Continuations
|
||||
|
||||
RFC2231 has added the character sets, languages, and continuations mechanism.
|
||||
charset, and language information may also be returned to the caller.
|
||||
For example,
|
||||
MimeHeaders_get_parameter("text/plain; name*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A", "name")
|
||||
MimeHeaders_get_parameter("text/plain; name*0*=us-ascii'en-us'This%20is%20; CRLFLWSPname*1*=%2A%2A%2Afun%2A%2A%2A", "name")
|
||||
would return "This is ***fun***" and *charset = "us-ascii", *language = "en-us"
|
||||
RFC2231 has added the character sets, languages, and continuations mechanism.
|
||||
charset, and language information may also be returned to the caller.
|
||||
Note that charset and language should be nsMemory::Free()'d while
|
||||
the return value (parameter) has to be PR_FREE'd.
|
||||
|
||||
For example,
|
||||
MimeHeaders_get_parameter("text/plain; name*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A", "name")
|
||||
MimeHeaders_get_parameter("text/plain; name*0*=us-ascii'en-us'This%20is%20; CRLFLWSPname*1*=%2A%2A%2Afun%2A%2A%2A", "name")
|
||||
would return "This is ***fun***" and *charset = "us-ascii", *language = "en-us"
|
||||
*/
|
||||
extern char *MimeHeaders_get_parameter (const char *header_value,
|
||||
const char *parm_name,
|
||||
|
|
|
@ -570,4 +570,20 @@
|
|||
{0x8c, 0x31, 0x28, 0x65, 0xfb, 0xb6, 0x8c, 0x91} \
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* netwerk/mime classes
|
||||
*/
|
||||
|
||||
#define NS_MIMEHEADERPARAM_CLASSNAME \
|
||||
"nsMIMEHeaderParamImpl"
|
||||
// {1F4DBCF7-245C-4c8c-943D-8A1DA0495E8A}
|
||||
#define NS_MIMEHEADERPARAM_CID \
|
||||
{ 0x1f4dbcf7, \
|
||||
0x245c, \
|
||||
0x4c8c, \
|
||||
{ 0x94, 0x3d, 0x8a, 0x1d, 0xa0, 0x49, 0x5e, 0x8a } \
|
||||
}
|
||||
|
||||
#define NS_MIMEHEADERPARAM_CONTRACTID "@mozilla.org/network/mime-hdrparam;1"
|
||||
|
||||
#endif // nsNetCID_h__
|
||||
|
|
|
@ -112,6 +112,11 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMIMEInfoImpl)
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "nsMIMEHeaderParamImpl.h"
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMIMEHeaderParamImpl)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "nsRequestObserverProxy.h"
|
||||
#include "nsSimpleStreamListener.h"
|
||||
#include "nsDirIndexParser.h"
|
||||
|
@ -811,6 +816,12 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
|
|||
nsMIMEInfoImplConstructor
|
||||
},
|
||||
|
||||
{ "mime header param",
|
||||
NS_MIMEHEADERPARAM_CID,
|
||||
NS_MIMEHEADERPARAM_CONTRACTID,
|
||||
nsMIMEHeaderParamImplConstructor
|
||||
},
|
||||
|
||||
#ifdef NECKO_PROTOCOL_file
|
||||
// from netwerk/protocol/file:
|
||||
{ NS_FILEPROTOCOLHANDLER_CLASSNAME,
|
||||
|
|
|
@ -32,6 +32,7 @@ XPIDL_MODULE = mimetype
|
|||
XPIDLSRCS = \
|
||||
nsIMIMEService.idl \
|
||||
nsIMIMEInfo.idl \
|
||||
nsIMIMEHeaderParam.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
*/
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Jungshik Shin <jshin@mailaps.org>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003.
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* This interface allows any module to access the routine
|
||||
* for MIME header parameter parsing (RFC 2231)
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(ddbbdfb8-a1c0-4dd5-a31b-5d2a7a3bb6ec)]
|
||||
interface nsIMIMEHeaderParam : nsISupports {
|
||||
|
||||
/**
|
||||
* Given the value of a single header field (such as
|
||||
* Content-Disposition and Content-Type) and the name of a parameter
|
||||
* (e.g. filename, name, charset), returns the value of the parameter.
|
||||
* The value is obtained by decoding RFC 2231-style encoding,
|
||||
* RFC 2047-style encoding, and converting to UniChar(UTF-16)
|
||||
* from charset specified in RFC 2231/2047 encoding, UTF-8,
|
||||
* <code>aFallbackCharset</code> and the locale charset as the last
|
||||
* resort if <code>TryLocaleCharset</code> is set.
|
||||
*
|
||||
* <p>
|
||||
* This method internally invokes <code>getParameterInternal</code>,
|
||||
* However, it does not stop at decoding RFC 2231 (the task for
|
||||
* <code>getParameterInternal</code> but tries to cope
|
||||
* with several non-standard-compliant cases mentioned below.
|
||||
*
|
||||
* <p>
|
||||
* Note that a lot of MUAs and HTTP servers put RFC 2047-encoded parameters
|
||||
* in mail headers and HTTP headers. Unfortunately, this includes Mozilla
|
||||
* as of 2003-05-30. Even more standard-ignorant MUAs, web servers and
|
||||
* application servers put 'raw 8bit characters'. This will try to cope
|
||||
* with all these cases as gracefully as possible. Additionally, it
|
||||
* returns the language tag if the parameter is encoded per RFC 2231 and
|
||||
* includes lang.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param aHeaderVal a header string to get the value of a parameter
|
||||
* from.
|
||||
* @param aParamName the name of a MIME header parameter (e.g.
|
||||
* filename, name, charset). If empty, returns
|
||||
* the first (possibly) _unnamed_ 'parameter'.
|
||||
* @param aFallbackCharset fallback charset to try if the string after
|
||||
* RFC 2231/2047 decoding or the raw 8bit
|
||||
* string is not UTF-8
|
||||
* @param aTryLocaleCharset If set, makes yet another attempt
|
||||
* with the locale charset.
|
||||
* @param aLang If non-null, assigns it to a pointer
|
||||
* to a string containing the value of language
|
||||
* obtained from RFC 2231 parsing. Caller has to
|
||||
* nsMemory::Free it.
|
||||
* @return the value of <code>aParamName</code> in Unichar(UTF-16).
|
||||
*/
|
||||
|
||||
AString getParameter(in ACString aHeaderVal,
|
||||
in string aParamName,
|
||||
in ACString aFallbackCharset,
|
||||
in boolean aTryLocaleCharset,
|
||||
out string aLang);
|
||||
/**
|
||||
* Given the value of a single header field (such as
|
||||
* Content-Disposition and Content-Type) and the name of a parameter
|
||||
* (e.g. filename, name, charset), returns the value of the parameter
|
||||
* after decoding RFC 2231-style encoding.
|
||||
* <p>
|
||||
* For <strong>internal use only</strong>. The only other place where
|
||||
* this needs to be invoked is |MimeHeaders_get_parameter| in
|
||||
* mailnews/mime/src/mimehdrs.cpp defined as
|
||||
* char * MimeHeaders_get_parameter (const char *header_value,
|
||||
* const char *parm_name,
|
||||
* char **charset, char **language)
|
||||
*
|
||||
* Otherwise, this method would have been made static.
|
||||
*
|
||||
* @param aHeaderVal a header string to get the value of a parameter from.
|
||||
* @param aParamName the name of a MIME header parameter (e.g.
|
||||
* filename, name, charset). If empty, returns
|
||||
* the first (possibly) _unnamed_ 'parameter'.
|
||||
* @param aCharset If non-null, it gets assigned a new pointer
|
||||
* to a string containing the value of charset obtained
|
||||
* from RFC 2231 parsing. Caller has to nsMemory::Free it.
|
||||
* @param aLang If non-null, it gets assigned a new pointer
|
||||
* to a string containing the value of language obtained
|
||||
* from RFC 2231 parsing. Caller has to nsMemory::Free it.
|
||||
* @return the value of <code>aParamName</code> after
|
||||
* RFC 2231 decoding but without charset conversion.
|
||||
*/
|
||||
|
||||
[noscript]
|
||||
string getParameterInternal(in string aHeaderVal,
|
||||
in string aParamName,
|
||||
out string aCharset,
|
||||
out string aLang);
|
||||
|
||||
|
||||
/**
|
||||
* Given a header value, decodes RFC 2047-style encoding and
|
||||
* returns the decoded header value in UTF-8 if either it's
|
||||
* RFC-2047-encoded or aDefaultCharset is given. Otherwise,
|
||||
* returns the input header value (in whatever encoding)
|
||||
* as it is except that RFC 822 (using backslash) quotation and
|
||||
* CRLF (if aEatContinuation is set) are stripped away
|
||||
* <p>
|
||||
* For internal use only. The only other place where this needs to be
|
||||
* invoked is <code>MIME_DecodeMimeHeader</code> in
|
||||
* mailnews/mime/src/mimehdrs.cpp defined as
|
||||
* char * Mime_DecodeMimeHeader(char *header_val, const char *charset,
|
||||
* PRBool override, PRBool eatcontinuation)
|
||||
*
|
||||
* @param aHeaderVal a header value to decode
|
||||
* @param aDefaultCharset MIME charset to use in place of MIME charset
|
||||
* specified in RFC 2047 style encoding
|
||||
* when <code>aOverrideCharset</code> is set.
|
||||
* @param aOverrideCharset When set, overrides MIME charset specified
|
||||
* in RFC 2047 style encoding with <code>aDefaultCharset</code>
|
||||
* @param aEatContinuation When set, removes CR/LF
|
||||
* @return decoded header value
|
||||
*/
|
||||
[noscript]
|
||||
ACString decodeRFC2047Header(in string aHeaderVal,
|
||||
in string aDefaultCharset,
|
||||
in boolean aOverrideCharset,
|
||||
in boolean aEatContinuation);
|
||||
|
||||
|
||||
/**
|
||||
* Given a header parameter, decodes RFC 2047 style encoding (if it's
|
||||
* not obtained from RFC 2231 encoding), converts it to
|
||||
* UTF-8 and returns the result in UTF-8 if an attempt to extract
|
||||
* charset info. from a few different sources succeeds.
|
||||
* Otherwise, returns the input header value (in whatever encoding)
|
||||
* as it is except that RFC 822 (using backslash) quotation is
|
||||
* stripped off.
|
||||
* <p>
|
||||
* For internal use only. The only other place where this needs to be
|
||||
* invoked is <code>mime_decode_filename</code> in
|
||||
* mailnews/mime/src/mimehdrs.cpp defined as
|
||||
* char * mime_decode_filename(char *name, const char *charset,
|
||||
* MimeDisplayOptions *opt)
|
||||
*
|
||||
* @param aParamValue the value of a parameter to decode and convert
|
||||
* @param aCharset charset obtained from RFC 2231 decoding in which
|
||||
* <code>aParamValue</code> is encoded. If null,
|
||||
* indicates that it needs to try RFC 2047, instead.
|
||||
* @param aDefaultCharset MIME charset to use when aCharset is null and
|
||||
* cannot be obtained per RFC 2047 (most likely
|
||||
* because 'bare' string is used.) Besides, it
|
||||
* overrides aCharset/MIME charset obtained from
|
||||
* RFC 2047 if <code>aOverrideCharset</code> is set.
|
||||
* @param aOverrideCharset When set, overrides MIME charset specified
|
||||
* in RFC 2047 style encoding with
|
||||
* <code>aDefaultCharset</code>
|
||||
* @return decoded parameter
|
||||
*/
|
||||
|
||||
[noscript]
|
||||
ACString decodeParameter(in ACString aParamValue,
|
||||
in string aCharset,
|
||||
in string aDefaultCharset,
|
||||
in boolean aOverrideCharset);
|
||||
};
|
||||
|
|
@ -31,11 +31,13 @@ LIBRARY_NAME = nkmime_s
|
|||
REQUIRES = xpcom \
|
||||
string \
|
||||
necko \
|
||||
uconv \
|
||||
pref \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsMIMEInfoImpl.cpp \
|
||||
nsMIMEHeaderParamImpl.cpp \
|
||||
$(NULL)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
|
|
|
@ -0,0 +1,745 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=4:
|
||||
*/
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998, 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* rhp@netscape.com
|
||||
* Jungshik Shin <jshin@mailaps.org>
|
||||
* John G Myers <jgmyers@netscape.com>
|
||||
* Takayuki Tei <taka@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prmem.h"
|
||||
#include "prprf.h"
|
||||
#include "plstr.h"
|
||||
#include "plbase64.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIUTF8ConverterService.h"
|
||||
#include "nsUConvCID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsMIMEHeaderParamImpl.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
// static functions declared below are moved from mailnews/mime/src/comi18n.cpp
|
||||
|
||||
static char *DecodeQ(const char *, PRUint32);
|
||||
static PRBool Is7bitNonAsciiString(const char *, PRUint32);
|
||||
static void CopyRawHeader(const char *, PRUint32, const char *, nsACString &);
|
||||
static nsresult DecodeRFC2047Str(const char *, const char *, PRBool, nsACString&);
|
||||
|
||||
// XXX The chance of UTF-7 being used in the message header is really
|
||||
// low, but in theory it's possible.
|
||||
#define IS_7BIT_NON_ASCII_CHARSET(cset) \
|
||||
(!nsCRT::strncasecmp((cset), "ISO-2022", 8) || \
|
||||
!nsCRT::strncasecmp((cset), "HZ-GB", 5) || \
|
||||
!nsCRT::strncasecmp((cset), "UTF-7", 5))
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsMIMEHeaderParamImpl, nsIMIMEHeaderParam)
|
||||
|
||||
// XXX : aTryLocaleCharset is not yet effective.
|
||||
NS_IMETHODIMP
|
||||
nsMIMEHeaderParamImpl::GetParameter(const nsACString& aHeaderVal,
|
||||
const char *aParamName,
|
||||
const nsACString& aFallbackCharset,
|
||||
PRBool aTryLocaleCharset,
|
||||
char **aLang, nsAString& aResult)
|
||||
{
|
||||
aResult.Truncate();
|
||||
nsresult rv;
|
||||
|
||||
// get parameter (decode RFC 2231 if it's RFC 2231-encoded and
|
||||
// return charset.)
|
||||
nsXPIDLCString med;
|
||||
nsXPIDLCString charset;
|
||||
rv = GetParameterInternal(PromiseFlatCString(aHeaderVal).get(), aParamName,
|
||||
getter_Copies(charset), aLang, getter_Copies(med));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(!aTryLocaleCharset, "aTryLocaleCharset not yet supported !");
|
||||
|
||||
// convert to UTF-8 after charset conversion and RFC 2047 decoding
|
||||
// if necessary.
|
||||
|
||||
nsCAutoString str1;
|
||||
rv = DecodeParameter(med, charset.get(), nsnull, PR_FALSE, str1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aFallbackCharset.IsEmpty())
|
||||
{
|
||||
nsCAutoString str2;
|
||||
nsCOMPtr<nsIUTF8ConverterService>
|
||||
cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
NS_SUCCEEDED(cvtUTF8->ConvertStringToUTF8(str1,
|
||||
PromiseFlatCString(aFallbackCharset).get(), PR_FALSE, str2)))
|
||||
CopyUTF8toUTF16(str2, aResult);
|
||||
else
|
||||
CopyUTF8toUTF16(str1, aResult);
|
||||
}
|
||||
else
|
||||
CopyUTF8toUTF16(str1, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// moved almost verbatim from mimehdrs.cpp
|
||||
// char *
|
||||
// MimeHeaders_get_parameter (const char *header_value, const char *parm_name,
|
||||
// char **charset, char **language)
|
||||
//
|
||||
// The format of these header lines is
|
||||
// <token> [ ';' <token> '=' <token-or-quoted-string> ]*
|
||||
NS_IMETHODIMP
|
||||
nsMIMEHeaderParamImpl::GetParameterInternal(const char *aHeaderValue,
|
||||
const char *aParamName,
|
||||
char **aCharset,
|
||||
char **aLang,
|
||||
char **aResult)
|
||||
{
|
||||
if (!aHeaderValue || !*aHeaderValue || !aResult)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
*aResult = nsnull;
|
||||
|
||||
if (aCharset) *aCharset = nsnull;
|
||||
if (aLang) *aLang = nsnull;
|
||||
|
||||
const char *str = aHeaderValue;
|
||||
|
||||
// skip leading white space.
|
||||
for (; *str && nsCRT::IsAsciiSpace(*str); ++str)
|
||||
;
|
||||
const char *start = str;
|
||||
|
||||
// aParamName is empty. return the first (possibly) _unnamed_ 'parameter'
|
||||
// For instance, return 'inline' in the following case:
|
||||
// Content-Disposition: inline; filename=.....
|
||||
if (!aParamName || !*aParamName)
|
||||
{
|
||||
for (; *str && *str != ';' && !nsCRT::IsAsciiSpace(*str); ++str)
|
||||
;
|
||||
if (str == start)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
*aResult = (char *) nsMemory::Clone(start, (str - start) + 1);
|
||||
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Skip forward to first ';' */
|
||||
for (; *str && *str != ';' && *str != ','; ++str)
|
||||
;
|
||||
if (*str)
|
||||
str++;
|
||||
/* Skip over following whitespace */
|
||||
for (; *str && nsCRT::IsAsciiSpace(*str); ++str)
|
||||
;
|
||||
|
||||
// Some broken http servers just specify parameters
|
||||
// like 'filename' without sepcifying disposition
|
||||
// method. Rewind to the first non-white-space
|
||||
// character.
|
||||
|
||||
if (!*str)
|
||||
str = start;
|
||||
|
||||
// RFC2231 - The legitimate parm format can be:
|
||||
// A. title=ThisIsTitle
|
||||
// B. title*=us-ascii'en-us'This%20is%20wierd.
|
||||
// C. title*0*=us-ascii'en'This%20is%20wierd.%20We
|
||||
// title*1*=have%20to%20support%20this.
|
||||
// title*2="Else..."
|
||||
// D. title*0="Hey, what you think you are doing?"
|
||||
// title*1="There is no charset and lang info."
|
||||
|
||||
PRInt32 paramLen = strlen(aParamName);
|
||||
|
||||
while (*str) {
|
||||
const char *tokenStart = str;
|
||||
const char *tokenEnd = 0;
|
||||
const char *valueStart = str;
|
||||
const char *valueEnd = 0;
|
||||
|
||||
NS_ASSERTION(!nsCRT::IsAsciiSpace(*str), "should be after whitespace.");
|
||||
|
||||
// Skip forward to the end of this token.
|
||||
for (; *str && !nsCRT::IsAsciiSpace(*str) && *str != '=' && *str != ';'; str++)
|
||||
;
|
||||
tokenEnd = str;
|
||||
|
||||
// Skip over whitespace, '=', and whitespace
|
||||
while (nsCRT::IsAsciiSpace(*str)) ++str;
|
||||
if (*str == '=') ++str;
|
||||
while (nsCRT::IsAsciiSpace(*str)) ++str;
|
||||
|
||||
if (*str != '"')
|
||||
{
|
||||
// The value is a token, not a quoted string.
|
||||
valueStart = str;
|
||||
for (valueEnd = str;
|
||||
*valueEnd && !nsCRT::IsAsciiSpace (*valueEnd) && *valueEnd != ';';
|
||||
valueEnd++)
|
||||
;
|
||||
str = valueEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a quoted string.
|
||||
++str;
|
||||
valueStart = str;
|
||||
for (valueEnd = str; *valueEnd; ++valueEnd)
|
||||
{
|
||||
if (*valueEnd == '\\')
|
||||
++valueEnd;
|
||||
else if (*valueEnd == '"')
|
||||
break;
|
||||
}
|
||||
str = valueEnd + 1;
|
||||
}
|
||||
|
||||
// See if this is the simplest case (case A above),
|
||||
// a 'single' line value with no charset and lang.
|
||||
// If so, copy it and return.
|
||||
if (tokenEnd - tokenStart == paramLen &&
|
||||
!nsCRT::strncasecmp(tokenStart, aParamName, paramLen))
|
||||
{
|
||||
// if the parameter spans across multiple lines we have to strip out the
|
||||
// line continuation -- jht 4/29/98
|
||||
nsCAutoString tempStr(valueStart, valueEnd - valueStart);
|
||||
tempStr.StripChars("\r\n");
|
||||
*aResult = ToNewCString(tempStr);
|
||||
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
|
||||
return NS_OK;
|
||||
}
|
||||
// case B, C, and D
|
||||
else if (tokenEnd - tokenStart > paramLen &&
|
||||
!nsCRT::strncasecmp(tokenStart, aParamName, paramLen) &&
|
||||
*(tokenStart + paramLen) == '*')
|
||||
{
|
||||
const char *cp = tokenStart + paramLen + 1; // 1st char pass '*'
|
||||
PRBool needUnescape = *(tokenEnd - 1) == '*';
|
||||
// the 1st line of a multi-line parameter or a single line that needs
|
||||
// unescaping. ( title*0*= or title*= )
|
||||
if ((*cp == '0' && needUnescape) || (tokenEnd - tokenStart == paramLen + 1))
|
||||
{
|
||||
// look for single quotation mark(')
|
||||
const char *sQuote1 = PL_strchr(valueStart, 0x27);
|
||||
const char *sQuote2 = (char *) (sQuote1 ? PL_strchr(sQuote1 + 1, 0x27) : nsnull);
|
||||
|
||||
// Two single quotation marks must be present even in
|
||||
// absence of charset and lang.
|
||||
if (!sQuote1 || !sQuote2)
|
||||
NS_WARNING("Mandatory two single quotes are missing in header parameter\n");
|
||||
if (aCharset && sQuote1 > valueStart && sQuote1 < valueEnd)
|
||||
{
|
||||
*aCharset = (char *) nsMemory::Clone(valueStart, sQuote1 - valueStart + 1);
|
||||
if (*aCharset)
|
||||
*(*aCharset + (sQuote1 - valueStart)) = 0;
|
||||
}
|
||||
if (aLang && sQuote1 && sQuote2 && sQuote2 > sQuote1 + 1 &&
|
||||
sQuote2 < valueEnd)
|
||||
{
|
||||
*aLang = (char *) nsMemory::Clone(sQuote1 + 1, sQuote2 - (sQuote1 + 1) + 1);
|
||||
if (*aLang)
|
||||
*(*aLang + (sQuote2 - (sQuote1 + 1))) = 0;
|
||||
}
|
||||
|
||||
// Be generous and handle gracefully when required
|
||||
// single quotes are absent.
|
||||
if (sQuote1)
|
||||
{
|
||||
if(!sQuote2)
|
||||
sQuote2 = sQuote1;
|
||||
}
|
||||
else
|
||||
sQuote2 = valueStart - 1;
|
||||
|
||||
if (sQuote2 && sQuote2 + 1 < valueEnd)
|
||||
{
|
||||
NS_ASSERTION(!*aResult, "This is the 1st line. result buffer should be null.");
|
||||
*aResult = (char *) nsMemory::Alloc(valueEnd - (sQuote2 + 1) + 1);
|
||||
if (*aResult)
|
||||
{
|
||||
memcpy(*aResult, sQuote2 + 1, valueEnd - (sQuote2 + 1));
|
||||
*(*aResult + (valueEnd - (sQuote2 + 1))) = 0;
|
||||
if (needUnescape)
|
||||
{
|
||||
nsUnescape(*aResult);
|
||||
if (tokenEnd - tokenStart == paramLen + 1)
|
||||
// we're done; this is case B
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end of if-block : title*0*= or title*=
|
||||
// a line of multiline param with no need for unescaping : title*[0-9]=
|
||||
// or 2nd or later lines of a multiline param : title*[1-9]*=
|
||||
else if (nsCRT::IsAsciiDigit(PRUnichar(*cp)))
|
||||
{
|
||||
PRInt32 len = 0;
|
||||
if (*aResult) // 2nd or later lines of multiline parameter
|
||||
{
|
||||
len = strlen(*aResult);
|
||||
char *ns = (char *) nsMemory::Realloc(*aResult, len + (valueEnd - valueStart) + 1);
|
||||
if (!ns)
|
||||
{
|
||||
nsMemory::Free(*aResult);
|
||||
}
|
||||
*aResult = ns;
|
||||
}
|
||||
else if (*cp == '0') // must be; 1st line : title*0=
|
||||
{
|
||||
*aResult = (char *) nsMemory::Alloc(valueEnd - valueStart + 1);
|
||||
}
|
||||
// else {} something is really wrong; out of memory
|
||||
if (*aResult)
|
||||
{
|
||||
// append a partial value
|
||||
memcpy(*aResult + len, valueStart, valueEnd - valueStart);
|
||||
*(*aResult + len + (valueEnd - valueStart)) = 0;
|
||||
if (needUnescape)
|
||||
nsUnescape(*aResult + len);
|
||||
}
|
||||
else
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
} // end of if-block : title*[0-9]= or title*[1-9]*=
|
||||
}
|
||||
|
||||
// str now points after the end of the value.
|
||||
// skip over whitespace, ';', whitespace.
|
||||
|
||||
while (nsCRT::IsAsciiSpace(*str)) ++str;
|
||||
if (*str == ';') ++str;
|
||||
while (nsCRT::IsAsciiSpace(*str)) ++str;
|
||||
}
|
||||
|
||||
if (*aResult)
|
||||
return NS_OK;
|
||||
else
|
||||
return NS_ERROR_INVALID_ARG; // aParameter not found !!
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEHeaderParamImpl::DecodeRFC2047Header(const char* aHeaderVal,
|
||||
const char* aDefaultCharset,
|
||||
PRBool aOverrideCharset,
|
||||
PRBool aEatContinuations,
|
||||
nsACString& aResult)
|
||||
{
|
||||
aResult.Truncate();
|
||||
if (!aHeaderVal)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
if (!*aHeaderVal)
|
||||
return NS_OK;
|
||||
|
||||
|
||||
// If aHeaderVal is RFC 2047 encoded or is not a UTF-8 string but
|
||||
// aDefaultCharset is specified, decodes RFC 2047 encoding and converts
|
||||
// to UTF-8. Otherwise, just strips away CRLF.
|
||||
if (PL_strstr(aHeaderVal, "=?") ||
|
||||
aDefaultCharset && (!IsUTF8(nsDependentCString(aHeaderVal)) ||
|
||||
Is7bitNonAsciiString(aHeaderVal, PL_strlen(aHeaderVal)))) {
|
||||
DecodeRFC2047Str(aHeaderVal, aDefaultCharset, aOverrideCharset, aResult);
|
||||
} else if (aEatContinuations &&
|
||||
(PL_strchr(aHeaderVal, '\n') || PL_strchr(aHeaderVal, '\r'))) {
|
||||
aResult = aHeaderVal;
|
||||
} else {
|
||||
aEatContinuations = PR_FALSE;
|
||||
aResult = aHeaderVal;
|
||||
}
|
||||
|
||||
if (aEatContinuations) {
|
||||
nsCAutoString temp(aResult);
|
||||
temp.StripChars("\r\n");
|
||||
aResult = temp;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMIMEHeaderParamImpl::DecodeParameter(const nsACString& aParamValue,
|
||||
const char* aCharset,
|
||||
const char* aDefaultCharset,
|
||||
PRBool aOverrideCharset,
|
||||
nsACString& aResult)
|
||||
{
|
||||
aResult.Truncate();
|
||||
nsresult rv;
|
||||
// If aCharset is given, aParamValue was obtained from RFC2231
|
||||
// encoding and we're pretty sure that it's in aCharset.
|
||||
if (aCharset && *aCharset)
|
||||
{
|
||||
nsCOMPtr<nsIUTF8ConverterService> cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
// skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset.
|
||||
return cvtUTF8->ConvertStringToUTF8(aParamValue, aCharset,
|
||||
IS_7BIT_NON_ASCII_CHARSET(aCharset), aResult);
|
||||
}
|
||||
|
||||
const nsAFlatCString& param = PromiseFlatCString(aParamValue);
|
||||
nsCAutoString unQuoted;
|
||||
nsACString::const_iterator s, e;
|
||||
param.BeginReading(s);
|
||||
param.EndReading(e);
|
||||
|
||||
// strip '\' when used to quote CR, LF, '"' and '\'
|
||||
for ( ; s != e; ++s) {
|
||||
if ((*s == '\\')) {
|
||||
if (++s == e) {
|
||||
--s; // '\' is at the end. move back and append '\'.
|
||||
}
|
||||
else if (*s != nsCRT::CR && *s != nsCRT::LF && *s != '"' && *s != '\\') {
|
||||
--s; // '\' is not foll. by CR,LF,'"','\'. move back and append '\'
|
||||
}
|
||||
// else : skip '\' and append the quoted character.
|
||||
}
|
||||
unQuoted.Append(*s);
|
||||
}
|
||||
|
||||
aResult = unQuoted;
|
||||
|
||||
nsCAutoString decoded;
|
||||
|
||||
// Try RFC 2047 encoding, instead.
|
||||
rv = DecodeRFC2047Header(unQuoted.get(), aDefaultCharset,
|
||||
aOverrideCharset, PR_TRUE, decoded);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !decoded.IsEmpty())
|
||||
aResult = decoded;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define ISHEXCHAR(c) \
|
||||
(0x30 <= PRUint8(c) && PRUint8(c) <= 0x39 || \
|
||||
0x41 <= PRUint8(c) && PRUint8(c) <= 0x46 || \
|
||||
0x61 <= PRUint8(c) && PRUint8(c) <= 0x66)
|
||||
|
||||
// Decode Q encoding (RFC 2047).
|
||||
// static
|
||||
char *DecodeQ(const char *in, PRUint32 length)
|
||||
{
|
||||
char *out, *dest = 0;
|
||||
|
||||
out = dest = (char *)PR_Calloc(length + 1, sizeof(char));
|
||||
if (dest == nsnull)
|
||||
return nsnull;
|
||||
while (length > 0) {
|
||||
switch (*in) {
|
||||
case '=':
|
||||
// check if |in| in the form of '=hh' where h is [0-9a-fA-F].
|
||||
if (length < 3 || !ISHEXCHAR(in[1]) || !ISHEXCHAR(in[2]))
|
||||
goto badsyntax;
|
||||
PR_sscanf(in + 1, "%2X", out);
|
||||
++out;
|
||||
in += 3;
|
||||
length -= 3;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
*out++ = ' ';
|
||||
in++;
|
||||
length--;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (*in & 0x80) goto badsyntax;
|
||||
*out++ = *in++;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
*out++ = '\0';
|
||||
|
||||
for (out = dest; *out ; ++out) {
|
||||
if (*out == '\t')
|
||||
*out = ' ';
|
||||
}
|
||||
|
||||
return dest;
|
||||
|
||||
badsyntax:
|
||||
PR_Free(dest);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// check if input is HZ (a 7bit encoding for simplified Chinese : RFC 1842))
|
||||
// or has ESC which may be an indication that it's in one of many ISO
|
||||
// 2022 7bit encodings (e.g. ISO-2022-JP(-2)/CN : see RFC 1468, 1922, 1554).
|
||||
// static
|
||||
PRBool Is7bitNonAsciiString(const char *input, PRUint32 len)
|
||||
{
|
||||
PRInt32 c;
|
||||
|
||||
enum { hz_initial, // No HZ seen yet
|
||||
hz_escaped, // Inside an HZ ~{ escape sequence
|
||||
hz_seen, // Have seen at least one complete HZ sequence
|
||||
hz_notpresent // Have seen something that is not legal HZ
|
||||
} hz_state;
|
||||
|
||||
hz_state = hz_initial;
|
||||
while (len) {
|
||||
c = PRUint8(*input++);
|
||||
len--;
|
||||
if (c & 0x80) return PR_FALSE;
|
||||
if (c == 0x1B) return PR_TRUE;
|
||||
if (c == '~') {
|
||||
switch (hz_state) {
|
||||
case hz_initial:
|
||||
case hz_seen:
|
||||
if (*input == '{') {
|
||||
hz_state = hz_escaped;
|
||||
} else if (*input == '~') {
|
||||
// ~~ is the HZ encoding of ~. Skip over second ~ as well
|
||||
hz_state = hz_seen;
|
||||
input++;
|
||||
len--;
|
||||
} else {
|
||||
hz_state = hz_notpresent;
|
||||
}
|
||||
break;
|
||||
|
||||
case hz_escaped:
|
||||
if (*input == '}') hz_state = hz_seen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hz_state == hz_seen;
|
||||
}
|
||||
|
||||
#define REPLACEMENT_CHAR "\357\277\275" // EF BF BD (UTF-8 encoding of U+FFFD)
|
||||
|
||||
// copy 'raw' sequences of octets in aInput to aOutput.
|
||||
// If aDefaultCharset is specified, the input is assumed to be in the
|
||||
// charset and converted to UTF-8. Otherwise, a blind copy is made.
|
||||
// If aDefaultCharset is specified, but the conversion to UTF-8
|
||||
// is not successful, each octet is replaced by Unicode replacement
|
||||
// chars. *aOutput is advanced by the number of output octets.
|
||||
// static
|
||||
void CopyRawHeader(const char *aInput, PRUint32 aLen,
|
||||
const char *aDefaultCharset, nsACString &aOutput)
|
||||
{
|
||||
PRInt32 c;
|
||||
|
||||
// If aDefaultCharset is not specified, make a blind copy.
|
||||
if (!aDefaultCharset || !*aDefaultCharset) {
|
||||
aOutput.Append(aInput, aLen);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy as long as it's US-ASCII. An ESC may indicate ISO 2022
|
||||
// A ~ may indicate it is HZ
|
||||
while (aLen && (c = PRUint8(*aInput++)) != 0x1B && c != '~' && !(c & 0x80)) {
|
||||
aOutput.Append(char(c));
|
||||
aLen--;
|
||||
}
|
||||
if (!aLen) {
|
||||
return;
|
||||
}
|
||||
aInput--;
|
||||
|
||||
// skip ASCIIness/UTF8ness test if aInput is supected to be a 7bit non-ascii
|
||||
// string and aDefaultCharset is a 7bit non-ascii charset.
|
||||
PRBool skipCheck = (c == 0x1B || c == '~') &&
|
||||
IS_7BIT_NON_ASCII_CHARSET(aDefaultCharset);
|
||||
|
||||
nsresult rv;
|
||||
// If not UTF-8, treat as default charset
|
||||
nsCOMPtr<nsIUTF8ConverterService>
|
||||
cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
|
||||
nsCAutoString utf8Text;
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
NS_SUCCEEDED(
|
||||
cvtUTF8->ConvertStringToUTF8(nsDependentCString(aInput, aLen),
|
||||
aDefaultCharset, skipCheck, utf8Text))) {
|
||||
aOutput.Append(utf8Text);
|
||||
} else { // replace each octet with Unicode replacement char in UTF-8.
|
||||
for (PRUint32 i = 0; i < aLen; i++) {
|
||||
aOutput.Append(REPLACEMENT_CHAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char especials[] = "()<>@,;:\\\"/[]?.=";
|
||||
|
||||
// |decode_mime_part2_str| taken from comi18n.c
|
||||
// Decode RFC2047-encoded words in the input and convert the result to UTF-8.
|
||||
// If aOverrideCharset is true, charset in RFC2047-encoded words is
|
||||
// ignored and aDefaultCharset is assumed, instead. aDefaultCharset
|
||||
// is also used to convert raw octets (without RFC 2047 encoding) to UTF-8.
|
||||
//static
|
||||
nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset,
|
||||
PRBool aOverrideCharset, nsACString &aResult)
|
||||
{
|
||||
const char *p, *q, *r;
|
||||
char *decodedText;
|
||||
const char *begin; // tracking pointer for where we are in the input buffer
|
||||
PRInt32 isLastEncodedWord = 0;
|
||||
const char *charsetStart, *charsetEnd;
|
||||
char charset[80];
|
||||
|
||||
// initialize charset name to an empty string
|
||||
charset[0] = '\0';
|
||||
|
||||
begin = aHeader;
|
||||
|
||||
// To avoid buffer realloc, if possible, set capacity in advance. No
|
||||
// matter what, more than 3x expansion can never happen for all charsets
|
||||
// supported by Mozilla. SCSU/BCSU with the sliding window set to a
|
||||
// non-BMP block may be exceptions, but Mozilla does not support them.
|
||||
// Neither any known mail/news program use them. Even if there's, we're
|
||||
// safe because we don't use a raw *char any more.
|
||||
aResult.SetCapacity(3 * strlen(aHeader));
|
||||
|
||||
while ((p = PL_strstr(begin, "=?")) != 0) {
|
||||
if (isLastEncodedWord) {
|
||||
// See if it's all whitespace.
|
||||
for (q = begin; q < p; ++q) {
|
||||
if (!PL_strchr(" \t\r\n", *q)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLastEncodedWord || q < p) {
|
||||
// copy the part before the encoded-word
|
||||
CopyRawHeader(begin, p - begin, aDefaultCharset, aResult);
|
||||
begin = p;
|
||||
}
|
||||
|
||||
p += 2;
|
||||
|
||||
// Get charset info
|
||||
charsetStart = p;
|
||||
charsetEnd = 0;
|
||||
for (q = p; *q != '?'; q++) {
|
||||
if (*q <= ' ' || PL_strchr(especials, *q)) {
|
||||
goto badsyntax;
|
||||
}
|
||||
|
||||
// RFC 2231 section 5
|
||||
if (!charsetEnd && *q == '*') {
|
||||
charsetEnd = q;
|
||||
}
|
||||
}
|
||||
if (!charsetEnd) {
|
||||
charsetEnd = q;
|
||||
}
|
||||
|
||||
// Check for too-long charset name
|
||||
if (PRUint32(charsetEnd - charsetStart) >= sizeof(charset))
|
||||
goto badsyntax;
|
||||
|
||||
memcpy(charset, charsetStart, charsetEnd - charsetStart);
|
||||
charset[charsetEnd - charsetStart] = 0;
|
||||
|
||||
q++;
|
||||
if (*q != 'Q' && *q != 'q' && *q != 'B' && *q != 'b')
|
||||
goto badsyntax;
|
||||
|
||||
if (q[1] != '?')
|
||||
goto badsyntax;
|
||||
|
||||
r = q;
|
||||
for (r = q + 2; *r != '?'; r++) {
|
||||
if (*r < ' ') goto badsyntax;
|
||||
}
|
||||
if (r[1] != '=')
|
||||
goto badsyntax;
|
||||
else if (r == q + 2) {
|
||||
// it's empty, skip
|
||||
begin = r + 2;
|
||||
isLastEncodedWord = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(*q == 'Q' || *q == 'q')
|
||||
decodedText = DecodeQ(q + 2, r - (q + 2));
|
||||
else
|
||||
decodedText = PL_Base64Decode(q + 2, r - (q + 2), nsnull);
|
||||
|
||||
if (decodedText == nsnull)
|
||||
goto badsyntax;
|
||||
|
||||
// Override charset if requested. Never override labeled UTF-8.
|
||||
// Use default charset instead of UNKNOWN-8BIT
|
||||
if ((aOverrideCharset && 0 != nsCRT::strcasecmp(charset, "UTF-8")) ||
|
||||
(aDefaultCharset && 0 == nsCRT::strcasecmp(charset, "UNKNOWN-8BIT"))) {
|
||||
PL_strncpy(charset, aDefaultCharset, sizeof(charset) - 1);
|
||||
charset[sizeof(charset) - 1] = '\0';
|
||||
}
|
||||
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIUTF8ConverterService>
|
||||
cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
|
||||
nsCAutoString utf8Text;
|
||||
// skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset.
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
NS_SUCCEEDED(
|
||||
cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText),
|
||||
charset, IS_7BIT_NON_ASCII_CHARSET(charset), utf8Text))) {
|
||||
aResult.Append(utf8Text);
|
||||
} else {
|
||||
aResult.Append(REPLACEMENT_CHAR);
|
||||
}
|
||||
}
|
||||
PR_Free(decodedText);
|
||||
begin = r + 2;
|
||||
isLastEncodedWord = 1;
|
||||
continue;
|
||||
|
||||
badsyntax:
|
||||
// copy the part before the encoded-word
|
||||
aResult.Append(begin, p - begin);
|
||||
begin = p;
|
||||
isLastEncodedWord = 0;
|
||||
}
|
||||
|
||||
// put the tail back
|
||||
CopyRawHeader(begin, strlen(begin), aDefaultCharset, aResult);
|
||||
|
||||
nsCAutoString tempStr(aResult);
|
||||
tempStr.ReplaceChar('\t', ' ');
|
||||
aResult = tempStr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Jungshik Shin <jshin@mailaps.org>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the NPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the NPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
|
||||
#ifndef __nsmimeheaderparamimpl_h___
|
||||
#define __nsmimeheaderparamimpl_h___
|
||||
class nsMIMEHeaderParamImpl : public nsIMIMEHeaderParam
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMIMEHEADERPARAM
|
||||
|
||||
nsMIMEHeaderParamImpl() {};
|
||||
virtual ~nsMIMEHeaderParamImpl() {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -45,6 +45,7 @@ REQUIRES = xpcom \
|
|||
intl \
|
||||
webshell \
|
||||
xpconnect \
|
||||
mimetype \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
|
|
@ -71,6 +71,9 @@
|
|||
#include "nsICategoryManager.h"
|
||||
#include "nsCExternalHandlerService.h" // contains contractids for the helper app service
|
||||
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
|
||||
|
||||
|
||||
|
@ -281,8 +284,6 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
|
|||
// could happen because the Content-Disposition header is set so, or, in the
|
||||
// future, because the user has specified external handling for the MIME
|
||||
// type.
|
||||
// XXXbz we need a utility function in necko for parsing content-disposition
|
||||
// headers, methinks.
|
||||
PRBool forceExternalHandling = PR_FALSE;
|
||||
nsCAutoString disposition;
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
|
||||
|
@ -302,39 +303,22 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest *request, nsISupports *
|
|||
|
||||
if (NS_SUCCEEDED(rv) && !disposition.IsEmpty())
|
||||
{
|
||||
nsCAutoString::const_iterator start, end;
|
||||
disposition.BeginReading(start);
|
||||
disposition.EndReading(end);
|
||||
// skip leading whitespace
|
||||
while (start != end && nsCRT::IsAsciiSpace(*start))
|
||||
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
++start;
|
||||
}
|
||||
nsCAutoString::const_iterator iter = start;
|
||||
// walk forward till we hit the next whitespace, semicolon, or
|
||||
// equals sign
|
||||
while (iter != end && *iter != ';' && *iter != '=' &&
|
||||
!nsCRT::IsAsciiSpace(*iter))
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (start != iter)
|
||||
{
|
||||
const nsACString & dispToken = Substring(start, iter);
|
||||
nsAutoString dispToken;
|
||||
// Get the disposition type
|
||||
rv = mimehdrpar->GetParameter(disposition, "", NS_LITERAL_CSTRING(""),
|
||||
PR_FALSE, nsnull, dispToken);
|
||||
// RFC 2183, section 2.8 says that an unknown disposition
|
||||
// value should be treated as "attachment"
|
||||
if (!dispToken.Equals(NS_LITERAL_CSTRING("inline"),
|
||||
nsCaseInsensitiveCStringComparator()) &&
|
||||
if (NS_FAILED(rv) || !dispToken.EqualsIgnoreCase("inline",6) &&
|
||||
// Broken sites just send
|
||||
// Content-Disposition: filename="file"
|
||||
// without a disposition token... screen those out.
|
||||
!dispToken.Equals(NS_LITERAL_CSTRING("filename"),
|
||||
nsCaseInsensitiveCStringComparator()))
|
||||
{
|
||||
!dispToken.EqualsIgnoreCase("filename", 8))
|
||||
// We have a content-disposition of "attachment" or unknown
|
||||
forceExternalHandling = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* vim:expandtab:shiftwidth=2:tabstop=3:
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
|
@ -80,6 +80,7 @@
|
|||
#include "nsIDOMWindow.h"
|
||||
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
|
||||
#include "nsIPrefService.h"
|
||||
|
||||
|
@ -991,90 +992,54 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel* aChan
|
|||
// disposition-type < ; name=value >* < ; filename=value > < ; name=value >*
|
||||
if ( NS_SUCCEEDED( rv ) && !disp.IsEmpty() )
|
||||
{
|
||||
nsCAutoString::const_iterator start, end;
|
||||
disp.BeginReading(start);
|
||||
disp.EndReading(end);
|
||||
// skip leading whitespace
|
||||
while (start != end && nsCRT::IsAsciiSpace(*start)) {
|
||||
++start;
|
||||
}
|
||||
nsCAutoString::const_iterator iter = start;
|
||||
// walk forward till we hit the next whitespace, semicolon, or
|
||||
// equals sign
|
||||
while (iter != end && *iter != ';' && *iter != '=' &&
|
||||
!nsCRT::IsAsciiSpace(*iter)) {
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (start != iter) {
|
||||
const nsACString & dispToken = Substring(start, iter);
|
||||
// RFC 2183, section 2.8 says that an unknown disposition
|
||||
// value should be treated as "attachment"
|
||||
if (!dispToken.Equals(NS_LITERAL_CSTRING("inline"),
|
||||
nsCaseInsensitiveCStringComparator()) &&
|
||||
// Broken sites just send
|
||||
// Content-Disposition: filename="file"
|
||||
// without a disposition token... screen those out.
|
||||
!dispToken.Equals(NS_LITERAL_CSTRING("filename"),
|
||||
nsCaseInsensitiveCStringComparator())) {
|
||||
// We have a content-disposition of "attachment" or unknown
|
||||
mHandlingAttachment = PR_TRUE;
|
||||
}
|
||||
nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
nsAutoString dispToken;
|
||||
// Get the disposition type
|
||||
rv = mimehdrpar->GetParameter(disp, "", NS_LITERAL_CSTRING(""), PR_FALSE,
|
||||
nsnull, dispToken);
|
||||
// RFC 2183, section 2.8 says that an unknown disposition
|
||||
// value should be treated as "attachment"
|
||||
if (NS_FAILED(rv) || !dispToken.EqualsIgnoreCase("inline", 6) &&
|
||||
// Broken sites just send
|
||||
// Content-Disposition: filename="file"
|
||||
// without a disposition token... screen those out.
|
||||
!dispToken.EqualsIgnoreCase("filename", 8))
|
||||
{
|
||||
// We have a content-disposition of "attachment" or unknown
|
||||
mHandlingAttachment = PR_TRUE;
|
||||
}
|
||||
|
||||
// We may not have a disposition type listed; some servers suck.
|
||||
// But they could have listed a filename anyway.
|
||||
disp.BeginReading(start);
|
||||
iter = end;
|
||||
nsCOMPtr<nsIURI> srcUri;
|
||||
GetSource(getter_AddRefs(srcUri));
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(srcUri);
|
||||
|
||||
if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("filename="),
|
||||
start,
|
||||
iter))
|
||||
{
|
||||
// The value is either a string with no whitespace or a string
|
||||
// in double quotes. See RFC 2183 and bug 66181.
|
||||
nsCAutoString fallbackCharset;
|
||||
nsAutoString fileName;
|
||||
if (url)
|
||||
url->GetOriginCharset(fallbackCharset);
|
||||
// Get the value of 'filename' parameter
|
||||
rv = mimehdrpar->GetParameter(disp, "filename", fallbackCharset,
|
||||
PR_TRUE, nsnull, fileName);
|
||||
if (NS_FAILED(rv) || fileName.IsEmpty())
|
||||
// Try 'name' parameter, instead.
|
||||
rv = mimehdrpar->GetParameter(disp, "name",fallbackCharset, PR_TRUE,
|
||||
nsnull, fileName);
|
||||
if (NS_FAILED(rv) || fileName.IsEmpty())
|
||||
return;
|
||||
|
||||
// Search for the ';' if it's not in double quotes, then walk
|
||||
// back past any whitespace
|
||||
if (iter != end) { // otherwise our filename is empty...
|
||||
char endChar = ';';
|
||||
if (*iter == '"') {
|
||||
endChar = '"';
|
||||
++iter; // since we had iter < end, this is not running us past the end of the string
|
||||
}
|
||||
start = iter;
|
||||
FindCharInReadable(endChar, iter, end);
|
||||
// Now start points at the beginning of the filename. iter
|
||||
// points to just past its end if the name was quoted. If we
|
||||
// looked for a semicolon, we need to step back past
|
||||
// whitespace.
|
||||
if (endChar == ';' && iter != start) {
|
||||
--iter;
|
||||
while (iter != start && nsCRT::IsAsciiSpace(*iter)) {
|
||||
--iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
if (iter != start) { // not empty
|
||||
// ONLY if we got here, will we remember the suggested file name...
|
||||
// The filename must be ASCII, see RFC 2231
|
||||
// We ignore the filename in the header if the filename contains raw 8bit.
|
||||
// (and keep the URI filename instead).
|
||||
const nsACString& newFileName = Substring(start, iter);
|
||||
if (IsASCII(newFileName))
|
||||
CopyASCIItoUCS2(newFileName, mSuggestedFileName);
|
||||
mSuggestedFileName = fileName;
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Make sure extension is still correct.
|
||||
EnsureSuggestedFileName();
|
||||
// Make sure extension is still correct.
|
||||
EnsureSuggestedFileName();
|
||||
#endif
|
||||
|
||||
// replace platform specific path separator and illegal characters to avoid any confusion
|
||||
mSuggestedFileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
|
||||
}
|
||||
}
|
||||
} // if we found a file name in the header disposition field
|
||||
// replace platform specific path separator and illegal characters to avoid any confusion
|
||||
mSuggestedFileName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '-');
|
||||
} // we had a disp header
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче