diff --git a/mailnews/imap/src/nsImapMailFolder.cpp b/mailnews/imap/src/nsImapMailFolder.cpp index cea05e11a4c4..7ec1261736d0 100644 --- a/mailnews/imap/src/nsImapMailFolder.cpp +++ b/mailnews/imap/src/nsImapMailFolder.cpp @@ -39,6 +39,12 @@ #include "nsMsgBaseCID.h" #include "nsMsgLocalCID.h" +#ifdef DOING_FILTERS +#include "nsIMsgFilter.h" +#include "nsIMsgFilterService.h" +static NS_DEFINE_CID(kMsgFilterServiceCID, NS_MSGFILTERSERVICE_CID); +#endif + // we need this because of an egcs 1.0 (and possibly gcc) compiler bug // that doesn't allow you to call ::nsISupports::GetIID() inside of a class // that multiply inherits from nsISupports @@ -127,7 +133,12 @@ NS_IMETHODIMP nsImapMailFolder::QueryInterface(REFNSIID aIID, void** aInstancePt { *aInstancePtr = NS_STATIC_CAST(nsIUrlListener *, this); } - +#ifdef DOING_FILTERS + else if (aIID.Equals(nsIMsgFilterHitNotify::GetIID())) + { + *aInstancePtr = NS_STATIC_CAST(nsIMsgFilterHitNotify *, this); + } +#endif if(*aInstancePtr) { AddRef(); @@ -401,8 +412,7 @@ NS_IMETHODIMP nsImapMailFolder::GetMessages(nsIEnumerator* *result) char *folderName = nsnull; rv = GetName(&folderName); -// if (folderName && !PL_strcasecmp(folderName, "INBOX")) - selectFolder = PR_TRUE; + selectFolder = PR_TRUE; delete [] folderName; @@ -1271,6 +1281,19 @@ NS_IMETHODIMP nsImapMailFolder::SetupHeaderParseStream( if (!mDatabase) GetDatabase(); +#ifdef DOING_FILTERS + if (mFlags & MSG_FOLDER_FLAG_INBOX && !m_filterList) + { + NS_WITH_SERVICE(nsIMsgFilterService, filterService, kMsgFilterServiceCID, &rv); + if (NS_FAILED(rv)) + return rv; + + // need a file spec for filters... + nsFileSpec filterFile("rules.dat"); + nsresult res = filterService->OpenFilterList(&filterFile, getter_AddRefs(m_filterList)); + + } +#endif m_nextMessageByteLength = aStreamInfo->size; if (!m_msgParser) { @@ -1334,8 +1357,24 @@ NS_IMETHODIMP nsImapMailFolder::NormalEndHeaderParseStream(nsIImapProtocol* m_msgParser->GetNewMsgHdr(getter_AddRefs(newMsgHdr)); if (NS_SUCCEEDED(rv) && newMsgHdr) { + char *headers; + PRInt32 headersSize; + newMsgHdr->SetMessageKey(m_curMsgUid); TweakHeaderFlags(aProtocol, newMsgHdr); + // If this is the inbox, try to apply filters. + if (mFlags & MSG_FOLDER_FLAG_INBOX) + { + rv = m_msgParser->GetAllHeaders(&headers, &headersSize); + + if (NS_SUCCEEDED(rv) && headers) + { +#ifdef DOING_FILTERS + m_filterList->ApplyFiltersToHdr(nsMsgFilterInboxRule, newMsgHdr, this, mDatabase, + headers, headersSize, this); +#endif + } + } // here we need to tweak flags from uid state.. mDatabase->AddNewHdrToDB(newMsgHdr, PR_TRUE); m_msgParser->FinishHeader(); @@ -1413,6 +1452,218 @@ NS_IMETHODIMP nsImapMailFolder::EndCopy(PRBool copySucceeded) return rv; } +#ifdef DOING_FILTERS +NS_IMETHODIMP nsImapMailFolder::ApplyFilterHit(nsIMsgFilter *filter, PRBool *applyMore) +{ + nsMsgRuleActionType actionType; + void *value = nsnull; + PRUint32 newFlags; + nsresult rv = NS_OK; + + if (!applyMore) + { + NS_ASSERTION(PR_FALSE, "need to return status!"); + return NS_ERROR_NULL_POINTER; + } + // look at action - currently handle move +#ifdef DEBUG_bienvenu + printf("got a rule hit!\n"); +#endif + if (NS_SUCCEEDED(filter->GetAction(&actionType, &value))) + { + nsCOMPtr msgHdr; + nsresult rv = NS_OK; + + if (m_msgParser) + m_msgParser->GetNewMsgHdr(getter_AddRefs(msgHdr)); + if (NS_SUCCEEDED(rv) && msgHdr) + + { + PRUint32 msgFlags; + + msgHdr->GetFlags(&msgFlags); + + PRBool isRead = (msgFlags & MSG_FLAG_READ); + switch (actionType) + { + case nsMsgFilterActionDelete: + { +#ifdef DOING_DELETE + MSG_IMAPFolderInfoMail *imapFolder = m_folder->GetIMAPFolderInfoMail(); + PRBool serverIsImap = GetMaster()->GetPrefs()->GetMailServerIsIMAP4(); + PRBool deleteToTrash = !imapFolder || imapFolder->DeleteIsMoveToTrash(); + PRBool showDeletedMessages = (!imapFolder) || imapFolder->ShowDeletedMessages(); + if (deleteToTrash || !serverIsImap) + { + // set value to trash folder + MSG_FolderInfoMail *mailTrash = GetTrashFolder(); + if (mailTrash) + value = (void *) mailTrash->GetPathname(); + + msgHdr->OrFlags(MSG_FLAG_READ); // mark read in trash. + } + else // (!deleteToTrash && serverIsImap) + { + msgHdr->OrFlags(MSG_FLAG_READ | MSG_FLAG_IMAP_DELETED); + nsMsgKeyArray keysToFlag; + + keysToFlag.Add(msgHdr->GetMessageKey()); + if (imapFolder) + imapFolder->StoreImapFlags(m_pane, kImapMsgSeenFlag | kImapMsgDeletedFlag, TRUE, keysToFlag, ((ParseIMAPMailboxState *) this)->GetFilterUrlQueue()); + if (!showDeletedMessages) + msgMoved = TRUE; // this will prevent us from adding the header to the db. + + } +#endif // DOING_DELETE + } + case nsMsgFilterActionMoveToFolder: + { + // if moving to a different file, do it. + char *folderName = nsnull; + rv = GetName(&folderName); + + if (value && PL_strcasecmp(folderName, (char *) value)) + { + PRUint32 msgFlags; + msgHdr->GetFlags(&msgFlags); + + if (msgFlags & MSG_FLAG_MDN_REPORT_NEEDED && + !isRead) + { + +#if DOING_MDN // leave it to the user aciton + struct message_header to; + struct message_header cc; + GetAggregateHeader (m_toList, &to); + GetAggregateHeader (m_ccList, &cc); + msgHdr->SetFlags(msgFlags & ~MSG_FLAG_MDN_REPORT_NEEDED); + msgHdr->OrFlags(MSG_FLAG_MDN_REPORT_SENT, &newFlags); + if (actionType == nsMsgFilterActionDelete) + { + MSG_ProcessMdnNeededState processMdnNeeded + (MSG_ProcessMdnNeededState::eDeleted, + m_pane, m_folder, msgHdr->GetMessageKey(), + &state->m_return_path, &state->m_mdn_dnt, + &to, &cc, &state->m_subject, + &state->m_date, &state->m_mdn_original_recipient, + &state->m_message_id, state->m_headers, + (PRInt32) state->m_headers_fp, TRUE); + } + else + { + MSG_ProcessMdnNeededState processMdnNeeded + (MSG_ProcessMdnNeededState::eProcessed, + m_pane, m_folder, msgHdr->GetMessageKey(), + &state->m_return_path, &state->m_mdn_dnt, + &to, &cc, &state->m_subject, + &state->m_date, &state->m_mdn_original_recipient, + &state->m_message_id, state->m_headers, + (PRInt32) state->m_headers_fp, TRUE); + } + char *tmp = (char*) to.value; + PR_FREEIF(tmp); + tmp = (char*) cc.value; + PR_FREEIF(tmp); +#endif + } + nsresult err = MoveIncorporatedMessage(msgHdr, mDatabase, (char *) value, filter); + if (NS_SUCCEEDED(err)) + m_msgMovedByFilter = PR_TRUE; + + } + delete [] folderName; + } + break; + case nsMsgFilterActionMarkRead: + MarkFilteredMessageRead(msgHdr); + break; + case nsMsgFilterActionKillThread: + // for ignore and watch, we will need the db + // to check for the flags in msgHdr's that + // get added, because only then will we know + // the thread they're getting added to. + msgHdr->OrFlags(MSG_FLAG_IGNORED, &newFlags); + break; + case nsMsgFilterActionWatchThread: + msgHdr->OrFlags(MSG_FLAG_WATCHED, &newFlags); + break; + case nsMsgFilterActionChangePriority: + msgHdr->SetPriority(*(nsMsgPriority *) &value); + break; + default: + break; + } + } + return rv; + } +} + + +nsresult nsImapMailFolder::MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr, + nsIMsgDatabase *sourceDB, + char *destFolder, + nsIMsgFilter *filter) +{ + nsresult err = NS_OK; + + if (fUrlQueue && fUrlQueue->GetPane()) + { + // look for matching imap folders, then pop folders + MSG_FolderInfoContainer *imapContainer = m_imapContainer; + nsIMsgFolder *sourceFolder = imapContainer->FindMailPathname(m_mailboxName); + nsIMsgFolder *destinationFolder = imapContainer->FindMailPathname(destFolder); + if (!destinationFolder) + destinationFolder = m_mailMaster->FindMailFolder(destFolder, FALSE); + + if (destinationFolder) + { + nsIMsgFolder *inbox=nsnull; + imapContainer->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, &inbox, 1); + if (inbox) + { + MSG_FolderInfoMail *destMailFolder = destinationFolder->GetMailFolderInfo(); + // put the header into the source db, since it needs to be there when we copy it + // and we need a valid header to pass to StartAsyncCopyMessagesInto + nsMsgKey keyToFilter = mailHdr->GetMessageKey(); + + if (sourceDB && destMailFolder) + { + PRBool imapDeleteIsMoveToTrash = m_host->GetDeleteIsMoveToTrash(); + + nsMsgKeyArray *idsToMoveFromInbox = destMailFolder->GetImapIdsToMoveFromInbox(); + idsToMoveFromInbox->Add(keyToFilter); + + // this is our last best chance to log this + if (m_filterList->LoggingEnabled()) + filter->LogRuleHit(GetLogFile(), mailHdr); + + if (imapDeleteIsMoveToTrash) + { + if (m_parseMsgState->m_newMsgHdr) + { + m_parseMsgState->m_newMsgHdr->Release(); + m_parseMsgState->m_newMsgHdr = nsnull; + } + } + + destinationFolder->SetFlag(MSG_FOLDER_FLAG_GOT_NEW); + + if (imapDeleteIsMoveToTrash) + err = 0; + } + } + } + } + + + // we have to return an error because we do not actually move the message + // it is done async and that can fail + return err; +} + + +#endif // DOING_FILTERS + // both of these algorithms assume that key arrays and flag states are sorted by increasing key. void nsImapMailFolder::FindKeysToDelete(const nsMsgKeyArray &existingKeys, nsMsgKeyArray &keysToDelete, nsImapFlagAndUidState *flagState) { diff --git a/mailnews/imap/src/nsImapMailFolder.h b/mailnews/imap/src/nsImapMailFolder.h index 5b40bdc48107..c2a668ca6d12 100644 --- a/mailnews/imap/src/nsImapMailFolder.h +++ b/mailnews/imap/src/nsImapMailFolder.h @@ -29,6 +29,13 @@ #include "nsIUrlListener.h" #include "nsIImapIncomingServer.h" // we need this for its IID #include "nsIMsgParseMailMsgState.h" +#ifdef DEBUG_bienvenu +//#define DOING_FILTERS +#endif +#ifdef DOING_FILTERS +#include "nsIMsgFilterHitNotify.h" +#include "nsIMsgFilterList.h" +#endif /* fa32d000-f6a0-11d2-af8d-001083002da8 */ #define NS_IMAPRESOURCE_CID \ @@ -43,6 +50,9 @@ class nsImapMailFolder : public nsMsgDBFolder, public nsIImapMiscellaneousSink, public nsICopyMessageListener, public nsIUrlListener +#ifdef DOING_FILTERS + ,public nsIMsgFilterHitNotify +#endif { public: nsImapMailFolder(); @@ -231,6 +241,15 @@ public: NS_IMETHOD ProcessTunnel(nsIImapProtocol* aProtocol, TunnelInfo *aInfo); +#ifdef DOING_FILTERS + // nsIMsgFilterHitNotification method(s) + NS_IMETHOD ApplyFilterHit(nsIMsgFilter *filter, PRBool *applyMore); + + nsresult MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr, + nsIMsgDatabase *sourceDB, + char *destFolder, + nsIMsgFilter *filter) +#endif // DOING_FILTERS protected: // Helper methods void FindKeysToAdd(const nsMsgKeyArray &existingKeys, nsMsgKeyArray @@ -263,6 +282,10 @@ protected: PRBool m_haveDiscoverAllFolders; PRBool m_haveReadNameFromDB; nsCOMPtr m_msgParser; +#ifdef DOING_FILTERS + nsCOMPtr m_filterList; + PRBool m_msgMovedByFilter; +#endif nsMsgKey m_curMsgUid; PRInt32 m_nextMessageByteLength; nsCOMPtr m_eventQueue; diff --git a/mailnews/local/public/nsIMsgParseMailMsgState.h b/mailnews/local/public/nsIMsgParseMailMsgState.h index 7cbb6180d963..c7d3bd77761f 100644 --- a/mailnews/local/public/nsIMsgParseMailMsgState.h +++ b/mailnews/local/public/nsIMsgParseMailMsgState.h @@ -46,6 +46,7 @@ public: NS_IMETHOD ParseAFolderLine(const char *line, PRUint32 lineLength) = 0; NS_IMETHOD GetNewMsgHdr(nsIMsgDBHdr ** aMsgHeader) = 0; NS_IMETHOD FinishHeader() = 0; + NS_IMETHOD GetAllHeaders(char **headers, PRInt32 *headersSize) = 0; }; #endif /* nsIMsgParseMailMsgState_h___ */ diff --git a/mailnews/local/src/nsParseMailbox.cpp b/mailnews/local/src/nsParseMailbox.cpp index 5ceb58125110..cf54cb9d61e3 100644 --- a/mailnews/local/src/nsParseMailbox.cpp +++ b/mailnews/local/src/nsParseMailbox.cpp @@ -605,6 +605,16 @@ NS_IMETHODIMP nsParseMailMessageState::FinishHeader() return NS_OK; } +NS_IMETHODIMP nsParseMailMessageState::GetAllHeaders(char ** pHeaders, PRInt32 *pHeadersSize) +{ + if (!pHeaders || !pHeadersSize) + return NS_ERROR_NULL_POINTER; + *pHeaders = m_headers.GetBuffer(); + *pHeadersSize = m_headers.GetBufferPos(); + return NS_OK; +} + + struct message_header *nsParseMailMessageState::GetNextHeaderInAggregate (nsVoidArray &list) { // When parsing a message with multiple To or CC header lines, we're storing each line in a @@ -1332,6 +1342,10 @@ nsParseNewMailState::nsParseNewMailState() #endif } +#ifdef DOING_FILTERS +NS_IMPL_ISUPPORTS_INHERITED(nsParseNewMailState, nsMsgMailboxParser, nsIMsgFilterHitNotify) +#endif + nsresult nsParseNewMailState::Init(nsIFolder *rootFolder, nsFileSpec &folder, nsIOFileStream *inboxFileStream) { @@ -1538,186 +1552,160 @@ nsIMsgFolder *nsParseNewMailState::GetTrashFolder() void nsParseNewMailState::ApplyFilters(PRBool *pMoved) { - nsIMsgFilter *filter; - PRUint32 filterCount = 0; PRBool msgMoved = FALSE; - PRUint32 newFlags; + + m_msgMovedByFilter = PR_FALSE; nsIMsgDBHdr *msgHdr = m_newMsgHdr; - if (m_filterList != nsnull) - m_filterList->GetFilterCount(&filterCount); - - for (PRUint32 filterIndex = 0; filterIndex < filterCount; filterIndex++) + nsCOMPtr inbox; + nsCOMPtr rootMsgFolder = do_QueryInterface(m_rootFolder); + if (rootMsgFolder) { - if (NS_SUCCEEDED(m_filterList->GetFilterAt(filterIndex, &filter))) - { - PRBool isEnabled; - nsMsgFilterType filterType; + PRUint32 numFolders; + rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, getter_AddRefs(inbox), 1, &numFolders); + char * headers = m_headers.GetBuffer(); + PRUint32 headersSize = m_headers.GetBufferPos(); + nsresult matchTermStatus = m_filterList->ApplyFiltersToHdr(nsMsgFilterInboxRule, msgHdr, inbox, + m_mailDB, headers, headersSize, this); + } - filter->IsFilterEnabled(&isEnabled); - if (!isEnabled) - continue; + if (pMoved) + *pMoved = m_msgMovedByFilter; +} - filter->GetFilterType(&filterType); - if (filterType == nsMsgFilterInboxJavaScript) - { -#ifdef DOING_JSFILTERS - if (JSMailFilter_execute(this, filter, msgHdr, m_mailDB, &msgMoved) == SearchError_Success) - break; -#endif - } - else if (filterType == nsMsgFilterInboxRule) - { - nsresult matchTermStatus = NS_OK; +NS_IMETHODIMP nsParseNewMailState::ApplyFilterHit(nsIMsgFilter *filter, PRBool *applyMore) +{ + nsMsgRuleActionType actionType; + void *value = nsnull; + PRUint32 newFlags; + nsresult rv = NS_OK; - { - // how are we going to do this? Probably we need to load - // the offline mail search service and run the filter, - // or perhaps just add an interface on the filter object - // that does it internally. - - nsCOMPtr inbox; - nsCOMPtr rootMsgFolder = do_QueryInterface(m_rootFolder); - if (rootMsgFolder) - { - PRUint32 numFolders; - rootMsgFolder->GetFoldersWithFlag(MSG_FOLDER_FLAG_INBOX, getter_AddRefs(inbox), 1, &numFolders); - char * headers = m_headers.GetBuffer(); - PRUint32 headersSize = m_headers.GetBufferPos(); - matchTermStatus = filter->MatchHdr(msgHdr, inbox, m_mailDB, headers, headersSize); - } - - } - if (matchTermStatus == NS_OK) - { - nsMsgRuleActionType actionType; - void *value = nsnull; - // look at action - currently handle move + if (!applyMore) + { + NS_ASSERTION(PR_FALSE, "need to return status!"); + return NS_ERROR_NULL_POINTER; + } + // look at action - currently handle move #ifdef DEBUG_bienvenu - printf("got a rule hit!\n"); + printf("got a rule hit!\n"); #endif - if (NS_SUCCEEDED(filter->GetAction(&actionType, &value))) - { - PRUint32 msgFlags; + if (NS_SUCCEEDED(filter->GetAction(&actionType, &value))) + { + nsIMsgDBHdr *msgHdr = m_newMsgHdr; + PRUint32 msgFlags; - msgHdr->GetFlags(&msgFlags); + msgHdr->GetFlags(&msgFlags); - PRBool isRead = (msgFlags & MSG_FLAG_READ); - switch (actionType) - { - case nsMsgFilterActionDelete: - { + PRBool isRead = (msgFlags & MSG_FLAG_READ); + switch (actionType) + { + case nsMsgFilterActionDelete: + { #ifdef DOING_DELETE - MSG_IMAPFolderInfoMail *imapFolder = m_folder->GetIMAPFolderInfoMail(); - PRBool serverIsImap = GetMaster()->GetPrefs()->GetMailServerIsIMAP4(); - PRBool deleteToTrash = !imapFolder || imapFolder->DeleteIsMoveToTrash(); - PRBool showDeletedMessages = (!imapFolder) || imapFolder->ShowDeletedMessages(); - if (deleteToTrash || !serverIsImap) - { - // set value to trash folder - MSG_FolderInfoMail *mailTrash = GetTrashFolder(); - if (mailTrash) - value = (void *) mailTrash->GetPathname(); + MSG_IMAPFolderInfoMail *imapFolder = m_folder->GetIMAPFolderInfoMail(); + PRBool serverIsImap = GetMaster()->GetPrefs()->GetMailServerIsIMAP4(); + PRBool deleteToTrash = !imapFolder || imapFolder->DeleteIsMoveToTrash(); + PRBool showDeletedMessages = (!imapFolder) || imapFolder->ShowDeletedMessages(); + if (deleteToTrash || !serverIsImap) + { + // set value to trash folder + MSG_FolderInfoMail *mailTrash = GetTrashFolder(); + if (mailTrash) + value = (void *) mailTrash->GetPathname(); - msgHdr->OrFlags(MSG_FLAG_READ); // mark read in trash. - } - else // (!deleteToTrash && serverIsImap) - { - msgHdr->OrFlags(MSG_FLAG_READ | MSG_FLAG_IMAP_DELETED); - nsMsgKeyArray keysToFlag; + msgHdr->OrFlags(MSG_FLAG_READ); // mark read in trash. + } + else // (!deleteToTrash && serverIsImap) + { + msgHdr->OrFlags(MSG_FLAG_READ | MSG_FLAG_IMAP_DELETED); + nsMsgKeyArray keysToFlag; - keysToFlag.Add(msgHdr->GetMessageKey()); - if (imapFolder) - imapFolder->StoreImapFlags(m_pane, kImapMsgSeenFlag | kImapMsgDeletedFlag, TRUE, keysToFlag, ((ParseIMAPMailboxState *) this)->GetFilterUrlQueue()); - if (!showDeletedMessages) - msgMoved = TRUE; // this will prevent us from adding the header to the db. + keysToFlag.Add(msgHdr->GetMessageKey()); + if (imapFolder) + imapFolder->StoreImapFlags(m_pane, kImapMsgSeenFlag | kImapMsgDeletedFlag, TRUE, keysToFlag, ((ParseIMAPMailboxState *) this)->GetFilterUrlQueue()); + if (!showDeletedMessages) + msgMoved = TRUE; // this will prevent us from adding the header to the db. - } + } #endif // DOING_DELETE - } - case nsMsgFilterActionMoveToFolder: - // if moving to a different file, do it. - if (value && PL_strcasecmp(m_mailboxName, (char *) value)) - { - PRUint32 msgFlags; - msgHdr->GetFlags(&msgFlags); + } + case nsMsgFilterActionMoveToFolder: + // if moving to a different file, do it. + if (value && PL_strcasecmp(m_mailboxName, (char *) value)) + { + PRUint32 msgFlags; + msgHdr->GetFlags(&msgFlags); - if (msgFlags & MSG_FLAG_MDN_REPORT_NEEDED && - !isRead) - { - struct message_header to; - struct message_header cc; - GetAggregateHeader (m_toList, &to); - GetAggregateHeader (m_ccList, &cc); - msgHdr->SetFlags(msgFlags & ~MSG_FLAG_MDN_REPORT_NEEDED); - msgHdr->OrFlags(MSG_FLAG_MDN_REPORT_SENT, &newFlags); + if (msgFlags & MSG_FLAG_MDN_REPORT_NEEDED && + !isRead) + { + struct message_header to; + struct message_header cc; + GetAggregateHeader (m_toList, &to); + GetAggregateHeader (m_ccList, &cc); + msgHdr->SetFlags(msgFlags & ~MSG_FLAG_MDN_REPORT_NEEDED); + msgHdr->OrFlags(MSG_FLAG_MDN_REPORT_SENT, &newFlags); #if DOING_MDN // leave it to the user aciton - if (actionType == nsMsgFilterActionDelete) - { - MSG_ProcessMdnNeededState processMdnNeeded - (MSG_ProcessMdnNeededState::eDeleted, - m_pane, m_folder, msgHdr->GetMessageKey(), - &state->m_return_path, &state->m_mdn_dnt, - &to, &cc, &state->m_subject, - &state->m_date, &state->m_mdn_original_recipient, - &state->m_message_id, state->m_headers, - (PRInt32) state->m_headers_fp, TRUE); - } - else - { - MSG_ProcessMdnNeededState processMdnNeeded - (MSG_ProcessMdnNeededState::eProcessed, - m_pane, m_folder, msgHdr->GetMessageKey(), - &state->m_return_path, &state->m_mdn_dnt, - &to, &cc, &state->m_subject, - &state->m_date, &state->m_mdn_original_recipient, - &state->m_message_id, state->m_headers, - (PRInt32) state->m_headers_fp, TRUE); - } -#endif - char *tmp = (char*) to.value; - PR_FREEIF(tmp); - tmp = (char*) cc.value; - PR_FREEIF(tmp); - } - nsresult err = MoveIncorporatedMessage(msgHdr, m_mailDB, (char *) value, filter); - if (NS_SUCCEEDED(err)) - msgMoved = TRUE; - - } - break; - case nsMsgFilterActionMarkRead: - MarkFilteredMessageRead(msgHdr); - break; - case nsMsgFilterActionKillThread: - // for ignore and watch, we will need the db - // to check for the flags in msgHdr's that - // get added, because only then will we know - // the thread they're getting added to. - msgHdr->OrFlags(MSG_FLAG_IGNORED, &newFlags); - break; - case nsMsgFilterActionWatchThread: - msgHdr->OrFlags(MSG_FLAG_WATCHED, &newFlags); - break; - case nsMsgFilterActionChangePriority: - msgHdr->SetPriority(*(nsMsgPriority *) &value); - break; - default: - break; - } - PRBool loggingEnabled; - m_filterList->IsLoggingEnabled(&loggingEnabled); - if (loggingEnabled && !msgMoved && actionType != nsMsgFilterActionMoveToFolder) - filter->LogRuleHit(GetLogFile(), msgHdr); + if (actionType == nsMsgFilterActionDelete) + { + MSG_ProcessMdnNeededState processMdnNeeded + (MSG_ProcessMdnNeededState::eDeleted, + m_pane, m_folder, msgHdr->GetMessageKey(), + &state->m_return_path, &state->m_mdn_dnt, + &to, &cc, &state->m_subject, + &state->m_date, &state->m_mdn_original_recipient, + &state->m_message_id, state->m_headers, + (PRInt32) state->m_headers_fp, TRUE); } - break; + else + { + MSG_ProcessMdnNeededState processMdnNeeded + (MSG_ProcessMdnNeededState::eProcessed, + m_pane, m_folder, msgHdr->GetMessageKey(), + &state->m_return_path, &state->m_mdn_dnt, + &to, &cc, &state->m_subject, + &state->m_date, &state->m_mdn_original_recipient, + &state->m_message_id, state->m_headers, + (PRInt32) state->m_headers_fp, TRUE); + } +#endif + char *tmp = (char*) to.value; + PR_FREEIF(tmp); + tmp = (char*) cc.value; + PR_FREEIF(tmp); } + nsresult err = MoveIncorporatedMessage(msgHdr, m_mailDB, (char *) value, filter); + if (NS_SUCCEEDED(err)) + m_msgMovedByFilter = PR_TRUE; + } + break; + case nsMsgFilterActionMarkRead: + MarkFilteredMessageRead(msgHdr); + break; + case nsMsgFilterActionKillThread: + // for ignore and watch, we will need the db + // to check for the flags in msgHdr's that + // get added, because only then will we know + // the thread they're getting added to. + msgHdr->OrFlags(MSG_FLAG_IGNORED, &newFlags); + break; + case nsMsgFilterActionWatchThread: + msgHdr->OrFlags(MSG_FLAG_WATCHED, &newFlags); + break; + case nsMsgFilterActionChangePriority: + msgHdr->SetPriority(*(nsMsgPriority *) &value); + break; + default: + break; } + PRBool loggingEnabled; + m_filterList->LoggingEnabled(&loggingEnabled); + if (loggingEnabled && !m_msgMovedByFilter && actionType != nsMsgFilterActionMoveToFolder) + filter->LogRuleHit(GetLogFile(), msgHdr); } - if (pMoved) - *pMoved = msgMoved; + return rv; } int nsParseNewMailState::MarkFilteredMessageRead(nsIMsgDBHdr *msgHdr) @@ -1897,7 +1885,7 @@ nsresult nsParseNewMailState::MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr, // We are logging the hit with the old mailHdr, which should work, as long // as LogRuleHit doesn't assume the new hdr. PRBool loggingEnabled; - m_filterList->IsLoggingEnabled(&loggingEnabled); + m_filterList->LoggingEnabled(&loggingEnabled); if (loggingEnabled) filter->LogRuleHit(GetLogFile(), mailHdr); @@ -2016,7 +2004,7 @@ nsresult ParseIMAPMailboxState::MoveIncorporatedMessage(nsIMsgDBHdr *mailHdr, idsToMoveFromInbox->Add(keyToFilter); // this is our last best chance to log this - if (m_filterList->IsLoggingEnabled()) + if (m_filterList->LoggingEnabled()) filter->LogRuleHit(GetLogFile(), mailHdr); if (imapDeleteIsMoveToTrash) diff --git a/mailnews/local/src/nsParseMailbox.h b/mailnews/local/src/nsParseMailbox.h index 4033fd34a774..afd3dd7790c6 100644 --- a/mailnews/local/src/nsParseMailbox.h +++ b/mailnews/local/src/nsParseMailbox.h @@ -32,7 +32,12 @@ #ifdef DEBUG_bienvenu -#define DOING_FILTERS +//#define DOING_FILTERS +#endif + +#ifdef DOING_FILTERS +#include "nsIMsgFilterList.h" +#include "nsIMsgFilterHitNotify.h" #endif class nsFileSpec; @@ -75,7 +80,7 @@ public: NS_IMETHOD ParseAFolderLine(const char *line, PRUint32 lineLength); NS_IMETHOD GetNewMsgHdr(nsIMsgDBHdr ** aMsgHeader); NS_IMETHOD FinishHeader(); - + NS_IMETHOD GetAllHeaders(char **headers, PRInt32 *headersSize); void Init(PRUint32 fileposition); virtual PRInt32 ParseFolderLine(const char *line, PRUint32 lineLength); virtual int StartNewEnvelope(const char *line, PRUint32 lineLength); @@ -233,11 +238,16 @@ private: }; class nsParseNewMailState : public nsMsgMailboxParser +#ifdef DOING_FILTERS +, public nsIMsgFilterHitNotify +#endif { public: nsParseNewMailState(); virtual ~nsParseNewMailState(); - +#ifdef DOING_FILTERS + NS_DECL_ISUPPORTS_INHERITED +#endif nsresult Init(nsIFolder *rootFolder, nsFileSpec &folder, nsIOFileStream *inboxFileStream); virtual void DoneParsingFolder(); @@ -255,6 +265,9 @@ public: PRBool *pMoved); #endif #ifdef DOING_FILTERS + // nsIMsgFilterHitNotification method(s) + NS_IMETHOD ApplyFilterHit(nsIMsgFilter *filter, PRBool *applyMore); + nsOutputFileStream *GetLogFile(); #endif // DOING_FILTERS protected: @@ -277,6 +290,7 @@ protected: char *m_tmpdbName; // Temporary filename of new database PRBool m_usingTempDB; PRBool m_disableFilters; + PRBool m_msgMovedByFilter; }; #ifdef IMAP_NEW_MAIL_HANDLED