зеркало из https://github.com/mozilla/pjs.git
fix 166111 patch by ch.ey@gmx.net, r=bienvenu, sr=mscott fix handling of downloading of pop3 messages with non-standard line endings
This commit is contained in:
Родитель
c2b5d9f9c1
Коммит
235a74f646
|
@ -107,7 +107,6 @@ nsMsgLineBuffer::nsMsgLineBuffer(nsMsgLineBufferHandler *handler, PRBool convert
|
|||
m_handler = handler;
|
||||
m_convertNewlinesP = convertNewlinesP;
|
||||
m_lookingForCRLF = PR_TRUE;
|
||||
m_ignoreCRLFs = PR_FALSE;
|
||||
}
|
||||
|
||||
nsMsgLineBuffer::~nsMsgLineBuffer()
|
||||
|
@ -140,43 +139,40 @@ PRInt32 nsMsgLineBuffer::BufferInput(const char *net_buffer, PRInt32 net_buffer_
|
|||
const char *net_buffer_end = net_buffer + net_buffer_size;
|
||||
const char *newline = 0;
|
||||
const char *s;
|
||||
|
||||
if (!m_ignoreCRLFs)
|
||||
|
||||
for (s = net_buffer; s < net_buffer_end; s++)
|
||||
{
|
||||
for (s = net_buffer; s < net_buffer_end; s++)
|
||||
{
|
||||
if (m_lookingForCRLF) {
|
||||
/* Move forward in the buffer until the first newline.
|
||||
Stop when we see CRLF, CR, or LF, or the end of the buffer.
|
||||
*But*, if we see a lone CR at the *very end* of the buffer,
|
||||
treat this as if we had reached the end of the buffer without
|
||||
seeing a line terminator. This is to catch the case of the
|
||||
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
|
||||
*/
|
||||
if (*s == nsCRT::CR || *s == nsCRT::LF) {
|
||||
newline = s;
|
||||
if (newline[0] == nsCRT::CR) {
|
||||
if (s == net_buffer_end - 1) {
|
||||
/* CR at end - wait for the next character. */
|
||||
newline = 0;
|
||||
break;
|
||||
}
|
||||
else if (newline[1] == nsCRT::LF) {
|
||||
/* CRLF seen; swallow both. */
|
||||
newline++;
|
||||
}
|
||||
if (m_lookingForCRLF) {
|
||||
/* Move forward in the buffer until the first newline.
|
||||
Stop when we see CRLF, CR, or LF, or the end of the buffer.
|
||||
*But*, if we see a lone CR at the *very end* of the buffer,
|
||||
treat this as if we had reached the end of the buffer without
|
||||
seeing a line terminator. This is to catch the case of the
|
||||
buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
|
||||
*/
|
||||
if (*s == nsCRT::CR || *s == nsCRT::LF) {
|
||||
newline = s;
|
||||
if (newline[0] == nsCRT::CR) {
|
||||
if (s == net_buffer_end - 1) {
|
||||
/* CR at end - wait for the next character. */
|
||||
newline = 0;
|
||||
break;
|
||||
}
|
||||
else if (newline[1] == nsCRT::LF) {
|
||||
/* CRLF seen; swallow both. */
|
||||
newline++;
|
||||
}
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* if not looking for a CRLF, stop at CR or LF. (for example, when parsing the newsrc file). this fixes #9896, where we'd lose the last line of anything we'd parse that used CR as the line break. */
|
||||
if (*s == nsCRT::CR || *s == nsCRT::LF) {
|
||||
newline = s;
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* if not looking for a CRLF, stop at CR or LF. (for example, when parsing the newsrc file). this fixes #9896, where we'd lose the last line of anything we'd parse that used CR as the line break. */
|
||||
if (*s == nsCRT::CR || *s == nsCRT::LF) {
|
||||
newline = s;
|
||||
newline++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +328,7 @@ void nsMsgLineStreamBuffer::ClearBuffer()
|
|||
// Note to people wishing to modify this function: Be *VERY CAREFUL* this is a critical function used by all of
|
||||
// our mail protocols including imap, nntp, and pop. If you screw it up, you could break a lot of stuff.....
|
||||
|
||||
char * nsMsgLineStreamBuffer::ReadNextLine(nsIInputStream * aInputStream, PRUint32 &aNumBytesInLine, PRBool &aPauseForMoreData, nsresult *prv)
|
||||
char * nsMsgLineStreamBuffer::ReadNextLine(nsIInputStream * aInputStream, PRUint32 &aNumBytesInLine, PRBool &aPauseForMoreData, nsresult *prv, PRBool addLineTerminator)
|
||||
{
|
||||
// try to extract a line from m_inputBuffer. If we don't have an entire line,
|
||||
// then read more bytes out from the stream. If the stream is empty then wait
|
||||
|
@ -436,7 +432,7 @@ char * nsMsgLineStreamBuffer::ReadNextLine(nsIInputStream * aInputStream, PRUint
|
|||
aNumBytesInLine--;
|
||||
|
||||
// PR_CALLOC zeros out the allocated line
|
||||
char* newLine = (char*) PR_CALLOC(aNumBytesInLine+1);
|
||||
char* newLine = (char*) PR_CALLOC(aNumBytesInLine + (addLineTerminator ? MSG_LINEBREAK_LEN : 0) + 1);
|
||||
if (!newLine)
|
||||
{
|
||||
aNumBytesInLine = 0;
|
||||
|
@ -445,6 +441,11 @@ char * nsMsgLineStreamBuffer::ReadNextLine(nsIInputStream * aInputStream, PRUint
|
|||
}
|
||||
|
||||
memcpy(newLine, startOfLine, aNumBytesInLine); // copy the string into the new line buffer
|
||||
if (addLineTerminator)
|
||||
{
|
||||
memcpy(newLine + aNumBytesInLine, MSG_LINEBREAK, MSG_LINEBREAK_LEN);
|
||||
aNumBytesInLine += MSG_LINEBREAK_LEN;
|
||||
}
|
||||
|
||||
if (m_eatCRLFs)
|
||||
endOfLine += 1; // advance past LF or CR if we haven't already done so...
|
||||
|
|
|
@ -90,7 +90,6 @@ protected:
|
|||
nsMsgLineBufferHandler *m_handler;
|
||||
PRBool m_convertNewlinesP;
|
||||
PRBool m_lookingForCRLF;
|
||||
PRBool m_ignoreCRLFs;
|
||||
};
|
||||
|
||||
// I'm adding this utility class here for lack of a better place. This utility class is similar to nsMsgLineBuffer
|
||||
|
@ -122,7 +121,7 @@ public:
|
|||
// aEndOfLinetoken -- delimiter used to denote the end of a line.
|
||||
// aNumBytesInLine -- The number of bytes in the line returned
|
||||
// aPauseForMoreData -- There is not enough data in the stream to make a line at this time...
|
||||
char * ReadNextLine(nsIInputStream * aInputStream, PRUint32 &anumBytesInLine, PRBool &aPauseForMoreData, nsresult *rv = nsnull);
|
||||
char * ReadNextLine(nsIInputStream * aInputStream, PRUint32 &anumBytesInLine, PRBool &aPauseForMoreData, nsresult *rv = nsnull, PRBool addLineTerminator = PR_FALSE);
|
||||
nsresult GrowBuffer(PRInt32 desiredSize);
|
||||
void ClearBuffer();
|
||||
PRBool NextLineAvailable();
|
||||
|
|
|
@ -509,7 +509,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsMsgProtocol)
|
|||
|
||||
nsPop3Protocol::nsPop3Protocol(nsIURI* aURL)
|
||||
: nsMsgProtocol(aURL),
|
||||
nsMsgLineBuffer(NULL, PR_FALSE),
|
||||
m_bytesInMsgReceived(0),
|
||||
m_totalFolderSize(0),
|
||||
m_totalDownloadSize(0),
|
||||
|
@ -520,8 +519,6 @@ nsPop3Protocol::nsPop3Protocol(nsIURI* aURL)
|
|||
m_responseTimer(nsnull),
|
||||
m_responseTimeout(45)
|
||||
{
|
||||
SetLookingForCRLF(MSG_LINEBREAK_LEN == 2);
|
||||
m_ignoreCRLFs = PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult nsPop3Protocol::Initialize(nsIURI * aURL)
|
||||
|
@ -3020,21 +3017,22 @@ nsPop3Protocol::RetrResponse(nsIInputStream* inputStream,
|
|||
{
|
||||
if (m_pop3ConData->msg_closure)
|
||||
{
|
||||
m_ignoreCRLFs = PR_TRUE;
|
||||
PRInt32 res = BufferInput(line, buffer_size);
|
||||
if (res < 0) return(Error(POP3_MESSAGE_WRITE_ERROR));
|
||||
m_ignoreCRLFs = PR_FALSE;
|
||||
res = BufferInput(MSG_LINEBREAK, MSG_LINEBREAK_LEN);
|
||||
if (res < 0) return(Error(POP3_MESSAGE_WRITE_ERROR));
|
||||
rv = HandleLine(line, buffer_size);
|
||||
if (NS_FAILED(rv))
|
||||
return (Error(POP3_MESSAGE_WRITE_ERROR));
|
||||
|
||||
// not really sure we always had CRLF in input since we
|
||||
// also treat a single LF as line ending!
|
||||
m_pop3ConData->parsed_bytes += (buffer_size+2); // including CRLF
|
||||
}
|
||||
|
||||
// now read in the next line
|
||||
PR_Free(line);
|
||||
line = m_lineStreamBuffer->ReadNextLine(inputStream, buffer_size,
|
||||
pauseForMoreData);
|
||||
pauseForMoreData, &rv, PR_TRUE);
|
||||
PR_LOG(POP3LOGMODULE, PR_LOG_ALWAYS,("RECV: %s", line));
|
||||
// not really sure we always had CRLF in input since we
|
||||
// also treat a single LF as line ending!
|
||||
status += (buffer_size+2); // including CRLF
|
||||
} while (line);
|
||||
}
|
||||
|
@ -3068,8 +3066,8 @@ nsPop3Protocol::RetrResponse(nsIInputStream* inputStream,
|
|||
// (Note: This is only a temp hack until the underlying XPCOM is
|
||||
// fixed to return errors)
|
||||
|
||||
if(NS_FAILED(rv))
|
||||
return(Error(POP3_MESSAGE_WRITE_ERROR));
|
||||
if (NS_FAILED(rv))
|
||||
return (Error(POP3_MESSAGE_WRITE_ERROR));
|
||||
|
||||
m_pop3ConData->msg_closure = 0;
|
||||
}
|
||||
|
@ -3195,50 +3193,41 @@ nsPop3Protocol::TopResponse(nsIInputStream* inputStream, PRUint32 length)
|
|||
return RetrResponse(inputStream, length);
|
||||
}
|
||||
|
||||
|
||||
PRInt32
|
||||
/* line is handed over as null-terminated string with MSG_LINEBREAK */
|
||||
nsresult
|
||||
nsPop3Protocol::HandleLine(char *line, PRUint32 line_length)
|
||||
{
|
||||
nsresult rv;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(m_pop3ConData->msg_closure, "m_pop3ConData->msg_closure is null in nsPop3Protocol::HandleLine()");
|
||||
if (!m_pop3ConData->msg_closure)
|
||||
return -1;
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (!m_senderInfo.IsEmpty() && !m_pop3ConData->seenFromHeader)
|
||||
{
|
||||
if (line_length > 6 && !PL_strncasecmp("From: ", line, 6))
|
||||
{
|
||||
/* Zzzzz PL_strstr only works with NULL terminated string. Since,
|
||||
* the last character of a line is either a carriage return
|
||||
* or a linefeed. Temporary setting the last character of the
|
||||
* line to NULL and later setting it back should be the right
|
||||
* thing to do.
|
||||
*/
|
||||
char ch = line[line_length-1];
|
||||
line[line_length-1] = 0;
|
||||
m_pop3ConData->seenFromHeader = PR_TRUE;
|
||||
if (PL_strstr(line, m_senderInfo.get()) == NULL)
|
||||
m_nsIPop3Sink->SetSenderAuthedFlag(m_pop3ConData->msg_closure,
|
||||
PR_FALSE);
|
||||
line[line_length-1] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
// line contains only dot and linebreak -> message end
|
||||
if (line[0] == '.' && line_length == 1 + MSG_LINEBREAK_LEN)
|
||||
// line contains only a single dot and linebreak -> message end
|
||||
if (line_length == 1 + MSG_LINEBREAK_LEN && line[0] == '.')
|
||||
{
|
||||
m_pop3ConData->assumed_end = PR_TRUE; /* in case byte count from server is */
|
||||
/* wrong, mark we may have had the end */
|
||||
if (!m_pop3ConData->dot_fix || m_pop3ConData->truncating_cur_msg ||
|
||||
(m_pop3ConData->parsed_bytes >= (m_pop3ConData->pop3_size -3)))
|
||||
{
|
||||
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url, &rv);
|
||||
nsCOMPtr<nsIMsgWindow> msgWindow;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
|
||||
rv = m_nsIPop3Sink->IncorporateComplete(msgWindow,
|
||||
m_pop3ConData->truncating_cur_msg ? m_pop3ConData->cur_msg_size : 0);
|
||||
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(m_url, &rv);
|
||||
nsCOMPtr<nsIMsgWindow> msgWindow;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mailnewsUrl->GetMsgWindow(getter_AddRefs(msgWindow));
|
||||
rv = m_nsIPop3Sink->IncorporateComplete(msgWindow,
|
||||
m_pop3ConData->truncating_cur_msg ? m_pop3ConData->cur_msg_size : 0);
|
||||
|
||||
// The following was added to prevent the loss of Data when we try
|
||||
// and write to somewhere we dont have write access error to (See
|
||||
|
@ -3246,35 +3235,25 @@ nsPop3Protocol::HandleLine(char *line, PRUint32 line_length)
|
|||
// (Note: This is only a temp hack until the underlying XPCOM is
|
||||
// fixed to return errors)
|
||||
|
||||
if(NS_FAILED(rv))
|
||||
return(Error((rv == NS_MSG_ERROR_COPYING_FROM_TMP_DOWNLOAD)
|
||||
? POP3_TMP_DOWNLOAD_FAILED
|
||||
: POP3_MESSAGE_WRITE_ERROR));
|
||||
if (NS_FAILED(rv))
|
||||
return (Error((rv == NS_MSG_ERROR_COPYING_FROM_TMP_DOWNLOAD)
|
||||
? POP3_TMP_DOWNLOAD_FAILED
|
||||
: POP3_MESSAGE_WRITE_ERROR));
|
||||
|
||||
m_pop3ConData->msg_closure = 0;
|
||||
return 0;
|
||||
m_pop3ConData->msg_closure = nsnull;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
/*When examining a multi-line response, the client checks
|
||||
to see if the line begins with the termination octet. If so and if
|
||||
octets other than CRLF follow, the first octet of the line (the
|
||||
termination octet) is stripped away.*/
|
||||
else if (line_length > 1 && line[0] == '.' && line[1] == '.' )
|
||||
{
|
||||
PRUint32 i=0;
|
||||
while ( i < line_length -1 ){
|
||||
line[i] = line[i+1];
|
||||
i++;
|
||||
}
|
||||
line[i] = '\0';
|
||||
line_length -= 1;
|
||||
/* Check if the line begins with the termination octet. If so
|
||||
and if another termination octet follows, we step over the
|
||||
first occurence of it. */
|
||||
else if (line_length > 1 && line[0] == '.' && line[1] == '.') {
|
||||
line++;
|
||||
line_length--;
|
||||
|
||||
}
|
||||
rv = m_nsIPop3Sink->IncorporateWrite(line, line_length);
|
||||
if(NS_FAILED(rv))
|
||||
return(Error(POP3_MESSAGE_WRITE_ERROR));
|
||||
|
||||
return 0;
|
||||
|
||||
return m_nsIPop3Sink->IncorporateWrite(line, line_length);
|
||||
}
|
||||
|
||||
PRInt32 nsPop3Protocol::SendDele()
|
||||
|
|
|
@ -281,7 +281,7 @@ typedef struct _Pop3ConData {
|
|||
#define POP3_AUTH_FAILURE 0x00000008 /* extended code said authentication failed */
|
||||
|
||||
|
||||
class nsPop3Protocol : public nsMsgProtocol, public nsMsgLineBuffer, public nsIPop3Protocol
|
||||
class nsPop3Protocol : public nsMsgProtocol, public nsIPop3Protocol
|
||||
{
|
||||
public:
|
||||
nsPop3Protocol(nsIURI* aURL);
|
||||
|
@ -301,8 +301,6 @@ public:
|
|||
NS_IMETHOD OnTransportStatus(nsITransport *transport, nsresult status, PRUint32 progress, PRUint32 progressMax);
|
||||
NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports * aContext, nsresult aStatus);
|
||||
NS_IMETHOD Cancel(nsresult status);
|
||||
// for nsMsgLineBuffer
|
||||
virtual PRInt32 HandleLine(char *line, PRUint32 line_length);
|
||||
|
||||
static void MarkMsgInHashTable(PLHashTable *hashTable, const Pop3UidlEntry *uidl,
|
||||
PRBool *changed);
|
||||
|
@ -365,6 +363,8 @@ private:
|
|||
void SetResponseTimer();
|
||||
void CancelResponseTimer();
|
||||
|
||||
nsresult HandleLine(char *line, PRUint32 line_length);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Begin Pop3 protocol state handlers
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -2422,14 +2422,14 @@ PRInt32 nsNNTPProtocol::BeginArticle()
|
|||
|
||||
PRInt32 nsNNTPProtocol::DisplayArticle(nsIInputStream * inputStream, PRUint32 length)
|
||||
{
|
||||
PRUint32 status = 0;
|
||||
PRUint32 line_length = 0;
|
||||
|
||||
PRBool pauseForMoreData = PR_FALSE;
|
||||
if (m_channelListener)
|
||||
{
|
||||
|
||||
char *line = m_lineStreamBuffer->ReadNextLine(inputStream, status, pauseForMoreData);
|
||||
if(pauseForMoreData)
|
||||
nsresult rv = NS_OK;
|
||||
char *line = m_lineStreamBuffer->ReadNextLine(inputStream, line_length, pauseForMoreData, &rv, PR_TRUE);
|
||||
if (pauseForMoreData)
|
||||
{
|
||||
PRUint32 inlength = 0;
|
||||
mDisplayInputStream->Available(&inlength);
|
||||
|
@ -2437,13 +2437,14 @@ PRInt32 nsNNTPProtocol::DisplayArticle(nsIInputStream * inputStream, PRUint32 le
|
|||
m_channelListener->OnDataAvailable(this, m_channelContext, mDisplayInputStream, 0, inlength);
|
||||
SetFlag(NNTP_PAUSE_FOR_READ);
|
||||
PR_Free(line);
|
||||
return status;
|
||||
return line_length;
|
||||
}
|
||||
|
||||
|
||||
if (m_newsFolder)
|
||||
m_newsFolder->NotifyDownloadedLine(line, m_key);
|
||||
|
||||
if (line[0] == '.' && line[1] == 0)
|
||||
|
||||
// line only contains a single dot -> message end
|
||||
if (line_length == 1 + MSG_LINEBREAK_LEN && line[0] == '.')
|
||||
{
|
||||
m_nextState = NEWS_DONE;
|
||||
|
||||
|
@ -2454,23 +2455,22 @@ PRInt32 nsNNTPProtocol::DisplayArticle(nsIInputStream * inputStream, PRUint32 le
|
|||
if (inlength > 0) // broadcast our batched up ODA changes
|
||||
m_channelListener->OnDataAvailable(this, m_channelContext, mDisplayInputStream, 0, inlength);
|
||||
PR_Free(line);
|
||||
return status;
|
||||
return line_length;
|
||||
}
|
||||
else // we aren't finished with the message yet
|
||||
{
|
||||
PRUint32 count = 0;
|
||||
|
||||
|
||||
// skip over the quoted '.'
|
||||
if (line[0] == '.')
|
||||
mDisplayOutputStream->Write(line+1, PL_strlen(line)-1, &count);
|
||||
if (line_length > 1 && line[0] == '.' && line[1] == '.')
|
||||
mDisplayOutputStream->Write(line+1, line_length-1, &count);
|
||||
else
|
||||
mDisplayOutputStream->Write(line, PL_strlen(line), &count);
|
||||
mDisplayOutputStream->Write(MSG_LINEBREAK, PL_strlen(MSG_LINEBREAK), &count);
|
||||
mDisplayOutputStream->Write(line, line_length, &count);
|
||||
}
|
||||
|
||||
|
||||
PR_Free(line);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче