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:
bienvenu%nventure.com 2005-02-04 15:45:56 +00:00
Родитель 759319ad37
Коммит 0b7fd0e665
5 изменённых файлов: 93 добавлений и 114 удалений

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

@ -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;
}