diff --git a/mailnews/local/src/nsMailboxProtocol.cpp b/mailnews/local/src/nsMailboxProtocol.cpp index 20f8adfbc2b..af08f83541e 100644 --- a/mailnews/local/src/nsMailboxProtocol.cpp +++ b/mailnews/local/src/nsMailboxProtocol.cpp @@ -24,6 +24,7 @@ #include "nsIOutputStream.h" #include "nsINetService.h" #include "nsIMsgDatabase.h" +#include "nsMsgLineBuffer.h" #include "nsIMessage.h" #include "nsMsgDBCID.h" @@ -79,15 +80,16 @@ nsMailboxProtocol::~nsMailboxProtocol() { // release all of our event sinks NS_IF_RELEASE(m_mailboxParser); - - // free our local state - PR_FREEIF(m_dataBuf); // free handles on all networking objects... NS_IF_RELEASE(m_outputStream); NS_IF_RELEASE(m_outputConsumer); NS_IF_RELEASE(m_transport); NS_IF_RELEASE(m_runningUrl); + + // free our local state + if (m_lineStreamBuffer) + delete m_lineStreamBuffer; } void nsMailboxProtocol::Initialize(nsIURL * aURL) @@ -136,10 +138,10 @@ void nsMailboxProtocol::Initialize(nsIURL * aURL) rv = m_transport->SetInputStreamConsumer((nsIStreamListener *) this); NS_ASSERTION(NS_SUCCEEDED(rv), "unable to register MAILBOX instance as a consumer on the socket"); - m_dataBuf = (char *) PR_Malloc(sizeof(char) * OUTPUT_BUFFER_SIZE); - m_dataBufSize = OUTPUT_BUFFER_SIZE; m_mailboxParser = nsnull; + m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, PR_TRUE); + m_nextState = MAILBOX_READ_FOLDER; m_initialState = MAILBOX_READ_FOLDER; @@ -245,55 +247,6 @@ NS_IMETHODIMP nsMailboxProtocol::OnStopBinding(nsIURL* aURL, nsresult aStatus, c // End of nsIStreamListenerSupport ////////////////////////////////////////////////////////////////////////////////////////////// -PRInt32 nsMailboxProtocol::ReadLine(nsIInputStream * inputStream, PRUint32 length, char ** line) -{ - // I haven't looked into writing this yet. We have a couple of possibilities: - // (1) insert ReadLine *yuck* into here or better yet into the nsIInputStream - // then we can just turn around and call it here. - // OR - // (2) we write "protocol" specific code for news which looks for a CRLF in the incoming - // stream. If it finds it, that's our new line that we put into @param line. We'd - // need a buffer (m_dataBuf) to store extra info read in from the stream..... - - // read out everything we've gotten back and return it in line...this won't work for much but it does - // get us going... - - // XXX: please don't hold this quick "algorithm" against me. I just want to read just one - // line for the stream. I promise this is ONLY temporary to test out NNTP. We need a generic - // way to read one line from a stream. For now I'm going to read out one character at a time. - // (I said it was only temporary =)) and test for newline... - - PRUint32 numBytesToRead = 0; // MAX # bytes to read from the stream - PRUint32 numBytesRead = 0; // total number bytes we have read from the stream during this call - inputStream->GetLength(&length); // refresh the length in case it has changed... - - if (length > OUTPUT_BUFFER_SIZE) - numBytesToRead = OUTPUT_BUFFER_SIZE; - else - numBytesToRead = length; - - m_dataBuf[0] = '\0'; - PRUint32 numBytesLastRead = 0; // total number of bytes read in the last cycle... - do - { - inputStream->Read(m_dataBuf + numBytesRead /* offset into m_dataBuf */, 1 /* read just one byte */, &numBytesLastRead); - numBytesRead += numBytesLastRead; - } while (numBytesRead <= numBytesToRead && numBytesLastRead > 0 && m_dataBuf[numBytesRead-1] != '\n'); - - m_dataBuf[numBytesRead] = '\0'; // null terminate the string. - - // oops....we also want to eat up the '\n' and the \r'... - if (numBytesRead > 1 && m_dataBuf[numBytesRead-2] == '\r') - m_dataBuf[numBytesRead-2] = '\0'; // hit both cr and lf... - else - if (numBytesRead > 0 && (m_dataBuf[numBytesRead-1] == '\r' || m_dataBuf[numBytesRead-1] == '\n')) - m_dataBuf[numBytesRead-1] = '\0'; - - if (line) - *line = m_dataBuf; - return numBytesRead; -} - /* * Writes the data contained in dataBuffer into the current output stream. It also informs * the transport layer that this data is now available for transmission. @@ -481,7 +434,7 @@ PRInt32 nsMailboxProtocol::ReadFolderResponse(nsIInputStream * inputStream, PRUi PRInt32 nsMailboxProtocol::ReadMessageResponse(nsIInputStream * inputStream, PRUint32 length) { - char *line; + char *line = nsnull; PRInt32 status = 0; nsresult rv = NS_OK; @@ -495,54 +448,20 @@ PRInt32 nsMailboxProtocol::ReadMessageResponse(nsIInputStream * inputStream, PRU } else { - char outputBuffer[OUTPUT_BUFFER_SIZE]; + PRBool pauseForMoreData = PR_FALSE; do { - status = ReadLine(inputStream, length, &line); - if(status == 0) - { - m_nextState = MAILBOX_ERROR_DONE; - ClearFlag(MAILBOX_PAUSE_FOR_READ); - m_runningUrl->SetErrorMessage("error message not implemented yet"); - return status; - } - - if (status > length) - length = 0; - else - length -= status; - - if(!line) - return(status); /* no line yet or error */ + line = m_lineStreamBuffer->ReadNextLine(inputStream, pauseForMoreData); if (!line || (line[0] == '.' && line[1] == 0)) { - m_nextState = MAILBOX_DONE; - // and close the article file if it was open.... - if (m_tempMessageFile) - PR_Close(m_tempMessageFile); - - // mscott: hack alert...now that the file is done...turn around and fire a file url - // to display the message.... - if (m_displayConsumer) - { - nsFilePath filePath(MESSAGE_PATH); - nsFileURL fileURL(filePath); - char * message_path_url = PL_strdup(fileURL.GetAsString()); - - m_displayConsumer->LoadURL(nsAutoString(message_path_url), nsnull, PR_TRUE, nsURLReload, 0); - - PR_FREEIF(message_path_url); - } - + // we reached the end of the message! ClearFlag(MAILBOX_PAUSE_FOR_READ); } // otherwise process the line else { if (line[0] == '.') - PL_strcpy (outputBuffer, line + 1); - else - PL_strcpy (outputBuffer, line); + line++; // skip over the '.' /* When we're sending this line to a converter (ie, it's a message/rfc822) use the local line termination @@ -552,16 +471,16 @@ PRInt32 nsMailboxProtocol::ReadMessageResponse(nsIInputStream * inputStream, PRU the local system will convert that to the local line terminator as it is read. */ - - PL_strcat (outputBuffer, LINEBREAK); if (m_tempMessageFile) - PR_Write(m_tempMessageFile,(void *) outputBuffer,PL_strlen(outputBuffer)); + { + if (line) + PR_Write(m_tempMessageFile,(void *) line,PL_strlen(line)); + PR_Write(m_tempMessageFile, (void *) LINEBREAK, PL_strlen(CRLF)); + } } - - } - while (length > 0 && status > 0); + while (line && !pauseForMoreData); } SetFlag(MAILBOX_PAUSE_FOR_READ); // wait for more data to become available... diff --git a/mailnews/local/src/nsMailboxProtocol.h b/mailnews/local/src/nsMailboxProtocol.h index 4b17feb4af0..1912c725917 100644 --- a/mailnews/local/src/nsMailboxProtocol.h +++ b/mailnews/local/src/nsMailboxProtocol.h @@ -69,6 +69,8 @@ typedef enum _MailboxStatesEnum { MAILBOX_FINISH_COPY_MESSAGES } MailboxStatesEnum; +class nsMsgLineStreamBuffer; + class nsMailboxProtocol : public nsIStreamListener { public: @@ -124,8 +126,6 @@ private: PRUint32 m_flags; // used to store flag information nsIMailboxUrl *m_runningUrl; // the nsIMailboxURL that is currently running nsMailboxAction m_mailboxAction; // current mailbox action associated with this connnection... - char *m_dataBuf; - PRUint32 m_dataBufSize; PRInt32 m_originalContentLength; /* the content length at the time of calling graph progress */ // Event sink handles @@ -138,6 +138,7 @@ private: nsITransport * m_transport; nsIOutputStream * m_outputStream; // this will be obtained from the transport interface nsIStreamListener * m_outputConsumer; // this will be obtained from the transport interface + nsMsgLineStreamBuffer * m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream // Generic state information -- What state are we in? What state do we want to go to // after the next response? What was the last response code? etc. @@ -161,8 +162,6 @@ private: // Communication methods --> Reading and writing protocol //////////////////////////////////////////////////////////////////////////////////////// - PRInt32 ReadLine(nsIInputStream * inputStream, PRUint32 length, char ** line); - // SendData not only writes the NULL terminated data in dataBuffer to our output stream // but it also informs the consumer that the data has been written to the stream. PRInt32 SendData(const char * dataBuffer);