diff --git a/mozilla/mail/locales/en-US/chrome/messenger/news.properties b/mozilla/mail/locales/en-US/chrome/messenger/news.properties index 07f7b6dfdce..6a26aae05cb 100644 --- a/mozilla/mail/locales/en-US/chrome/messenger/news.properties +++ b/mozilla/mail/locales/en-US/chrome/messenger/news.properties @@ -52,9 +52,7 @@ enterPasswordTitle=News Server Password Required okButtonText=Download noNewMessages=There are no new messages on the server. -# The difference between these two is that the second one is shown when processing XHDR commands downloadingHeaders=Downloading %S of %S headers -downloadingFilterHeaders=Getting filter headers: %S (%S/%S) downloadingArticles=Downloading articles %S-%S bytesReceived=Downloading newsgroups: %S received (%SKB read at %SKB/sec) checkingForNewNews=Checking newsgroup %S of %S on %S for new messages diff --git a/mozilla/mailnews/base/search/src/nsMsgSearchAdapter.cpp b/mozilla/mailnews/base/search/src/nsMsgSearchAdapter.cpp index 1f82df91cb8..5d084991116 100644 --- a/mozilla/mailnews/base/search/src/nsMsgSearchAdapter.cpp +++ b/mozilla/mailnews/base/search/src/nsMsgSearchAdapter.cpp @@ -1015,15 +1015,11 @@ NS_IMETHODIMP nsMsgSearchValidityManager::GetTable (int whichTable, nsIMsgSearch case nsMsgSearchScope::news: if (!m_newsTable) rv = InitNewsTable(); - if (m_newsTable) - rv = SetOtherHeadersInTable(m_newsTable, customHeaders.get()); *ppOutTable = m_newsTable; break; case nsMsgSearchScope::newsFilter: if (!m_newsFilterTable) rv = InitNewsFilterTable(); - if (m_newsFilterTable) - rv = SetOtherHeadersInTable(m_newsFilterTable, customHeaders.get()); *ppOutTable = m_newsFilterTable; break; case nsMsgSearchScope::localNews: diff --git a/mozilla/mailnews/base/search/src/nsMsgSearchNews.cpp b/mozilla/mailnews/base/search/src/nsMsgSearchNews.cpp index 65cf6838878..b2433a4a688 100644 --- a/mozilla/mailnews/base/search/src/nsMsgSearchNews.cpp +++ b/mozilla/mailnews/base/search/src/nsMsgSearchNews.cpp @@ -144,14 +144,8 @@ char *nsMsgSearchNews::EncodeTerm (nsIMsgSearchTerm *term) attribEncoding = m_kNntpSubject; break; default: - nsCString header; - term->GetArbitraryHeader(header); - if (header.IsEmpty()) - { - NS_ASSERTION(PR_FALSE,"malformed search"); // malformed search term? - return nsnull; - } - attribEncoding = header.get(); + NS_ASSERTION(PR_FALSE,"malformed search"); // malformed search term? + return nsnull; } // Build a string to represent the string pattern @@ -466,23 +460,6 @@ nsresult nsMsgSearchValidityManager::InitNewsTable() m_newsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1); m_newsTable->SetAvailable (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1); m_newsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1); - -#if 0 - // Size should be handled after the fact... - m_newsTable->SetAvailable (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1); - m_newsTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1); - m_newsTable->SetAvailable (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1); - m_newsTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1); -#endif - - m_newsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); - m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); - m_newsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); - m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); - m_newsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); - m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); - m_newsTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); - m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); } return rv; @@ -534,20 +511,6 @@ nsresult nsMsgSearchValidityManager::InitNewsFilterTable() m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1); m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1); m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1); - - m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1); - m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1); - m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1); - m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1); - - m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); - m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1); - m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); - m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1); - m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); - m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1); - m_newsFilterTable->SetAvailable (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); - m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1); } return rv; diff --git a/mozilla/mailnews/news/public/nsINNTPNewsgroupList.idl b/mozilla/mailnews/news/public/nsINNTPNewsgroupList.idl index bbaf381b3b5..b58a4be1ff5 100644 --- a/mozilla/mailnews/news/public/nsINNTPNewsgroupList.idl +++ b/mozilla/mailnews/news/public/nsINNTPNewsgroupList.idl @@ -73,19 +73,11 @@ interface nsINNTPNewsgroupList : nsISupports { /* the XOVER Sink should maintain the ListNewsGroupState */ void initXOVER(in long first_message, in long last_message); void processXOVERLINE(in string line, out unsigned long status); + void processNonXOVER(in string line); void resetXOVER(); void finishXOVERLINE(in long status, out long newstatus); void clearXOVERState(); - ACString initXHDR(); - void processXHDRLine(in ACString line); - - void initHEAD(in long message); - void processHEADLine(in ACString line); - - // Calls the entire header process - void callFilters(); - attribute boolean getOldMessages; }; diff --git a/mozilla/mailnews/news/src/nsNNTPNewsgroupList.cpp b/mozilla/mailnews/news/src/nsNNTPNewsgroupList.cpp index bd69a0dcb9f..e09772195b3 100644 --- a/mozilla/mailnews/news/src/nsNNTPNewsgroupList.cpp +++ b/mozilla/mailnews/news/src/nsNNTPNewsgroupList.cpp @@ -127,35 +127,6 @@ nsNNTPNewsgroupList::Initialize(nsINntpUrl *runningURL, nsIMsgNewsFolder *newsFo m_runningURL = runningURL; m_knownArts.set = nsMsgKeySet::Create(); - nsresult rv; - - nsCOMPtr folder = do_QueryInterface(m_newsFolder, &rv); - NS_ENSURE_SUCCESS(rv,rv); - - rv = folder->GetFilterList(m_msgWindow, getter_AddRefs(m_filterList)); - NS_ENSURE_SUCCESS(rv,rv); - nsCString ngHeaders; - m_filterList->GetArbitraryHeaders(ngHeaders); - m_filterHeaders.ParseString(ngHeaders.get(), " "); - - nsCOMPtr server; - rv = folder->GetServer(getter_AddRefs(server)); - NS_ENSURE_SUCCESS(rv,rv); - - rv = server->GetFilterList(m_msgWindow, getter_AddRefs(m_serverFilterList)); - NS_ENSURE_SUCCESS(rv,rv); - nsCAutoString servHeaders; - m_serverFilterList->GetArbitraryHeaders(servHeaders); - - nsCStringArray servArray; - servArray.ParseString(servHeaders.get(), " "); - - // servArray may have duplicates already in m_filterHeaders. - for (PRInt32 i = 0; i < servArray.Count(); i++) - { - if (m_filterHeaders.IndexOf(*(servArray[i])) == -1) - m_filterHeaders.AppendCString(*(servArray[i])); - } return NS_OK; } @@ -180,8 +151,9 @@ nsNNTPNewsgroupList::CleanUp() if (lastMissingCheck) firstKnown = lastMissingCheck + 1; } + PRBool done = firstKnown > lastKnown; // just in case... PRBool foundMissingArticle = PR_FALSE; - while (firstKnown <= lastKnown) + while (!done) { PRInt32 firstUnreadStart, firstUnreadEnd; m_set->FirstMissingRange(firstKnown, lastKnown, &firstUnreadStart, &firstUnreadEnd); @@ -520,13 +492,12 @@ nsNNTPNewsgroupList::InitXOVER(PRInt32 first_msg, PRInt32 last_msg) m_firstMsgNumber = first_msg; m_lastMsgNumber = last_msg; m_lastProcessedNumber = first_msg > 1 ? first_msg - 1 : 1; - m_currentXHDRIndex = -1; return status; } // from RFC 822, don't translate #define FROM_HEADER "From: " -#define SUBJECT_HEADER "Subject: " +#define SUBECT_HEADER "Subject: " #define DATE_HEADER "Date: " nsresult @@ -641,7 +612,136 @@ nsNNTPNewsgroupList::ParseLine(char *line, PRUint32 * message_number) GET_TOKEN (); /* xref */ - return m_newsDB->AddNewHdrToDB(newMsgHdr, PR_TRUE); + // apply filters + // XXX TODO + // do spam classification for news + + nsCOMPtr folder = do_QueryInterface(m_newsFolder, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + if (!m_filterList) + { + rv = folder->GetFilterList(m_msgWindow, getter_AddRefs(m_filterList)); + NS_ENSURE_SUCCESS(rv,rv); + } + + if (!m_serverFilterList) + { + nsCOMPtr server; + rv = folder->GetServer(getter_AddRefs(server)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = server->GetFilterList(m_msgWindow, getter_AddRefs(m_serverFilterList)); + NS_ENSURE_SUCCESS(rv,rv); + } + + // flag for kill + // if the action is Delete, and we get a hit (see ApplyFilterHit()) + // we set this to PR_FALSE. if false, we won't add it to the db. + m_addHdrToDB = PR_TRUE; + + PRUint32 filterCount = 0; + if (m_filterList) { + rv = m_filterList->GetFilterCount(&filterCount); + NS_ENSURE_SUCCESS(rv,rv); + } + + PRUint32 serverFilterCount = 0; + if (m_serverFilterList) { + rv = m_serverFilterList->GetFilterCount(&serverFilterCount); + NS_ENSURE_SUCCESS(rv,rv); + } + + // only do this if we have filters + if (filterCount || serverFilterCount) + { + // build up a "headers" for filter code + nsCString subject; + rv = newMsgHdr->GetSubject(getter_Copies(subject)); + NS_ENSURE_SUCCESS(rv,rv); + + PRUint32 headersSize = 0; + + // +1 to separate headers with a null byte + if (authorStr) + headersSize += strlen(FROM_HEADER) + strlen(authorStr) + 1; + + if (!(subject.IsEmpty())) + headersSize += strlen(SUBECT_HEADER) + subject.Length() + 1; + + if (dateStr) + headersSize += strlen(DATE_HEADER) + strlen(dateStr) + 1; + + if (headersSize) { + char *headers = (char *)PR_Malloc(headersSize); + char *headerPos = headers; + if (!headers) + return NS_ERROR_OUT_OF_MEMORY; + + if (authorStr) { + PL_strcpy(headerPos, FROM_HEADER); + headerPos += strlen(FROM_HEADER); + + PL_strcpy(headerPos, authorStr); + headerPos += strlen(authorStr); + + *headerPos = '\0'; + headerPos++; + } + + if (!(subject.IsEmpty())) { + PL_strcpy(headerPos, SUBECT_HEADER); + headerPos += strlen(SUBECT_HEADER); + + PL_strcpy(headerPos, subject.get()); + headerPos += subject.Length(); + + *headerPos = '\0'; + headerPos++; + } + + if (dateStr) { + PL_strcpy(headerPos, DATE_HEADER); + headerPos += strlen(DATE_HEADER); + + PL_strcpy(headerPos, dateStr); + headerPos += strlen(dateStr); + + *headerPos = '\0'; + headerPos++; + } + + // on a filter hit (see ApplyFilterHit()), we'll be modifying the header + // so keep track of the header + m_newMsgHdr = newMsgHdr; + + // the per-newsgroup filters should probably go first. It doesn't matter + // right now since nothing stops filter execution for newsgroups, but if something + // does, like adding a "stop execution" action, then users should be able to + // override the global filters in the per-newsgroup filters. + if (filterCount) + { + rv = m_filterList->ApplyFiltersToHdr(nsMsgFilterType::NewsRule, newMsgHdr, folder, m_newsDB, + headers, headersSize, this, m_msgWindow, nsnull); + } + if (serverFilterCount) + { + rv = m_serverFilterList->ApplyFiltersToHdr(nsMsgFilterType::NewsRule, newMsgHdr, folder, m_newsDB, + headers, headersSize, this, m_msgWindow, nsnull); + } + + PR_Free ((void*) headers); + NS_ENSURE_SUCCESS(rv,rv); + } + } + + // if we deleted it, don't add it + if (m_addHdrToDB) { + rv = m_newsDB->AddNewHdrToDB(newMsgHdr, PR_TRUE); + NS_ENSURE_SUCCESS(rv,rv); + } + + return NS_OK; } NS_IMETHODIMP nsNNTPNewsgroupList::ApplyFilterHit(nsIMsgFilter *aFilter, nsIMsgWindow *aMsgWindow, PRBool *aApplyMore) @@ -829,13 +929,48 @@ nsNNTPNewsgroupList::ProcessXOVERLINE(const char *line, PRUint32 *status) PRInt32 numDownloaded = lastIndex; PRInt32 totIndex = m_lastMsgNumber - m_firstMsgNumber + 1; + PRInt32 percent = (totIndex) ? (PRInt32)(100.0 * (double)numDownloaded / (double)totalToDownload) : 0; + PRTime elapsedTime; LL_SUB(elapsedTime, PR_Now(), m_lastStatusUpdate); if (LL_CMP(elapsedTime, >, MIN_STATUS_UPDATE_INTERVAL) || lastIndex == totIndex) - UpdateStatus(PR_FALSE, numDownloaded, totalToDownload); + { + nsAutoString numDownloadedStr; + numDownloadedStr.AppendInt(numDownloaded); + + nsAutoString totalToDownloadStr; + totalToDownloadStr.AppendInt(totalToDownload); + + nsString statusString; + nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr bundle; + rv = bundleService->CreateBundle(NEWS_MSGS_URL, getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv, rv); + + const PRUnichar *formatStrings[2] = { numDownloadedStr.get(), totalToDownloadStr.get() }; + rv = bundle->FormatStringFromName(NS_LITERAL_STRING("downloadingHeaders").get(), formatStrings, 2, getter_Copies(statusString)); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef DEBUG_NEWS + PRInt32 elapsed; + LL_L2I(elapsed, elapsedTime); + printf("usecs elapsed since last update: %d\n", elapsed); +#endif + + SetProgressStatus(statusString.get()); + m_lastStatusUpdate = PR_Now(); + + // only update the progress meter if it has changed + if (percent != m_lastPercent) { + SetProgressBarPercent(percent); + m_lastPercent = percent; + } + } } return NS_OK; } @@ -848,6 +983,22 @@ nsNNTPNewsgroupList::ResetXOVER() return 0; } +/* When we don't have XOVER, but use HEAD, this is called instead. + It reads lines until it has a whole header block, then parses the + headers; then takes selected headers and creates an XOVER line + from them. This is more for simplicity and code sharing than + anything else; it means we end up parsing some things twice. + But if we don't have XOVER, things are going to be so horribly + slow anyway that this just doesn't matter. + */ + +nsresult +nsNNTPNewsgroupList::ProcessNonXOVER (const char * /*line*/) +{ + // ### dmb write me + return NS_ERROR_NOT_IMPLEMENTED; +} + nsresult nsNNTPNewsgroupList::FinishXOVERLINE(int status, int *newstatus) { @@ -923,282 +1074,6 @@ nsNNTPNewsgroupList::ClearXOVERState() return NS_OK; } -NS_IMETHODIMP -nsNNTPNewsgroupList::InitXHDR(nsACString &header) -{ - ++m_currentXHDRIndex; - if (m_currentXHDRIndex >= m_filterHeaders.Count()) - header.Truncate(); - else - header.Assign(*m_filterHeaders[m_currentXHDRIndex]); - return NS_OK; -} - -NS_IMETHODIMP -nsNNTPNewsgroupList::ProcessXHDRLine(const nsACString &line) -{ - PRInt32 middle = line.FindChar(' '); - nsCString value, key = PromiseFlatCString(line); - if (middle == kNotFound) - return NS_OK; - value = Substring(line, middle+1); - key.Truncate((PRUint32)middle); - - // According to RFC 2980, some will send (none) instead. - // So we don't treat this is an error. - if (key.CharAt(0) < '0' || key.CharAt(0) > '9') - return NS_OK; - - PRInt32 code; - PRInt32 number = key.ToInteger(&code); - if (code != NS_OK) - return NS_ERROR_FAILURE; - // RFC 2980 specifies one or more spaces. - value.Trim(" "); - - nsCOMPtr header; - nsresult rv = m_newsDB->GetMsgHdrForKey(number, getter_AddRefs(header)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = header->SetStringProperty(m_filterHeaders[m_currentXHDRIndex]->get(), value.get()); - NS_ENSURE_SUCCESS(rv, rv); - - PRInt32 totalToDownload = m_lastMsgToDownload - m_firstMsgToDownload + 1; - PRInt32 numDownloaded = number - m_firstMsgNumber + 1; - - PRTime elapsedTime; - - LL_SUB(elapsedTime, PR_Now(), m_lastStatusUpdate); - - if (elapsedTime > MIN_STATUS_UPDATE_INTERVAL) - UpdateStatus(PR_TRUE, numDownloaded, totalToDownload); - return rv; -} - -NS_IMETHODIMP -nsNNTPNewsgroupList::InitHEAD(PRInt32 number) -{ - nsresult rv; - - if (m_newMsgHdr) - { - // Finish processing for this header - // If HEAD didn't properly return, then the header won't be set - if (m_addHdrToDB) - { - rv = m_newsDB->AddNewHdrToDB(m_newMsgHdr, PR_TRUE); - NS_ENSURE_SUCCESS(rv,rv); - } - - PRInt32 totalToDownload = m_lastMsgToDownload - m_firstMsgToDownload + 1; - PRInt32 lastIndex = m_lastProcessedNumber - m_firstMsgNumber + 1; - PRInt32 numDownloaded = lastIndex; - PRInt32 totIndex = m_lastMsgNumber - m_firstMsgNumber + 1; - - PRTime elapsedTime; - - LL_SUB(elapsedTime, PR_Now(), m_lastStatusUpdate); - - if (LL_CMP(elapsedTime, >, MIN_STATUS_UPDATE_INTERVAL) || - lastIndex == totIndex) - UpdateStatus(PR_FALSE, numDownloaded, totalToDownload); - } - - if (number >= 0) - { - rv = m_newsDB->CreateNewHdr(number, getter_AddRefs(m_newMsgHdr)); - m_addHdrToDB = PR_FALSE; - m_lastProcessedNumber = number; - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; -} - -NS_IMETHODIMP -nsNNTPNewsgroupList::ProcessHEADLine(const nsACString &line) -{ - PRInt32 colon = line.FindChar(':'); - nsCString header = PromiseFlatCString(line), value; - if (colon != kNotFound) - { - value = Substring(line, colon+1); - header.Truncate((PRUint32)colon); - } - else if (line.CharAt(0) == ' ' || line.CharAt(0) == '\t') // We are continuing the header - { - m_thisLine += header; // Preserve whitespace (should we?) - return NS_OK; - } - else - return NS_OK; // We are malformed. Just ignore and hope for the best... - - nsresult rv; - if (!m_lastHeader.IsEmpty()) - { - rv = AddHeader(m_lastHeader.get(), m_thisLine.get()); - NS_ENSURE_SUCCESS(rv,rv); - } - - value.Trim(" "); - - ToLowerCase(header, m_lastHeader); - m_thisLine.Assign(value); - return NS_OK; -} - -nsresult -nsNNTPNewsgroupList::AddHeader(const char *header, const char *value) -{ - nsresult rv = NS_OK; - // The From, Date, and Subject headers have special requirements. - if (PL_strcmp(header, "from") == 0) - rv = m_newMsgHdr->SetAuthor(value); - else if (PL_strcmp(header, "date") == 0) - { - PRTime date; - PRStatus status = PR_ParseTimeString (value, PR_FALSE, &date); - if (PR_SUCCESS == status) - rv = m_newMsgHdr->SetDate(date); - } - else if (PL_strcmp(header, "subject") == 0) - { - const char *subject = value; - PRUint32 subjectLen = strlen(value); - - PRUint32 flags = 0; - // ### should call IsHeaderRead here... - /* strip "Re: " */ - nsCString modifiedSubject; - if (NS_MsgStripRE(&subject, &subjectLen, getter_Copies(modifiedSubject))) - // this will make sure read flags agree with newsrc - (void) m_newMsgHdr->OrFlags(MSG_FLAG_HAS_RE, &flags); - - if (! (flags & MSG_FLAG_READ)) - rv = m_newMsgHdr->OrFlags(MSG_FLAG_NEW, &flags); - - rv = m_newMsgHdr->SetSubject(modifiedSubject.IsEmpty() ? subject : - modifiedSubject.get()); - } - else if (PL_strcmp(header, "message-id") == 0) - { - char * strippedId = PL_strdup(value); - char * freeable = strippedId; - if (strippedId[0] == '<') - strippedId++; - char * lastChar = strippedId + PL_strlen(strippedId) - 1; - - if (*lastChar == '>') - *lastChar = '\0'; - - rv = m_newMsgHdr->SetMessageId(strippedId); - PL_strfree(freeable); - } - else if (PL_strcmp(header, "references") == 0) - rv = m_newMsgHdr->SetReferences(value); - else if (PL_strcmp(header, "bytes") == 0) - rv = m_newMsgHdr->SetMessageSize(atol(value)); - else if (PL_strcmp(header, "lines") == 0) - rv = m_newMsgHdr->SetLineCount(atol(value)); - else if (m_filterHeaders.IndexOf(nsDependentCString(header)) != -1) - rv = m_newMsgHdr->SetStringProperty(header, value); - return rv; -} - -nsresult -nsNNTPNewsgroupList::CallFilters() -{ - nsresult rv; - nsCString filterString; - - nsCOMPtr folder = do_QueryInterface(m_newsFolder, &rv); - NS_ENSURE_SUCCESS(rv,rv); - - PRUint32 filterCount = 0; - if (m_filterList) - { - rv = m_filterList->GetFilterCount(&filterCount); - NS_ENSURE_SUCCESS(rv,rv); - } - - PRUint32 serverFilterCount = 0; - if (m_serverFilterList) - { - rv = m_serverFilterList->GetFilterCount(&serverFilterCount); - NS_ENSURE_SUCCESS(rv,rv); - } - - if (filterCount == 0 && serverFilterCount == 0) - return NS_OK; - - PRUint32 count = 0; - PRUint32 *keys; - rv = m_newsDB->GetNewList(&count, &keys); - NS_ENSURE_SUCCESS(rv,rv); - - for (PRUint32 i = 0; iGetMsgHdrForKey(*keys++, getter_AddRefs(m_newMsgHdr)); - NS_ENSURE_SUCCESS(rv, rv); - - // build up a "headers" for filter code - nsCString subject, author, date; - rv = m_newMsgHdr->GetSubject(getter_Copies(subject)); - NS_ENSURE_SUCCESS(rv,rv); - rv = m_newMsgHdr->GetAuthor(getter_Copies(author)); - NS_ENSURE_SUCCESS(rv,rv); - - nsCString fullHeaders; - if (!(author.IsEmpty())) - { - fullHeaders.AppendLiteral(FROM_HEADER); - fullHeaders += author; - fullHeaders += '\0'; - } - - if (!(subject.IsEmpty())) - { - fullHeaders.AppendLiteral(SUBJECT_HEADER); - fullHeaders += subject; - fullHeaders += '\0'; - } - - for (PRInt32 header = 0; header < m_filterHeaders.Count(); header++) - { - char *retValue; - m_newMsgHdr->GetStringProperty(m_filterHeaders[header]->get(), &retValue); - if (*retValue) - { - fullHeaders += *(m_filterHeaders[header]); - fullHeaders.AppendLiteral(": "); - fullHeaders += nsCString(retValue); - fullHeaders += '\0'; - } - } - - // the per-newsgroup filters should probably go first. It doesn't matter - // right now since nothing stops filter execution for newsgroups, but if something - // does, like adding a "stop execution" action, then users should be able to - // override the global filters in the per-newsgroup filters. - if (filterCount) - { - rv = m_filterList->ApplyFiltersToHdr(nsMsgFilterType::NewsRule, m_newMsgHdr, folder, m_newsDB, - fullHeaders.get(), fullHeaders.Length(), this, m_msgWindow, nsnull); - } - if (serverFilterCount) - { - rv = m_serverFilterList->ApplyFiltersToHdr(nsMsgFilterType::NewsRule, m_newMsgHdr, folder, m_newsDB, - fullHeaders.get(), fullHeaders.Length(), this, m_msgWindow, nsnull); - } - - NS_ENSURE_SUCCESS(rv,rv); - - if (!m_addHdrToDB) - m_newsDB->DeleteHeader(m_newMsgHdr, nsnull, PR_FALSE, PR_FALSE); - } - return NS_OK; -} - void nsNNTPNewsgroupList::SetProgressBarPercent(PRInt32 percent) { @@ -1233,59 +1108,6 @@ nsNNTPNewsgroupList::SetProgressStatus(const PRUnichar *message) } } -void -nsNNTPNewsgroupList::UpdateStatus(PRBool filtering, PRInt32 numDLed, PRInt32 totToDL) -{ - double ratio = filtering ? (m_currentXHDRIndex+1.0)/(m_filterHeaders.Count()+1) - : 1.0/(m_filterHeaders.Count()+1); - PRInt32 percent = (PRInt32)(ratio * numDLed / totToDL); - - nsAutoString numDownloadedStr; - numDownloadedStr.AppendInt(numDLed); - - nsAutoString totalToDownloadStr; - totalToDownloadStr.AppendInt(totToDL); - - nsresult rv; - nsString statusString; - nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); - if (!NS_SUCCEEDED(rv)) - return; - - nsCOMPtr bundle; - rv = bundleService->CreateBundle(NEWS_MSGS_URL, getter_AddRefs(bundle)); - if (!NS_SUCCEEDED(rv)) - return; - - if (filtering) - { - NS_ConvertUTF8toUTF16 header(*m_filterHeaders[m_currentXHDRIndex]); - const PRUnichar *formatStrings[3] = { header.get(), - numDownloadedStr.get(), totalToDownloadStr.get() }; - rv = bundle->FormatStringFromName(NS_LITERAL_STRING("downloadingFilterHeaders").get(), - formatStrings, 3, getter_Copies(statusString)); - } - else - { - const PRUnichar *formatStrings[2] = { numDownloadedStr.get(), - totalToDownloadStr.get() }; - rv = bundle->FormatStringFromName(NS_LITERAL_STRING("downloadingHeaders").get(), - formatStrings, 2, getter_Copies(statusString)); - } - if (!NS_SUCCEEDED(rv)) - return; - - SetProgressStatus(statusString.get()); - m_lastStatusUpdate = PR_Now(); - - // only update the progress meter if it has changed - if (percent != m_lastPercent) - { - SetProgressBarPercent(percent); - m_lastPercent = percent; - } -} - NS_IMETHODIMP nsNNTPNewsgroupList::SetGetOldMessages(PRBool aGetOldMessages) { m_getOldMessages = aGetOldMessages; diff --git a/mozilla/mailnews/news/src/nsNNTPNewsgroupList.h b/mozilla/mailnews/news/src/nsNNTPNewsgroupList.h index f6ea4aca364..40ae879b82d 100644 --- a/mozilla/mailnews/news/src/nsNNTPNewsgroupList.h +++ b/mozilla/mailnews/news/src/nsNNTPNewsgroupList.h @@ -103,9 +103,6 @@ private: void SetProgressBarPercent(PRInt32 percent); void SetProgressStatus(const PRUnichar *message); - void UpdateStatus(PRBool filtering, PRInt32 numDled, PRInt32 totToDL); - - nsresult AddHeader(const char * header, const char * value); protected: PRBool m_getOldMessages; PRBool m_promptedAlready; @@ -127,19 +124,12 @@ protected: struct MSG_NewsKnown m_knownArts; nsMsgKeySet *m_set; - nsCStringArray m_filterHeaders; - PRInt32 m_currentXHDRIndex; - nsCString m_lastHeader; - nsCString m_thisLine; - private: nsCOMPtr m_msgWindow; nsCOMPtr m_filterList; nsCOMPtr m_serverFilterList; nsCOMPtr m_newMsgHdr; /* current message header we're building */ - PRBool m_addHdrToDB; - }; #endif /* nsNNTPNewsgroupListState_h___ */ diff --git a/mozilla/mailnews/news/src/nsNNTPProtocol.cpp b/mozilla/mailnews/news/src/nsNNTPProtocol.cpp index 485ba1824b7..08b25657f00 100644 --- a/mozilla/mailnews/news/src/nsNNTPProtocol.cpp +++ b/mozilla/mailnews/news/src/nsNNTPProtocol.cpp @@ -97,8 +97,6 @@ #include "nsIMsgNewsFolder.h" #include "nsIDocShell.h" -#include "nsIMsgFilterList.h" - // for the memory cache... #include "nsICacheEntryDescriptor.h" #include "nsICacheSession.h" @@ -204,9 +202,6 @@ const char *const stateLabels[] = { "NNTP_XOVER_RESPONSE", "NNTP_XOVER", "NEWS_PROCESS_XOVER", -"NNTP_XHDR_SEND", -"NNTP_XHDR_RESPONSE", -"NNTP_XHDR", "NNTP_READ_GROUP", "NNTP_READ_GROUP_RESPONSE", "NNTP_READ_GROUP_BODY", @@ -3295,11 +3290,8 @@ void nsNNTPProtocol::HandleAuthenticationFailure() } } -/////////////////////////////////////////////////////////////////////////////// -// XOVER, XHDR, and HEAD processing code -// Used for filters -// State machine explanation located in doxygen comments for nsNNTPProtocol -/////////////////////////////////////////////////////////////////////////////// +/* start the xover command + */ PRInt32 nsNNTPProtocol::BeginReadXover() { @@ -3383,7 +3375,8 @@ PRInt32 nsNNTPProtocol::FigureNextChunk() rv = m_newsgroupList->GetRangeOfArtsToDownload(m_msgWindow, m_firstPossibleArticle, m_lastPossibleArticle, - m_numArticlesWanted - m_numArticlesLoaded, + m_numArticlesWanted - + m_numArticlesLoaded, &(m_firstArticle), &(m_lastArticle), &status); @@ -3504,7 +3497,7 @@ PRInt32 nsNNTPProtocol::ReadXover(nsIInputStream * inputStream, PRUint32 length) if(line[0] == '.' && line[1] == '\0') { - m_nextState = NNTP_XHDR_SEND; + m_nextState = NNTP_FIGURE_NEXT_CHUNK; ClearFlag(NNTP_PAUSE_FOR_READ); PR_Free(lineToFree); return(0); @@ -3526,7 +3519,7 @@ PRInt32 nsNNTPProtocol::ReadXover(nsIInputStream * inputStream, PRUint32 length) m_numArticlesLoaded++; PR_Free(lineToFree); - return NS_SUCCEEDED(rv) ? (PRInt32)status : -1; /* keep going if no error */ + return NS_SUCCEEDED(rv) ? status : -1; /* keep going if no error */ } /* Finished processing all the XOVER data. @@ -3541,7 +3534,6 @@ PRInt32 nsNNTPProtocol::ProcessXover() if (!m_newsgroupList) return -1; PRInt32 status = 0; - m_newsgroupList->CallFilters(); rv = m_newsgroupList->FinishXOVERLINE(0,&status); m_newsgroupList = nsnull; if (NS_SUCCEEDED(rv) && status < 0) return status; @@ -3551,113 +3543,17 @@ PRInt32 nsNNTPProtocol::ProcessXover() return(MK_DATA_LOADED); } -PRInt32 nsNNTPProtocol::XhdrSend() -{ - nsCString header; - m_newsgroupList->InitXHDR(header); - if (header.IsEmpty()) - { - m_nextState = NNTP_FIGURE_NEXT_CHUNK; - return 0; - } - char outputBuffer[OUTPUT_BUFFER_SIZE]; - PRInt32 status = 0; - - PR_snprintf(outputBuffer, OUTPUT_BUFFER_SIZE, - "XHDR %s %d-%d" CRLF, - header.get(), m_firstArticle, m_lastArticle); - NNTP_LOG_WRITE(outputBuffer); - - m_nextState = NNTP_RESPONSE; - m_nextStateAfterResponse = NNTP_XHDR_RESPONSE; - SetFlag(NNTP_PAUSE_FOR_READ); - - nsCOMPtr mailnewsurl = do_QueryInterface(m_runningURL); - if (mailnewsurl) - status = SendData(mailnewsurl, outputBuffer); - - return status; -} - -PRInt32 nsNNTPProtocol::ReadXhdrResponse() -{ -#ifdef TEST_NO_XOVER_SUPPORT - m_responseCode = MK_NNTP_RESPONSE_CHECK_ERROR; /* pretend XHDR generated an error */ -#endif - - if(m_responseCode != MK_NNTP_RESPONSE_XHDR_OK) - { - m_nextState = NNTP_READ_GROUP; - // The reasoning behind setting this flag and not an XHDR flag is that we - // are going to have to use HEAD instead. At that point, using XOVER as - // well is just wasting bandwidth. - SetFlag(NNTP_NO_XOVER_SUPPORT); - } - else - { - m_nextState = NNTP_XHDR; - } - - return(0); /* continue */ -} - -PRInt32 nsNNTPProtocol::ReadXhdr(nsIInputStream * inputStream, PRUint32 length) -{ - char *line, *lineToFree; - nsresult rv; - PRUint32 status = 1; - - PRBool pauseForMoreData = PR_FALSE; - line = lineToFree = m_lineStreamBuffer->ReadNextLine(inputStream, status, pauseForMoreData); - - if(pauseForMoreData) - { - SetFlag(NNTP_PAUSE_FOR_READ); - return 0; - } - - if(!line) - return(status); /* no line yet or TCP error */ - - if(line[0] == '.' && line[1] == '\0') - { - m_nextState = NNTP_XHDR_SEND; - ClearFlag(NNTP_PAUSE_FOR_READ); - PR_Free(lineToFree); - return(0); - } - else if (line [0] == '.' && line [1] == '.') - /* The NNTP server quotes all lines beginning with "." by doubling it. */ - line++; - - if(status > 1) - { - mBytesReceived += status; - mBytesReceivedSinceLastStatusUpdate += status; - } - - rv = m_newsgroupList->ProcessXHDRLine(nsCString(line)); - NS_ASSERTION(NS_SUCCEEDED(rv), "failed to process the XHDRLINE"); - - m_numArticlesLoaded++; - PR_Free(lineToFree); - return NS_SUCCEEDED(rv) ? (PRInt32)status : -1; /* keep going if no error */ -} - PRInt32 nsNNTPProtocol::ReadNewsgroup() { if(m_articleNumber > m_lastArticle) { /* end of groups */ - m_newsgroupList->InitHEAD(-1); m_nextState = NNTP_FIGURE_NEXT_CHUNK; ClearFlag(NNTP_PAUSE_FOR_READ); return(0); } else { - m_newsgroupList->InitHEAD(m_articleNumber); - char outputBuffer[OUTPUT_BUFFER_SIZE]; PR_snprintf(outputBuffer, OUTPUT_BUFFER_SIZE, @@ -3691,7 +3587,10 @@ PRInt32 nsNNTPProtocol::ReadNewsgroupResponse() m_key = nsMsgKey_None; - return 0; + /* Give the message number to the header parser. */ + rv = m_newsgroupList->ProcessNonXOVER(m_responseText); + /* convert nsresult->status */ + return NS_FAILED(rv); } else { @@ -3730,16 +3629,14 @@ PRInt32 nsNNTPProtocol::ReadNewsgroupBody(nsIInputStream * inputStream, PRUint32 { m_nextState = NNTP_READ_GROUP; ClearFlag(NNTP_PAUSE_FOR_READ); - return 0; } else if (line [0] == '.' && line [1] == '.') /* The NNTP server quotes all lines beginning with "." by doubling it. */ line++; - nsCString safe_line(line); - rv = m_newsgroupList->ProcessHEADLine(safe_line); - PR_Free(lineToFree); + rv = m_newsgroupList->ProcessNonXOVER(line); /* convert nsresult->status */ + PR_Free(lineToFree); return NS_FAILED(rv); } @@ -5135,18 +5032,6 @@ nsresult nsNNTPProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp status = ProcessXover(); break; - case NNTP_XHDR_SEND: - status = XhdrSend(); - break; - - case NNTP_XHDR_RESPONSE: - status = ReadXhdrResponse(); - break; - - case NNTP_XHDR: - status = ReadXhdr(inputStream, length); - break; - case NNTP_READ_GROUP: status = ReadNewsgroup(); break; @@ -5159,7 +5044,7 @@ nsresult nsNNTPProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp break; case NNTP_READ_GROUP_BODY: - status = ReadNewsgroupBody(inputStream, length); + status = ReadNewsgroupResponse(); break; case NNTP_SEND_POST_DATA: diff --git a/mozilla/mailnews/news/src/nsNNTPProtocol.h b/mozilla/mailnews/news/src/nsNNTPProtocol.h index 981a585ab5e..3a532da1ea5 100644 --- a/mozilla/mailnews/news/src/nsNNTPProtocol.h +++ b/mozilla/mailnews/news/src/nsNNTPProtocol.h @@ -118,9 +118,6 @@ NNTP_XOVER_SEND, NNTP_XOVER_RESPONSE, NNTP_XOVER, NEWS_PROCESS_XOVER, -NNTP_XHDR_SEND, -NNTP_XHDR_RESPONSE, -NNTP_XHDR, NNTP_READ_GROUP, NNTP_READ_GROUP_RESPONSE, NNTP_READ_GROUP_BODY, @@ -273,6 +270,7 @@ private: PRInt32 m_originalContentLength; /* the content length at the time of calling graph progress */ + nsCOMPtr m_stringBundle; nsCOMPtr m_nntpServer; @@ -350,6 +348,11 @@ private: PRInt32 BeginNewsgroups(); PRInt32 ProcessNewsgroups(nsIInputStream * inputStream, PRUint32 length); + PRInt32 ReadNewsgroup(); + PRInt32 ReadNewsgroupResponse(); + + PRInt32 ReadNewsgroupBody(nsIInputStream * inputStream, PRUint32 length); + // Protocol handlers used for posting data PRInt32 PostData(); PRInt32 PostDataResponse(); @@ -360,105 +363,19 @@ private: PRInt32 DisplayNewsRC(); PRInt32 DisplayNewsRCResponse(); - ///////////////////////////////////////////////////////////////////////////// - // XHDR, XOVER, HEAD filtering process handlers - // These are ordered by the rough order of usage - ///////////////////////////////////////////////////////////////////////////// - - /** - * The first step in the filtering process, the state NNTP_XOVER_BEGIN. - * This method sets up m_newsgroupList. - * Followed by: NNTP_FIGURE_NEXT_CHUNK - */ + // start off the xover command PRInt32 BeginReadXover(); - /** - * The loop control for filtering, the state NNTP_FIGURE_NEXT_CHUNK. - * This method contacts the newsgroupList to figure out which articles to - * download and then prepares it for XOVER support. - * Followed by: NEWS_PROCESS_XOVER if everything is finished - * NNTP_READ_GROUP if XOVER doesn't work - * NNTP_XOVER_SEND if XOVER does work - */ - PRInt32 FigureNextChunk(); - // The XOVER process core - /** - * The state NNTP_XOVER_SEND, which actually sends the message. - * Followed by: NNTP_XOVER_RESPONSE - */ - PRInt32 XoverSend(); - /** - * This state, NNTP_XOVER_RESPONSE, actually checks the XOVER capabiliity. - * Followed by: NNTP_XOVER if XOVER is supported - * NNTP_READ_GROUP if it isn't - */ - PRInt32 ReadXoverResponse(); - /** - * This state, NNTP_XOVER, processes the results from the XOVER command. - * It asks nsNNTPNewsgroupList to process the line using ProcessXOVERLINE. - * Followed by: NNTP_XHDR_SEND - */ + // process the xover list as it comes from the server and load it into the sort list. PRInt32 ReadXover(nsIInputStream * inputStream, PRUint32 length); + // See if the xover response is going to return us data. If the proper code isn't returned then + // assume xover isn't supported and use normal read_group. + PRInt32 ReadXoverResponse(); - // The XHDR process core - /** - * This state, NNTP_XHDR_SEND, sends the XHDR command. - * The headers are all managed by nsNNTPNewsgroupList, and this picks them up - * one by one as they are needed. - * Followed by: NNTP_XHDR_RESPONSE if there is a header to be sent - * NNTP_FIGURE_NEXT_CHUNK if all headers have been sent - */ - PRInt32 XhdrSend(); - /** - * This state, NNTP_XHDR_RESPONSE, evaluates the response. - * Note that if XHDR doesn't work properly, HEAD fallback is switched on and - * all subsequent chunks will NOT use XOVER. - * Followed by: NNTP_XHDR if XHDR works properly - * NNTP_READ_GROUP if it doesn't - */ - PRInt32 ReadXhdrResponse(); - /** - * This state, NNTP_XHDR, processes each line of the XHDR response. - * It mostly passes everything off to nsNNTPNewsgroupList and only checks for - * the end of the response and various other preprocessing. - * Followed by: NNTP_XHDR_SEND - */ - PRInt32 ReadXhdr(nsIInputStream * inputStream, PRUint32 length); - - // HEAD processing core - /** - * This state, NNTP_READ_GROUP, is the control for the HEAD processor. - * It sends the HEAD command and increments the article number until it is - * finished. WARNING: HEAD is REALLY SLOW. - * Followed by: NNTP_FIGURE_NEXT_CHUNK when it is finished - * NNTP_READ_GROUP_RESPONSE when it is not - */ - PRInt32 ReadNewsgroup(); - /** - * This state, NNTP_READ_GROUP_RESPONSE, checks if the article exists. - * Because it is required by NNTP, if it doesn't work, the only problem would - * be that the article doesn't exist. Passes off article number data to - * nsNNTPNewsgroupList. - * Followed by: NNTP_READ_GROUP_BODY if the article exists - * NNTP_READ_GROUP if it doesn't. - */ - PRInt32 ReadNewsgroupResponse(); - /** - * This state, NNTP_READ_GROUP_BODY, reads the body of the HEAD command. - * Once again, it passes information off to nsNNTPNewsgroupList. - * Followed by: NNTP_READ_GROUP - */ - PRInt32 ReadNewsgroupBody(nsIInputStream * inputStream, PRUint32 length); - - /** - * This state, NNTP_PROCESS_XOVER, is the final step of the filter-processing - * code. Currently, all it does is cleans up the unread count and calls the - * filters, both via nsNNTPNewsgroupList. - * Followed by: NEWS_DONE - */ + PRInt32 XoverSend(); PRInt32 ProcessXover(); - + PRInt32 FigureNextChunk(); // Canceling PRInt32 StartCancel(); diff --git a/mozilla/suite/locales/en-US/chrome/mailnews/news.properties b/mozilla/suite/locales/en-US/chrome/mailnews/news.properties index 07f7b6dfdce..6a26aae05cb 100644 --- a/mozilla/suite/locales/en-US/chrome/mailnews/news.properties +++ b/mozilla/suite/locales/en-US/chrome/mailnews/news.properties @@ -52,9 +52,7 @@ enterPasswordTitle=News Server Password Required okButtonText=Download noNewMessages=There are no new messages on the server. -# The difference between these two is that the second one is shown when processing XHDR commands downloadingHeaders=Downloading %S of %S headers -downloadingFilterHeaders=Getting filter headers: %S (%S/%S) downloadingArticles=Downloading articles %S-%S bytesReceived=Downloading newsgroups: %S received (%SKB read at %SKB/sec) checkingForNewNews=Checking newsgroup %S of %S on %S for new messages