Mozilla/mozilla/mailnews/base/src/nsMsgSearchDBView.cpp
2006-08-09 01:29:45 +00:00

632 lines
20 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Seth Spitzer <sspitzer@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "msgCore.h"
#include "nsMsgSearchDBView.h"
#include "nsIMsgHdr.h"
#include "nsIMsgThread.h"
#include "nsQuickSort.h"
#include "nsIDBFolderInfo.h"
#include "nsXPIDLString.h"
#include "nsMsgBaseCID.h"
#include "nsIMsgCopyService.h"
#include "nsICopyMsgStreamListener.h"
#include "nsMsgUtils.h"
#include "nsITreeColumns.h"
#include "nsIMsgMessageService.h"
nsMsgSearchDBView::nsMsgSearchDBView()
{
// don't try to display messages for the search pane.
mSuppressMsgDisplay = PR_TRUE;
}
nsMsgSearchDBView::~nsMsgSearchDBView()
{
}
NS_IMPL_ISUPPORTS_INHERITED3(nsMsgSearchDBView, nsMsgDBView, nsIMsgDBView, nsIMsgCopyServiceListener, nsIMsgSearchNotify)
NS_IMETHODIMP nsMsgSearchDBView::Open(nsIMsgFolder *folder, nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder, nsMsgViewFlagsTypeValue viewFlags, PRInt32 *pCount)
{
nsresult rv;
m_folders = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsMsgDBView::Open(folder, sortType, sortOrder, viewFlags, pCount);
NS_ENSURE_SUCCESS(rv, rv);
if (pCount)
*pCount = 0;
m_folder = nsnull;
return rv;
}
NS_IMETHODIMP
nsMsgSearchDBView::CopyDBView(nsMsgDBView *aNewMsgDBView, nsIMessenger *aMessengerInstance,
nsIMsgWindow *aMsgWindow, nsIMsgDBViewCommandUpdater *aCmdUpdater)
{
nsMsgDBView::CopyDBView(aNewMsgDBView, aMessengerInstance, aMsgWindow, aCmdUpdater);
nsMsgSearchDBView* newMsgDBView = (nsMsgSearchDBView *) aNewMsgDBView;
// now copy all of our private member data
newMsgDBView->mDestFolder = mDestFolder;
newMsgDBView->mCommand = mCommand;
newMsgDBView->mTotalIndices = mTotalIndices;
newMsgDBView->mCurIndex = mCurIndex;
if (m_folders)
m_folders->Clone(getter_AddRefs(newMsgDBView->m_folders));
if (m_hdrsForEachFolder)
m_hdrsForEachFolder->Clone(getter_AddRefs(newMsgDBView->m_hdrsForEachFolder));
if (m_copyListenerList)
m_copyListenerList->Clone(getter_AddRefs(newMsgDBView->m_copyListenerList));
if (m_uniqueFoldersSelected)
m_uniqueFoldersSelected->Clone(getter_AddRefs(newMsgDBView->m_uniqueFoldersSelected));
PRInt32 count = m_dbToUseList.Count();
for(PRInt32 i = 0; i < count; i++)
{
newMsgDBView->m_dbToUseList.AppendObject(m_dbToUseList[i]);
// register the new view with the database so it gets notifications
m_dbToUseList[i]->AddListener(newMsgDBView);
}
// nsUInt32Array* mTestIndices;
return NS_OK;
}
NS_IMETHODIMP nsMsgSearchDBView::Close()
{
PRInt32 count = m_dbToUseList.Count();
for(PRInt32 i = 0; i < count; i++)
m_dbToUseList[i]->RemoveListener(this);
m_dbToUseList.Clear();
return NS_OK;
}
NS_IMETHODIMP nsMsgSearchDBView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAString& aValue)
{
const PRUnichar* colID;
aCol->GetIdConst(&colID);
if (colID[0] == 'l' && colID[1] == 'o') // location, need to check for "lo" not just "l" to avoid "label" column
{
// XXX fix me by converting Fetch* to take an nsAString& parameter
nsXPIDLString valueText;
nsresult rv = FetchLocation(aRow, getter_Copies(valueText));
aValue.Assign(valueText);
return rv;
}
else
return nsMsgDBView::GetCellText(aRow, aCol, aValue);
}
nsresult nsMsgSearchDBView::FetchLocation(PRInt32 aRow, PRUnichar ** aLocationString)
{
nsCOMPtr <nsIMsgFolder> folder;
nsresult rv = GetFolderForViewIndex(aRow, getter_AddRefs(folder));
NS_ENSURE_SUCCESS(rv,rv);
rv = folder->GetPrettiestName(aLocationString);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
nsresult nsMsgSearchDBView::OnNewHeader(nsIMsgDBHdr *newHdr, nsMsgKey aParentKey, PRBool /*ensureListed*/)
{
return NS_OK;
}
nsresult nsMsgSearchDBView::GetMsgHdrForViewIndex(nsMsgViewIndex index, nsIMsgDBHdr **msgHdr)
{
nsresult rv = NS_MSG_INVALID_DBVIEW_INDEX;
nsCOMPtr<nsIMsgFolder> folder = do_QueryElementAt(m_folders, index);
if (folder)
{
nsCOMPtr <nsIMsgDatabase> db;
rv = folder->GetMsgDatabase(mMsgWindow, getter_AddRefs(db));
NS_ENSURE_SUCCESS(rv, rv);
if (db)
rv = db->GetMsgHdrForKey(m_keys.GetAt(index), msgHdr);
}
return rv;
}
NS_IMETHODIMP nsMsgSearchDBView::GetFolderForViewIndex(nsMsgViewIndex index, nsIMsgFolder **aFolder)
{
return m_folders->QueryElementAt(index, NS_GET_IID(nsIMsgFolder), (void **) aFolder);
}
nsresult nsMsgSearchDBView::GetDBForViewIndex(nsMsgViewIndex index, nsIMsgDatabase **db)
{
nsCOMPtr <nsIMsgFolder> aFolder;
GetFolderForViewIndex(index, getter_AddRefs(aFolder));
if (aFolder)
return aFolder->GetMsgDatabase(nsnull, db);
else
return NS_MSG_INVALID_DBVIEW_INDEX;
}
nsresult nsMsgSearchDBView::AddHdrFromFolder(nsIMsgDBHdr *msgHdr, nsISupports *folder)
{
m_folders->AppendElement(folder);
nsMsgKey msgKey;
PRUint32 msgFlags;
msgHdr->GetMessageKey(&msgKey);
// nsMsgKey_None means it's not a valid hdr.
if (msgKey != nsMsgKey_None)
{
msgHdr->GetFlags(&msgFlags);
m_keys.Add(msgKey);
m_levels.Add(0);
m_flags.Add(msgFlags);
// this needs to be called after we add the key, since RowCountChanged() will call our GetRowCount()
if (mTree)
mTree->RowCountChanged(GetSize() - 1, 1);
}
return NS_OK;
}
NS_IMETHODIMP
nsMsgSearchDBView::OnSearchHit(nsIMsgDBHdr* aMsgHdr, nsIMsgFolder *folder)
{
NS_ENSURE_ARG(aMsgHdr);
NS_ENSURE_ARG(folder);
nsCOMPtr <nsISupports> supports = do_QueryInterface(folder);
if (m_folders->IndexOf(supports) < 0 ) //do this just for new folder
{
nsCOMPtr<nsIMsgDatabase> dbToUse;
nsCOMPtr<nsIDBFolderInfo> folderInfo;
folder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo), getter_AddRefs(dbToUse));
if (dbToUse)
{
dbToUse->AddListener(this);
m_dbToUseList.AppendObject(dbToUse);
}
}
return AddHdrFromFolder(aMsgHdr, supports);
}
NS_IMETHODIMP
nsMsgSearchDBView::OnSearchDone(nsresult status)
{
//we want to set imap delete model once the search is over because setting next
//message after deletion will happen before deleting the message and search scope
//can change with every search.
mDeleteModel = nsMsgImapDeleteModels::MoveToTrash; //set to default in case it is non-imap folder
nsCOMPtr <nsIMsgFolder> curFolder = do_QueryElementAt(m_folders, 0);
if (curFolder)
GetImapDeleteModel(curFolder);
return NS_OK;
}
// for now also acts as a way of resetting the search datasource
NS_IMETHODIMP
nsMsgSearchDBView::OnNewSearch()
{
PRInt32 oldSize = GetSize();
PRInt32 count = m_dbToUseList.Count();
for(PRInt32 j = 0; j < count; j++)
m_dbToUseList[j]->RemoveListener(this);
m_dbToUseList.Clear();
m_folders->Clear();
m_keys.RemoveAll();
m_levels.RemoveAll();
m_flags.RemoveAll();
// needs to happen after we remove the keys, since RowCountChanged() will call our GetRowCount()
if (mTree)
mTree->RowCountChanged(0, -oldSize);
// mSearchResults->Clear();
return NS_OK;
}
NS_IMETHODIMP nsMsgSearchDBView::OnAnnouncerGoingAway(nsIDBChangeAnnouncer *instigator)
{
nsIMsgDatabase *db = NS_STATIC_CAST(nsIMsgDatabase *, instigator);
if (db)
{
db->RemoveListener(this);
m_dbToUseList.RemoveObject(db);
}
return NS_OK;
}
nsresult nsMsgSearchDBView::GetFolders(nsISupportsArray **aFolders)
{
NS_ENSURE_ARG_POINTER(aFolders);
NS_IF_ADDREF(*aFolders = m_folders);
return NS_OK;
}
NS_IMETHODIMP
nsMsgSearchDBView::GetCommandStatus(nsMsgViewCommandTypeValue command, PRBool *selectable_p, nsMsgViewCommandCheckStateValue *selected_p)
{
if (command != nsMsgViewCommandType::runJunkControls)
return nsMsgDBView::GetCommandStatus(command, selectable_p, selected_p);
*selectable_p = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsMsgSearchDBView::DoCommandWithFolder(nsMsgViewCommandTypeValue command, nsIMsgFolder *destFolder)
{
mCommand = command;
mDestFolder = destFolder;
return nsMsgDBView::DoCommandWithFolder(command, destFolder);
}
NS_IMETHODIMP nsMsgSearchDBView::DoCommand(nsMsgViewCommandTypeValue command)
{
mCommand = command;
if (command == nsMsgViewCommandType::deleteMsg || command == nsMsgViewCommandType::deleteNoTrash
|| command == nsMsgViewCommandType::selectAll)
return nsMsgDBView::DoCommand(command);
nsresult rv = NS_OK;
nsUInt32Array selection;
GetSelectedIndices(&selection);
nsMsgViewIndex *indices = selection.GetData();
PRInt32 numIndices = selection.GetSize();
// we need to break apart the selection by folders, and then call
// ApplyCommandToIndices with the command and the indices in the
// selection that are from that folder.
nsUInt32Array *indexArrays;
PRInt32 numArrays;
rv = PartitionSelectionByFolder(indices, numIndices, &indexArrays, &numArrays);
NS_ENSURE_SUCCESS(rv, rv);
for (PRInt32 folderIndex = 0; folderIndex < numArrays; folderIndex++)
{
rv = ApplyCommandToIndices(command, indexArrays[folderIndex].GetData(), indexArrays[folderIndex].GetSize());
NS_ENSURE_SUCCESS(rv, rv);
}
return rv;
}
// This method just removes the specified line from the view. It does
// NOT delete it from the database.
nsresult nsMsgSearchDBView::RemoveByIndex(nsMsgViewIndex index)
{
if (!IsValidIndex(index))
return NS_MSG_INVALID_DBVIEW_INDEX;
m_folders->RemoveElementAt(index);
return nsMsgDBView::RemoveByIndex(index);
}
nsresult nsMsgSearchDBView::DeleteMessages(nsIMsgWindow *window, nsMsgViewIndex *indices, PRInt32 numIndices, PRBool deleteStorage)
{
nsresult rv;
GetFoldersAndHdrsForSelection(indices, numIndices);
if (mDeleteModel != nsMsgImapDeleteModels::MoveToTrash)
deleteStorage = PR_TRUE;
if (!deleteStorage)
rv = ProcessRequestsInOneFolder(window);
else
rv = ProcessRequestsInAllFolders(window);
return rv;
}
nsresult
nsMsgSearchDBView::CopyMessages(nsIMsgWindow *window, nsMsgViewIndex *indices, PRInt32 numIndices, PRBool isMove, nsIMsgFolder *destFolder)
{
nsresult rv;
GetFoldersAndHdrsForSelection(indices, numIndices);
rv = ProcessRequestsInOneFolder(window);
return rv;
}
nsresult
nsMsgSearchDBView::PartitionSelectionByFolder(nsMsgViewIndex *indices, PRInt32 numIndices, nsUInt32Array **indexArrays, PRInt32 *numArrays)
{
nsresult rv = NS_OK;
nsCOMPtr <nsISupportsArray> uniqueFoldersSelected = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
mCurIndex = 0;
//Build unique folder list based on headers selected by the user
for (nsMsgViewIndex i = 0; i < (nsMsgViewIndex) numIndices; i++)
{
nsCOMPtr <nsISupports> curSupports = getter_AddRefs(m_folders->ElementAt(indices[i]));
if ( uniqueFoldersSelected->IndexOf(curSupports) < 0)
uniqueFoldersSelected->AppendElement(curSupports);
}
PRUint32 numFolders =0;
rv = uniqueFoldersSelected->Count(&numFolders); //group the headers selected by each folder
*indexArrays = new nsUInt32Array[numFolders];
*numArrays = numFolders;
NS_ENSURE_TRUE(*indexArrays, NS_ERROR_OUT_OF_MEMORY);
for (PRUint32 folderIndex=0; folderIndex < numFolders; folderIndex++)
{
nsCOMPtr <nsIMsgFolder> curFolder =
do_QueryElementAt(uniqueFoldersSelected, folderIndex, &rv);
for (nsMsgViewIndex i = 0; i < (nsMsgViewIndex) numIndices; i++)
{
nsCOMPtr <nsIMsgFolder> msgFolder = do_QueryElementAt(m_folders,
indices[i], &rv);
if (NS_SUCCEEDED(rv) && msgFolder && msgFolder == curFolder)
(*indexArrays)[folderIndex].Add(indices[i]);
}
}
return rv;
}
nsresult
nsMsgSearchDBView::GetFoldersAndHdrsForSelection(nsMsgViewIndex *indices, PRInt32 numIndices)
{
nsresult rv = NS_OK;
mCurIndex = 0;
//initialize and clear from the last usage
if (!m_uniqueFoldersSelected)
{
m_uniqueFoldersSelected = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
else
m_uniqueFoldersSelected->Clear();
if (!m_hdrsForEachFolder)
{
m_hdrsForEachFolder = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
}
else
m_hdrsForEachFolder->Clear();
//Build unique folder list based on headers selected by the user
for (nsMsgViewIndex i = 0; i < (nsMsgViewIndex) numIndices; i++)
{
nsCOMPtr <nsISupports> curSupports = getter_AddRefs(m_folders->ElementAt(indices[i]));
if ( m_uniqueFoldersSelected->IndexOf(curSupports) < 0)
m_uniqueFoldersSelected->AppendElement(curSupports);
}
PRUint32 numFolders =0;
rv = m_uniqueFoldersSelected->Count(&numFolders); //group the headers selected by each folder
NS_ENSURE_SUCCESS(rv,rv);
for (PRUint32 folderIndex=0; folderIndex < numFolders; folderIndex++)
{
nsCOMPtr <nsIMsgFolder> curFolder =
do_QueryElementAt(m_uniqueFoldersSelected, folderIndex, &rv);
nsCOMPtr <nsISupportsArray> msgHdrsForOneFolder;
NS_NewISupportsArray(getter_AddRefs(msgHdrsForOneFolder));
for (nsMsgViewIndex i = 0; i < (nsMsgViewIndex) numIndices; i++)
{
nsCOMPtr <nsIMsgFolder> msgFolder = do_QueryElementAt(m_folders,
indices[i], &rv);
if (NS_SUCCEEDED(rv) && msgFolder && msgFolder == curFolder)
{
nsCOMPtr<nsIMsgDBHdr> msgHdr;
rv = GetMsgHdrForViewIndex(indices[i],getter_AddRefs(msgHdr));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsISupports> hdrSupports = do_QueryInterface(msgHdr);
msgHdrsForOneFolder->AppendElement(hdrSupports);
}
}
nsCOMPtr <nsISupports> supports = do_QueryInterface(msgHdrsForOneFolder, &rv);
if (NS_SUCCEEDED(rv) && supports)
m_hdrsForEachFolder->AppendElement(supports);
}
return rv;
}
// nsIMsgCopyServiceListener methods
NS_IMETHODIMP
nsMsgSearchDBView::OnStartCopy()
{
return NS_OK;
}
NS_IMETHODIMP
nsMsgSearchDBView::OnProgress(PRUint32 aProgress, PRUint32 aProgressMax)
{
return NS_OK;
}
// believe it or not, these next two are msgcopyservice listener methods!
NS_IMETHODIMP
nsMsgSearchDBView::SetMessageKey(PRUint32 aMessageKey)
{
return NS_OK;
}
NS_IMETHODIMP
nsMsgSearchDBView::GetMessageId(nsCString* aMessageId)
{
return NS_OK;
}
NS_IMETHODIMP
nsMsgSearchDBView::OnStopCopy(nsresult aStatus)
{
nsresult rv = NS_OK;
if (NS_SUCCEEDED(aStatus))
{
mCurIndex++;
PRUint32 numFolders =0;
rv = m_uniqueFoldersSelected->Count(&numFolders);
if ( mCurIndex < numFolders)
ProcessRequestsInOneFolder(mMsgWindow);
}
return rv;
}
// end nsIMsgCopyServiceListener methods
nsresult nsMsgSearchDBView::ProcessRequestsInOneFolder(nsIMsgWindow *window)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIMsgFolder> curFolder =
do_QueryElementAt(m_uniqueFoldersSelected, mCurIndex);
NS_ASSERTION(curFolder, "curFolder is null");
nsCOMPtr <nsISupportsArray> messageArray =
do_QueryElementAt(m_hdrsForEachFolder, mCurIndex);
NS_ASSERTION(messageArray, "messageArray is null");
// called for delete with trash, copy and move
if (mCommand == nsMsgViewCommandType::deleteMsg)
curFolder->DeleteMessages(messageArray, window, PR_FALSE /* delete storage */, PR_FALSE /* is move*/, this, PR_TRUE /*allowUndo*/);
else
{
NS_ASSERTION(!(curFolder == mDestFolder), "The source folder and the destination folder are the same");
if (NS_SUCCEEDED(rv) && curFolder != mDestFolder)
{
nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
if (mCommand == nsMsgViewCommandType::moveMessages)
copyService->CopyMessages(curFolder, messageArray, mDestFolder, PR_TRUE /* isMove */, this, window, PR_TRUE /*allowUndo*/);
else if (mCommand == nsMsgViewCommandType::copyMessages)
copyService->CopyMessages(curFolder, messageArray, mDestFolder, PR_FALSE /* isMove */, this, window, PR_TRUE /*allowUndo*/);
}
}
}
return rv;
}
nsresult nsMsgSearchDBView::ProcessRequestsInAllFolders(nsIMsgWindow *window)
{
PRUint32 numFolders =0;
nsresult rv = m_uniqueFoldersSelected->Count(&numFolders);
NS_ENSURE_SUCCESS(rv,rv);
for (PRUint32 folderIndex=0; folderIndex < numFolders; folderIndex++)
{
nsCOMPtr<nsIMsgFolder> curFolder =
do_QueryElementAt(m_uniqueFoldersSelected, folderIndex);
NS_ASSERTION (curFolder, "curFolder is null");
nsCOMPtr <nsISupportsArray> messageArray =
do_QueryElementAt(m_hdrsForEachFolder, folderIndex);
NS_ASSERTION(messageArray, "messageArray is null");
curFolder->DeleteMessages(messageArray, window, PR_TRUE /* delete storage */, PR_FALSE /* is move*/, nsnull/*copyServListener*/, PR_FALSE /*allowUndo*/ );
}
return NS_OK;
}
NS_IMETHODIMP nsMsgSearchDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder)
{
nsresult rv;
PRInt32 rowCountBeforeSort = GetSize();
if (!rowCountBeforeSort)
return NS_OK;
nsMsgKey preservedKey;
nsMsgKeyArray preservedSelection;
SaveAndClearSelection(&preservedKey, &preservedSelection);
rv = nsMsgDBView::Sort(sortType,sortOrder);
// the sort may have changed the number of rows
// before we restore the selection, tell the tree
// do this before we call restore selection
// this is safe when there is no selection.
rv = AdjustRowCount(rowCountBeforeSort, GetSize());
RestoreSelection(preservedKey, &preservedSelection);
if (mTree) mTree->Invalidate();
NS_ENSURE_SUCCESS(rv,rv);
return rv;
}
// if nothing selected, return an NS_ERROR
NS_IMETHODIMP
nsMsgSearchDBView::GetHdrForFirstSelectedMessage(nsIMsgDBHdr **hdr)
{
NS_ENSURE_ARG_POINTER(hdr);
PRInt32 index;
if (!mTreeSelection)
return NS_ERROR_NULL_POINTER;
nsresult rv = mTreeSelection->GetCurrentIndex(&index);
NS_ENSURE_SUCCESS(rv,rv);
rv = GetMsgHdrForViewIndex(index, hdr);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
}
nsresult
nsMsgSearchDBView::GetFolderFromMsgURI(const char *aMsgURI, nsIMsgFolder **aFolder)
{
nsCOMPtr <nsIMsgMessageService> msgMessageService;
nsresult rv = GetMessageServiceFromURI(aMsgURI, getter_AddRefs(msgMessageService));
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsIMsgDBHdr> msgHdr;
rv = msgMessageService->MessageURIToMsgHdr(aMsgURI, getter_AddRefs(msgHdr));
NS_ENSURE_SUCCESS(rv,rv);
return msgHdr->GetFolder(aFolder);
}