зеркало из https://github.com/mozilla/gecko-dev.git
Bug #366016 --> reduce quoted text in our message preview string to "..."
Bug #346873 --> decode quoted printable and base64 when extracting the message preview text (patch by bienvenu) sr=bienvenu
This commit is contained in:
Родитель
2f5e88463f
Коммит
3d790db002
|
@ -71,7 +71,7 @@ typedef long nsMsgBiffState;
|
|||
// enumerated type for determining if a message has been replied to, forwarded, etc.
|
||||
typedef long nsMsgDispositionState;
|
||||
|
||||
[scriptable, uuid(4C4ECEC2-4BC7-4C9A-82CE-DB74A28F9E03)]
|
||||
[scriptable, uuid(913D683A-206F-4c91-9B10-3FC4CAEA644E)]
|
||||
interface nsIMsgFolder : nsICollection {
|
||||
|
||||
const nsMsgBiffState nsMsgBiffState_NewMail = 0; // User has new mail waiting.
|
||||
|
@ -497,11 +497,23 @@ const nsMsgBiffState nsMsgBiffState_Unknown = 2; // We dunno whether there is ne
|
|||
// would figure out the diffs, but these methods might be more convenient.
|
||||
void addKeywordToMessages(in nsISupportsArray aMessages, in string aKeyword);
|
||||
void removeKeywordFromMessages(in nsISupportsArray aMessages, in string aKeyword);
|
||||
ACString getMsgTextFromStream(in nsIMsgDBHdr aMsgHdr, in nsIInputStream aStream, in long aBytesToRead, in long aMaxOutputLen);
|
||||
|
||||
/**
|
||||
* Extract the message preview text from aStream, storing it as a string property
|
||||
* on aMsgHdr.
|
||||
*
|
||||
* @param aMsgHdr
|
||||
* @param aStream
|
||||
* @param aBytesToRead number of bytes to read from the stream
|
||||
* @param aMaxOutputLen desired length of the converted message text. Used to control how many characters
|
||||
* of msg text we want to store.
|
||||
* @param aCompressQuotes Replace quotes and citations with " ... " in the preview text
|
||||
*/
|
||||
ACString getMsgTextFromStream(in nsIMsgDBHdr aMsgHdr, in nsIInputStream aStream,
|
||||
in long aBytesToRead, in long aMaxOutputLen, in boolean aCompressQuotes);
|
||||
|
||||
// this allows a folder to have a special identity. E.g., you might want to
|
||||
// associate an identity with a particular newsgroup, or for IMAP shared folders in
|
||||
// the other users namespace, you might want to create a delegated identity
|
||||
readonly attribute nsIMsgIdentity customIdentity;
|
||||
|
||||
};
|
||||
|
|
|
@ -62,7 +62,6 @@ public:
|
|||
NS_DECL_NSIMSGSEARCHTERM
|
||||
|
||||
|
||||
void StripQuotedPrintable (unsigned char*);
|
||||
PRInt32 GetNextIMAPOfflineMsgLine (char * buf, int bufferSize, int msgOffset, nsIMsgDBHdr * msg, nsIMsgDatabase * db);
|
||||
|
||||
|
||||
|
|
|
@ -677,64 +677,6 @@ nsresult nsMsgSearchTerm::DeStreamNew (char *inStream, PRInt16 /*length*/)
|
|||
}
|
||||
|
||||
|
||||
void nsMsgSearchTerm::StripQuotedPrintable (unsigned char *src)
|
||||
{
|
||||
// decode quoted printable text in place
|
||||
|
||||
if (!*src)
|
||||
return;
|
||||
unsigned char *dest = src;
|
||||
int srcIdx = 0, destIdx = 0;
|
||||
|
||||
while (src[srcIdx] != 0)
|
||||
{
|
||||
if (src[srcIdx] == '=')
|
||||
{
|
||||
unsigned char *token = &src[srcIdx];
|
||||
unsigned char c = 0;
|
||||
|
||||
// decode the first quoted char
|
||||
if (token[1] >= '0' && token[1] <= '9')
|
||||
c = token[1] - '0';
|
||||
else if (token[1] >= 'A' && token[1] <= 'F')
|
||||
c = token[1] - ('A' - 10);
|
||||
else if (token[1] >= 'a' && token[1] <= 'f')
|
||||
c = token[1] - ('a' - 10);
|
||||
else
|
||||
{
|
||||
// first char after '=' isn't hex. copy the '=' as a normal char and keep going
|
||||
dest[destIdx++] = src[srcIdx++]; // aka token[0]
|
||||
continue;
|
||||
}
|
||||
|
||||
// decode the second quoted char
|
||||
c = (c << 4);
|
||||
if (token[2] >= '0' && token[2] <= '9')
|
||||
c += token[2] - '0';
|
||||
else if (token[2] >= 'A' && token[2] <= 'F')
|
||||
c += token[2] - ('A' - 10);
|
||||
else if (token[2] >= 'a' && token[2] <= 'f')
|
||||
c += token[2] - ('a' - 10);
|
||||
else
|
||||
{
|
||||
// second char after '=' isn't hex. copy the '=' as a normal char and keep going
|
||||
dest[destIdx++] = src[srcIdx++]; // aka token[0]
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we got here, we successfully decoded a quoted printable sequence,
|
||||
// so bump each pointer past it and move on to the next char;
|
||||
dest[destIdx++] = c;
|
||||
srcIdx += 3;
|
||||
|
||||
}
|
||||
else
|
||||
dest[destIdx++] = src[srcIdx++];
|
||||
}
|
||||
|
||||
dest[destIdx] = src[srcIdx]; // null terminate
|
||||
}
|
||||
|
||||
// Looks in the MessageDB for the user specified arbitrary header, if it finds the header, it then looks for a match against
|
||||
// the value for the header.
|
||||
nsresult nsMsgSearchTerm::MatchArbitraryHeader (nsIMsgSearchScopeTerm *scope,
|
||||
|
@ -863,7 +805,7 @@ nsresult nsMsgSearchTerm::MatchBody (nsIMsgSearchScopeTerm *scope, PRUint32 offs
|
|||
{
|
||||
// Do in-place decoding of quoted printable
|
||||
if (isQuotedPrintable)
|
||||
StripQuotedPrintable ((unsigned char*)buf.get());
|
||||
MsgStripQuotedPrintable ((unsigned char*)buf.get());
|
||||
nsCString compare(buf);
|
||||
// ConvertToUnicode(charset, buf, compare);
|
||||
if (!compare.IsEmpty()) {
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsMsgI18N.h"
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
#include "plbase64.h"
|
||||
#include <time.h>
|
||||
|
||||
#define oneHour 3600000000U
|
||||
|
@ -5146,7 +5147,11 @@ NS_IMETHODIMP nsMsgDBFolder::FetchMsgPreviewText(nsMsgKey *aKeysToFetch, PRUint3
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMsgDBFolder::GetMsgTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputStream *stream, PRInt32 bytesToRead, PRInt32 aMaxOutputLen, nsACString &aMsgText)
|
||||
NS_IMETHODIMP nsMsgDBFolder::GetMsgTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputStream *stream,
|
||||
PRInt32 bytesToRead,
|
||||
PRInt32 aMaxOutputLen,
|
||||
PRBool aCompressQuotes,
|
||||
nsACString &aMsgText)
|
||||
{
|
||||
/*
|
||||
1. non mime message - the message body starts after the blank line following the headers.
|
||||
|
@ -5154,30 +5159,30 @@ NS_IMETHODIMP nsMsgDBFolder::GetMsgTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputS
|
|||
advance past its headers, and treat the next few lines as the text.
|
||||
3. mime message, text/plain - body follows headers
|
||||
4. multipart/mixed - scan past boundary, treat next part as body.
|
||||
|
||||
TODO need to worry about quoted printable and other encodings,
|
||||
so look for content transfer encoding.
|
||||
*/
|
||||
|
||||
// If we've got a header charset, we'll use that, otherwise we'll look for one in
|
||||
// the mime parts.
|
||||
nsXPIDLCString strCharset;
|
||||
nsCString msgText;
|
||||
msgHdr->GetCharset(getter_Copies(strCharset));
|
||||
nsAutoString charset (NS_ConvertUTF8toUTF16(strCharset.get()));
|
||||
|
||||
// If we've got a header charset use it, otherwise look for one in the mime parts.
|
||||
PRUint32 len;
|
||||
msgHdr->GetMessageSize(&len);
|
||||
nsLineBuffer<char> *lineBuffer;
|
||||
|
||||
|
||||
nsresult rv = NS_InitLineBuffer(&lineBuffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
nsXPIDLCString strCharset;
|
||||
msgHdr->GetCharset(getter_Copies(strCharset));
|
||||
nsAutoString charset (NS_ConvertUTF8toUTF16(strCharset.get()));
|
||||
|
||||
nsCString msgText;
|
||||
nsCAutoString encoding;
|
||||
nsCAutoString boundary;
|
||||
nsCAutoString curLine;
|
||||
|
||||
// might want to use a state var instead of bools.
|
||||
PRBool inMsgBody = PR_FALSE, msgBodyIsHtml = PR_FALSE, lookingForBoundary = PR_FALSE;
|
||||
PRBool haveBoundary = PR_FALSE;
|
||||
PRBool isBase64 = PR_FALSE;
|
||||
PRBool reachedEndBody = bytesToRead >= len;
|
||||
PRBool more = PR_TRUE;
|
||||
while (len > 0 && more)
|
||||
{
|
||||
|
@ -5208,11 +5213,15 @@ NS_IMETHODIMP nsMsgDBFolder::GetMsgTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputS
|
|||
if (inMsgBody)
|
||||
{
|
||||
if (!boundary.IsEmpty() && boundary.Equals(curLine))
|
||||
{
|
||||
reachedEndBody = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
msgText.Append(curLine);
|
||||
msgText.Append(" "); // convert each end of line delimter into a space
|
||||
// how much html should we parse for text? 2K? 4K?
|
||||
if (msgText.Length() > bytesToRead || (!msgBodyIsHtml && msgText.Length() > aMaxOutputLen))
|
||||
if (!isBase64) // don't append a LF for base64 encoded text
|
||||
msgText.Append(nsCRT::LF); // put a LF back, we'll strip this out later
|
||||
|
||||
if (msgText.Length() > bytesToRead)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
@ -5238,67 +5247,177 @@ NS_IMETHODIMP nsMsgDBFolder::GetMsgTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputS
|
|||
mimehdrpar->GetParameter(curLine, "charset", EmptyCString(), false, nsnull, charset);
|
||||
if (FindInReadable(NS_LITERAL_CSTRING("text/html"), curLine,
|
||||
nsCaseInsensitiveCStringComparator()))
|
||||
{
|
||||
msgBodyIsHtml = PR_TRUE;
|
||||
// bodyFollowsHeaders = PR_TRUE;
|
||||
}
|
||||
else if (FindInReadable(NS_LITERAL_CSTRING("text/plain"), curLine,
|
||||
nsCaseInsensitiveCStringComparator()))
|
||||
/* bodyFollowsHeaders = PR_TRUE */;
|
||||
else if (FindInReadable(NS_LITERAL_CSTRING("multipart/"), curLine,
|
||||
nsCaseInsensitiveCStringComparator()))
|
||||
{
|
||||
lookingForBoundary = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else if (StringBeginsWith(curLine, NS_LITERAL_CSTRING("Content-Transfer-Encoding:"),
|
||||
nsCaseInsensitiveCStringComparator()))
|
||||
{
|
||||
curLine.Right(encoding, curLine.Length() - 27);
|
||||
if (encoding.EqualsLiteral("base64"))
|
||||
isBase64 = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: in order to convert from a specific charset to UTF-8 we have to go through unicode first.
|
||||
nsAutoString unicodeMsgBodyStr;
|
||||
// if the snippet is encoded, decode it
|
||||
if (!encoding.IsEmpty())
|
||||
decodeMsgSnippet(encoding, !reachedEndBody, msgText);
|
||||
|
||||
// In order to turn our snippet into unicode, we need to convert it from the charset we
|
||||
// detected earlier.
|
||||
nsString unicodeMsgBodyStr;
|
||||
ConvertToUnicode(NS_ConvertUTF16toUTF8(charset).get(), msgText, unicodeMsgBodyStr);
|
||||
|
||||
// now we've got a msg body. If it's html, convert it to plain text.
|
||||
// Then, set the previewProperty on the msg hdr to the plain text.
|
||||
if (msgBodyIsHtml)
|
||||
{
|
||||
nsAutoString bodyText;
|
||||
nsresult rv = NS_OK;
|
||||
// Create a parser
|
||||
nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create the appropriate output sink
|
||||
nsCOMPtr<nsIContentSink> sink = do_CreateInstance(NS_PLAINTEXTSINK_CONTRACTID,&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHTMLToTextSink> textSink(do_QueryInterface(sink));
|
||||
NS_ENSURE_TRUE(textSink, NS_ERROR_FAILURE);
|
||||
PRUint32 flags = nsIDocumentEncoder::OutputLFLineBreak
|
||||
| nsIDocumentEncoder::OutputNoScriptContent
|
||||
| nsIDocumentEncoder::OutputNoFramesContent
|
||||
| nsIDocumentEncoder::OutputBodyOnly;
|
||||
|
||||
textSink->Initialize(&bodyText, flags, 80);
|
||||
|
||||
parser->SetContentSink(sink);
|
||||
|
||||
nsAutoString msgBodyStr;
|
||||
rv = parser->Parse(unicodeMsgBodyStr, 0, NS_LITERAL_CSTRING("text/html"), PR_TRUE);
|
||||
// push bodyText back into unicodeMsgBodyStr
|
||||
unicodeMsgBodyStr.Assign(bodyText);
|
||||
}
|
||||
convertMsgSnippetToPlainText(unicodeMsgBodyStr);
|
||||
|
||||
// now convert back to utf-8 for storage
|
||||
CopyUTF16toUTF8(unicodeMsgBodyStr, aMsgText);
|
||||
// step 3, optionally remove quoted text from the snippet
|
||||
nsString compressedQuotesMsgStr;
|
||||
if (aCompressQuotes)
|
||||
compressQuotesInMsgSnippet(unicodeMsgBodyStr, compressedQuotesMsgStr);
|
||||
|
||||
// now convert back to utf-8 which is more convenient for storage
|
||||
CopyUTF16toUTF8(aCompressQuotes ? compressedQuotesMsgStr : unicodeMsgBodyStr, aMsgText);
|
||||
|
||||
// finally, truncate the string based on aMaxOutputLen
|
||||
if (aMsgText.Length() > aMaxOutputLen)
|
||||
aMsgText.Truncate(aMaxOutputLen);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* decodeMsgSnippet - helper function which applies the appropriate transfer decoding
|
||||
* to the message snippet based on aEncodingType. Currently handles
|
||||
* base64 and quoted-printable. If aEncodingType refers to an encoding we don't
|
||||
* handle, the message data is passed back unmodified.
|
||||
* @param aEncodingType the encoding type (base64, quoted-printable)
|
||||
* @param aIsComplete the snippet is actually the entire message so the decoder
|
||||
* doesn't have to worry about partial data
|
||||
* @param aMsgSnippet in/out argument. The encoded msg snippet and then the decoded snippet
|
||||
*/
|
||||
void nsMsgDBFolder::decodeMsgSnippet(const nsACString& aEncodingType, PRBool aIsComplete, nsCString& aMsgSnippet)
|
||||
{
|
||||
if (!aEncodingType.IsEmpty())
|
||||
{
|
||||
if (aEncodingType.EqualsLiteral("base64"))
|
||||
{
|
||||
PRInt32 base64Len = aMsgSnippet.Length();
|
||||
if (aIsComplete)
|
||||
base64Len -= base64Len % 4;
|
||||
char *decodedBody = PL_Base64Decode(aMsgSnippet.get(), base64Len, nsnull);
|
||||
if (decodedBody)
|
||||
aMsgSnippet.Adopt(decodedBody);
|
||||
|
||||
// base64 encoded message haven't had line endings converted to LFs yet.
|
||||
aMsgSnippet.ReplaceChar(nsCRT::CR, nsCRT::LF);
|
||||
|
||||
}
|
||||
else if (aEncodingType.EqualsLiteral("quoted-printable"))
|
||||
{
|
||||
// giant hack - decode in place, and truncate string.
|
||||
MsgStripQuotedPrintable((unsigned char *) aMsgSnippet.get());
|
||||
aMsgSnippet.Truncate(strlen(aMsgSnippet.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stripQuotesFromMsgSnippet - Reduces quoted reply text including the citation (Scott wrote:) from
|
||||
* the message snippet to " ... ". Assumes the snippet has been decoded and converted to
|
||||
* plain text.
|
||||
* @param aMsgSnippet in/out argument. The string to strip quotes from.
|
||||
*/
|
||||
void nsMsgDBFolder::compressQuotesInMsgSnippet(const nsString& aMsgSnippet, nsAString& aCompressedQuotes)
|
||||
{
|
||||
PRUint32 msgBodyStrLen = aMsgSnippet.Length();
|
||||
PRBool lastLineWasAQuote = PR_FALSE;
|
||||
PRUint32 offset = 0;
|
||||
PRUint32 lineFeedPos = 0;
|
||||
while (offset < msgBodyStrLen)
|
||||
{
|
||||
lineFeedPos = aMsgSnippet.FindChar(nsCRT::LF, offset);
|
||||
if (lineFeedPos != kNotFound)
|
||||
{
|
||||
const nsAString& currentLine = Substring(aMsgSnippet, offset, lineFeedPos - offset);
|
||||
// this catches quoted text ("> "), nested quotes of any level (">> ", ">>> ", ...)
|
||||
// it also catches empty line quoted text (">"). It might be over agressive and require
|
||||
// tweaking later.
|
||||
// Try to strip the citation. If the current line ends with a ':' and the next line
|
||||
// looks like a quoted reply (starts with a ">") skip the current line
|
||||
if (StringBeginsWith(currentLine, NS_LITERAL_STRING(">")) ||
|
||||
(lineFeedPos + 1 < msgBodyStrLen && lineFeedPos
|
||||
&& aMsgSnippet[lineFeedPos - 1] == PRUnichar(':')
|
||||
&& aMsgSnippet[lineFeedPos + 1] == PRUnichar('>')))
|
||||
{
|
||||
lastLineWasAQuote = PR_TRUE;
|
||||
}
|
||||
else if (!currentLine.IsEmpty())
|
||||
{
|
||||
if (lastLineWasAQuote)
|
||||
{
|
||||
aCompressedQuotes += NS_LITERAL_STRING(" ... ");
|
||||
lastLineWasAQuote = PR_FALSE;
|
||||
}
|
||||
|
||||
aCompressedQuotes += currentLine;
|
||||
aCompressedQuotes += PRUnichar(' '); // don't forget to substitute a space for the line feed
|
||||
}
|
||||
|
||||
offset = lineFeedPos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
aCompressedQuotes.Append(Substring(aMsgSnippet, offset, msgBodyStrLen - offset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* converts an html mail snippet to plain text
|
||||
* @param aMessageText - in place conversion
|
||||
*/
|
||||
nsresult nsMsgDBFolder::convertMsgSnippetToPlainText(nsAString& aMessageText)
|
||||
{
|
||||
nsString bodyText;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create a parser
|
||||
nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create the appropriate output sink
|
||||
nsCOMPtr<nsIContentSink> sink = do_CreateInstance(NS_PLAINTEXTSINK_CONTRACTID,&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHTMLToTextSink> textSink(do_QueryInterface(sink));
|
||||
NS_ENSURE_TRUE(textSink, NS_ERROR_FAILURE);
|
||||
PRUint32 flags = nsIDocumentEncoder::OutputLFLineBreak
|
||||
| nsIDocumentEncoder::OutputNoScriptContent
|
||||
| nsIDocumentEncoder::OutputNoFramesContent
|
||||
| nsIDocumentEncoder::OutputBodyOnly;
|
||||
|
||||
textSink->Initialize(&bodyText, flags, 80);
|
||||
parser->SetContentSink(sink);
|
||||
rv = parser->Parse(aMessageText, 0, NS_LITERAL_CSTRING("text/html"), PR_TRUE);
|
||||
aMessageText.Assign(bodyText);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsMsgDBFolder::GetMsgPreviewTextFromStream(nsIMsgDBHdr *msgHdr, nsIInputStream *stream)
|
||||
{
|
||||
nsCString msgBody;
|
||||
nsresult rv = GetMsgTextFromStream(msgHdr, stream, 2048, 255, msgBody);
|
||||
nsresult rv = GetMsgTextFromStream(msgHdr, stream, 2048, 255, PR_TRUE, msgBody);
|
||||
|
||||
// for grins, see if we already have a property
|
||||
nsXPIDLCString previewProp;
|
||||
msgHdr->GetStringProperty("preview", getter_Copies(previewProp));
|
||||
|
||||
// replaces all tabs and line returns with a space, then trims off leading and trailing white space
|
||||
msgBody.CompressWhitespace(PR_TRUE, PR_TRUE);
|
||||
msgHdr->SetStringProperty("preview", msgBody.get());
|
||||
|
@ -5360,7 +5479,7 @@ NS_IMETHODIMP nsMsgDBFolder::RemoveKeywordFromMessages(nsISupportsArray *aMessag
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsXPIDLCString keywords;
|
||||
// If the tag is also a label, we should remove the label too...
|
||||
PRBool keywordIsLabel = (!strncmp(aKeyword, "$label", 6) && aKeyword[6] >= '1' && aKeyword[6] <= '5');
|
||||
PRBool keywordIsLabel = (!PL_strncasecmp(aKeyword, "$label", 6) && aKeyword[6] >= '1' && aKeyword[6] <= '5');
|
||||
|
||||
for(PRUint32 i = 0; i < count; i++)
|
||||
{
|
||||
|
|
|
@ -115,6 +115,9 @@ protected:
|
|||
|
||||
virtual nsresult CreateBaseMessageURI(const char *aURI);
|
||||
|
||||
nsresult convertMsgSnippetToPlainText(nsAString& aMessageText);
|
||||
void compressQuotesInMsgSnippet(const nsString& aMessageText, nsAString& aCompressedQuotesStr);
|
||||
void decodeMsgSnippet(const nsACString& aEncodingType, PRBool aIsComplete, nsCString& aMsgSnippet);
|
||||
|
||||
// helper routine to parse the URI and update member variables
|
||||
nsresult parseURI(PRBool needServer=PR_FALSE);
|
||||
|
|
|
@ -84,8 +84,8 @@ static NS_DEFINE_CID(kCMailboxUrl, NS_MAILBOXURL_CID);
|
|||
static NS_DEFINE_CID(kCNntpUrlCID, NS_NNTPURL_CID);
|
||||
|
||||
#define ILLEGAL_FOLDER_CHARS ";#"
|
||||
#define ILLEGAL_FOLDER_CHARS_AS_FIRST_LETTER "."
|
||||
#define ILLEGAL_FOLDER_CHARS_AS_LAST_LETTER ".~"
|
||||
#define ILLEGAL_FOLDER_CHARS_AS_FIRST_LETTER "."
|
||||
#define ILLEGAL_FOLDER_CHARS_AS_LAST_LETTER ".~"
|
||||
|
||||
#define NS_PASSWORDMANAGER_CATEGORY "passwordmanager"
|
||||
static PRBool gInitPasswordManager = PR_FALSE;
|
||||
|
@ -342,16 +342,16 @@ nsresult NS_MsgHashIfNecessary(nsCAutoString &name)
|
|||
|
||||
// Need to check the first ('.') and last ('.' and '~') char
|
||||
if (illegalCharacterIndex == kNotFound)
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING (illegalFirstChars, ILLEGAL_FOLDER_CHARS_AS_FIRST_LETTER);
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING (illegalFirstChars, ILLEGAL_FOLDER_CHARS_AS_FIRST_LETTER);
|
||||
NS_NAMED_LITERAL_CSTRING (illegalLastChars, ILLEGAL_FOLDER_CHARS_AS_LAST_LETTER);
|
||||
|
||||
PRInt32 lastIndex = str.Length() - 1;
|
||||
PRInt32 lastIndex = str.Length() - 1;
|
||||
if(str.FindCharInSet(illegalFirstChars) == 0)
|
||||
illegalCharacterIndex = 0;
|
||||
else if(str.RFindCharInSet(illegalLastChars) == lastIndex)
|
||||
illegalCharacterIndex = lastIndex;
|
||||
else
|
||||
illegalCharacterIndex = lastIndex;
|
||||
else
|
||||
illegalCharacterIndex = -1;
|
||||
}
|
||||
|
||||
|
@ -396,17 +396,17 @@ nsresult NS_MsgHashIfNecessary(nsAutoString &name)
|
|||
|
||||
// Need to check the first ('.') and last ('.' and '~') char
|
||||
if (illegalCharacterIndex == kNotFound)
|
||||
{
|
||||
NS_NAMED_LITERAL_STRING (illegalFirstChars, ILLEGAL_FOLDER_CHARS_AS_FIRST_LETTER);
|
||||
{
|
||||
NS_NAMED_LITERAL_STRING (illegalFirstChars, ILLEGAL_FOLDER_CHARS_AS_FIRST_LETTER);
|
||||
NS_NAMED_LITERAL_STRING (illegalLastChars, ILLEGAL_FOLDER_CHARS_AS_LAST_LETTER);
|
||||
|
||||
PRInt32 lastIndex = name.Length() - 1;
|
||||
PRInt32 lastIndex = name.Length() - 1;
|
||||
if(name.FindCharInSet(illegalFirstChars) == 0)
|
||||
illegalCharacterIndex = 0;
|
||||
else if(name.RFindCharInSet(illegalLastChars) == lastIndex)
|
||||
illegalCharacterIndex = lastIndex;
|
||||
else
|
||||
illegalCharacterIndex = -1;
|
||||
illegalCharacterIndex = lastIndex;
|
||||
else
|
||||
illegalCharacterIndex = -1;
|
||||
}
|
||||
|
||||
char hashedname[9];
|
||||
|
@ -1481,4 +1481,62 @@ nsresult MsgMailboxGetURI(const char *nativepath, nsCString &mailboxUri)
|
|||
return mailboxUri.IsEmpty() ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_MSG_BASE void MsgStripQuotedPrintable (unsigned char *src)
|
||||
{
|
||||
// decode quoted printable text in place
|
||||
|
||||
if (!*src)
|
||||
return;
|
||||
unsigned char *dest = src;
|
||||
int srcIdx = 0, destIdx = 0;
|
||||
|
||||
while (src[srcIdx] != 0)
|
||||
{
|
||||
if (src[srcIdx] == '=')
|
||||
{
|
||||
unsigned char *token = &src[srcIdx];
|
||||
unsigned char c = 0;
|
||||
|
||||
// decode the first quoted char
|
||||
if (token[1] >= '0' && token[1] <= '9')
|
||||
c = token[1] - '0';
|
||||
else if (token[1] >= 'A' && token[1] <= 'F')
|
||||
c = token[1] - ('A' - 10);
|
||||
else if (token[1] >= 'a' && token[1] <= 'f')
|
||||
c = token[1] - ('a' - 10);
|
||||
else
|
||||
{
|
||||
// first char after '=' isn't hex. copy the '=' as a normal char and keep going
|
||||
dest[destIdx++] = src[srcIdx++]; // aka token[0]
|
||||
continue;
|
||||
}
|
||||
|
||||
// decode the second quoted char
|
||||
c = (c << 4);
|
||||
if (token[2] >= '0' && token[2] <= '9')
|
||||
c += token[2] - '0';
|
||||
else if (token[2] >= 'A' && token[2] <= 'F')
|
||||
c += token[2] - ('A' - 10);
|
||||
else if (token[2] >= 'a' && token[2] <= 'f')
|
||||
c += token[2] - ('a' - 10);
|
||||
else
|
||||
{
|
||||
// second char after '=' isn't hex. copy the '=' as a normal char and keep going
|
||||
dest[destIdx++] = src[srcIdx++]; // aka token[0]
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we got here, we successfully decoded a quoted printable sequence,
|
||||
// so bump each pointer past it and move on to the next char;
|
||||
dest[destIdx++] = c;
|
||||
srcIdx += 3;
|
||||
|
||||
}
|
||||
else
|
||||
dest[destIdx++] = src[srcIdx++];
|
||||
}
|
||||
|
||||
dest[destIdx] = src[srcIdx]; // null terminate
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,5 +194,7 @@ NS_MSG_BASE PRBool MsgHostDomainIsTrusted(nsCString &host, nsCString &trustedMai
|
|||
|
||||
NS_MSG_BASE nsresult MsgMailboxGetURI(const char *nativepath, nsCString &mailboxUri);
|
||||
|
||||
NS_MSG_BASE void MsgStripQuotedPrintable (unsigned char *src);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -3081,7 +3081,7 @@ nsImapProtocol::FetchMessage(const char * messageIds,
|
|||
PRInt32 numBytesToFetch;
|
||||
m_runningUrl->GetNumBytesToFetch(&numBytesToFetch);
|
||||
|
||||
commandString.Append(" %s (UID BODY.PEEK[HEADER.FIELDS (Content-Type)] BODY.PEEK[TEXT]<0.");
|
||||
commandString.Append(" %s (UID BODY.PEEK[HEADER.FIELDS (Content-Type Content-Transfer-Encoding)] BODY.PEEK[TEXT]<0.");
|
||||
commandString.AppendInt(numBytesToFetch);
|
||||
commandString.Append(">)");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче