mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-11 02:10:17 +01:00
765 lines
22 KiB
C++
765 lines
22 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) 2000
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Howard Chu <hyc@symas.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 "nsMsgSearchCore.h"
|
|
#include "nsMsgSearchAdapter.h"
|
|
#include "nsMsgSearchBoolExpression.h"
|
|
#include "nsMsgSearchSession.h"
|
|
#include "nsMsgResultElement.h"
|
|
#include "nsMsgSearchTerm.h"
|
|
#include "nsMsgSearchScopeTerm.h"
|
|
#include "nsIMsgMessageService.h"
|
|
#include "nsMsgUtils.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsIMsgSearchNotify.h"
|
|
#include "nsIMsgMailSession.h"
|
|
#include "nsMsgBaseCID.h"
|
|
#include "nsMsgFolderFlags.h"
|
|
#include "nsMsgLocalSearch.h"
|
|
|
|
NS_IMPL_ISUPPORTS3(nsMsgSearchSession, nsIMsgSearchSession, nsIUrlListener, nsISupportsWeakReference)
|
|
|
|
nsMsgSearchSession::nsMsgSearchSession()
|
|
{
|
|
m_sortAttribute = nsMsgSearchAttrib::Sender;
|
|
m_idxRunningScope = 0;
|
|
m_urlQueueIndex = 0;
|
|
m_handlingError = PR_FALSE;
|
|
m_expressionTree = nsnull;
|
|
m_searchPaused = PR_FALSE;
|
|
NS_NewISupportsArray(getter_AddRefs(m_termList));
|
|
}
|
|
|
|
nsMsgSearchSession::~nsMsgSearchSession()
|
|
{
|
|
InterruptSearch();
|
|
delete m_expressionTree;
|
|
DestroyResultList ();
|
|
DestroyScopeList ();
|
|
DestroyTermList ();
|
|
}
|
|
|
|
/* [noscript] void AddSearchTerm (in nsMsgSearchAttribute attrib, in nsMsgSearchOperator op, in nsMsgSearchValue value, in boolean BooleanAND, in string arbitraryHeader); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::AddSearchTerm(nsMsgSearchAttribValue attrib,
|
|
nsMsgSearchOpValue op,
|
|
nsIMsgSearchValue * value,
|
|
PRBool BooleanANDp,
|
|
const char *arbitraryHeader)
|
|
{
|
|
// stupid gcc
|
|
nsMsgSearchBooleanOperator boolOp;
|
|
if (BooleanANDp)
|
|
boolOp = (nsMsgSearchBooleanOperator)nsMsgSearchBooleanOp::BooleanAND;
|
|
else
|
|
boolOp = (nsMsgSearchBooleanOperator)nsMsgSearchBooleanOp::BooleanOR;
|
|
nsMsgSearchTerm *pTerm = new nsMsgSearchTerm (attrib, op, value,
|
|
boolOp, arbitraryHeader);
|
|
if (nsnull == pTerm)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
m_termList->AppendElement (pTerm);
|
|
// force the expression tree to rebuild whenever we change the terms
|
|
delete m_expressionTree;
|
|
m_expressionTree = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::AppendTerm(nsIMsgSearchTerm *aTerm)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aTerm);
|
|
NS_ENSURE_TRUE(m_termList, NS_ERROR_NOT_INITIALIZED);
|
|
delete m_expressionTree;
|
|
m_expressionTree = nsnull;
|
|
return m_termList->AppendElement(aTerm);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::GetSearchTerms(nsISupportsArray **aResult)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
*aResult = m_termList;
|
|
NS_ADDREF(*aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::CreateTerm(nsIMsgSearchTerm **aResult)
|
|
{
|
|
nsMsgSearchTerm *term = new nsMsgSearchTerm;
|
|
NS_ENSURE_TRUE(term, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
*aResult = NS_STATIC_CAST(nsIMsgSearchTerm*,term);
|
|
NS_ADDREF(*aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void RegisterListener (in nsIMsgSearchNotify listener); */
|
|
NS_IMETHODIMP nsMsgSearchSession::RegisterListener(nsIMsgSearchNotify *listener)
|
|
{
|
|
nsresult ret = NS_OK;
|
|
if (!m_listenerList)
|
|
ret = NS_NewISupportsArray(getter_AddRefs(m_listenerList));
|
|
|
|
if (NS_SUCCEEDED(ret) && m_listenerList)
|
|
m_listenerList->AppendElement(listener);
|
|
return ret;
|
|
}
|
|
|
|
/* void UnregisterListener (in nsIMsgSearchNotify listener); */
|
|
NS_IMETHODIMP nsMsgSearchSession::UnregisterListener(nsIMsgSearchNotify *listener)
|
|
{
|
|
if (m_listenerList)
|
|
m_listenerList->RemoveElement(listener);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute long numSearchTerms; */
|
|
NS_IMETHODIMP nsMsgSearchSession::GetNumSearchTerms(PRUint32 *aNumSearchTerms)
|
|
{
|
|
NS_ENSURE_ARG(aNumSearchTerms);
|
|
return m_termList->Count(aNumSearchTerms);
|
|
}
|
|
|
|
/* [noscript] void GetNthSearchTerm (in long whichTerm, in nsMsgSearchAttribute attrib, in nsMsgSearchOperator op, in nsMsgSearchValue value); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::GetNthSearchTerm(PRInt32 whichTerm,
|
|
nsMsgSearchAttribValue attrib,
|
|
nsMsgSearchOpValue op,
|
|
nsIMsgSearchValue * value)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* long CountSearchScopes (); */
|
|
NS_IMETHODIMP nsMsgSearchSession::CountSearchScopes(PRInt32 *_retval)
|
|
{
|
|
NS_ENSURE_ARG(_retval);
|
|
*_retval = m_scopeList.Count();
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void GetNthSearchScope (in long which, out nsMsgSearchScope scopeId, out nsIMsgFolder folder); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::GetNthSearchScope(PRInt32 which,
|
|
nsMsgSearchScopeValue *scopeId,
|
|
nsIMsgFolder **folder)
|
|
{
|
|
// argh, does this do an addref?
|
|
nsMsgSearchScopeTerm *scopeTerm = (nsMsgSearchScopeTerm *) m_scopeList.SafeElementAt(which);
|
|
if (!scopeTerm) return NS_ERROR_INVALID_ARG;
|
|
*scopeId = scopeTerm->m_attribute;
|
|
*folder = scopeTerm->m_folder;
|
|
NS_IF_ADDREF(*folder);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void AddScopeTerm (in nsMsgSearchScopeValue scope, in nsIMsgFolder folder); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::AddScopeTerm(nsMsgSearchScopeValue scope,
|
|
nsIMsgFolder *folder)
|
|
{
|
|
if (scope != nsMsgSearchScope::allSearchableGroups)
|
|
{
|
|
NS_ASSERTION(folder, "need folder if not searching all groups");
|
|
if (!folder)
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
nsMsgSearchScopeTerm *pScopeTerm = new nsMsgSearchScopeTerm(this, scope, folder);
|
|
if (!pScopeTerm)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
m_scopeList.AppendElement(pScopeTerm);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::AddDirectoryScopeTerm(nsMsgSearchScopeValue scope)
|
|
{
|
|
nsMsgSearchScopeTerm *pScopeTerm = new nsMsgSearchScopeTerm(this, scope, nsnull);
|
|
if (!pScopeTerm)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
m_scopeList.AppendElement(pScopeTerm);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::ClearScopes()
|
|
{
|
|
DestroyScopeList();
|
|
return NS_OK;
|
|
}
|
|
|
|
/* [noscript] boolean ScopeUsesCustomHeaders (in nsMsgSearchScope scope, in voidStar selection, in boolean forFilters); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::ScopeUsesCustomHeaders(nsMsgSearchScopeValue scope,
|
|
void * selection,
|
|
PRBool forFilters,
|
|
PRBool *_retval)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* boolean IsStringAttribute (in nsMsgSearchAttribute attrib); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::IsStringAttribute(nsMsgSearchAttribValue attrib,
|
|
PRBool *_retval)
|
|
{
|
|
NS_ENSURE_ARG(_retval);
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void AddAllScopes (in nsMsgSearchScope attrib); */
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::AddAllScopes(nsMsgSearchScopeValue attrib)
|
|
{
|
|
// don't think this is needed.
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* void Search (); */
|
|
NS_IMETHODIMP nsMsgSearchSession::Search(nsIMsgWindow *aWindow)
|
|
{
|
|
nsresult err = Initialize ();
|
|
NS_ENSURE_SUCCESS(err,err);
|
|
if (m_listenerList) {
|
|
PRUint32 count;
|
|
m_listenerList->Count(&count);
|
|
for (PRUint32 i=0; i<count;i++) {
|
|
nsCOMPtr<nsIMsgSearchNotify> listener;
|
|
m_listenerList->QueryElementAt(i, NS_GET_IID(nsIMsgSearchNotify),
|
|
(void **)getter_AddRefs(listener));
|
|
if (listener)
|
|
listener->OnNewSearch();
|
|
}
|
|
}
|
|
m_window = aWindow;
|
|
if (NS_SUCCEEDED(err))
|
|
err = BeginSearching ();
|
|
return err;
|
|
}
|
|
|
|
/* void InterruptSearch (); */
|
|
NS_IMETHODIMP nsMsgSearchSession::InterruptSearch()
|
|
{
|
|
if (m_window)
|
|
{
|
|
EnableFolderNotifications(PR_TRUE);
|
|
if (m_idxRunningScope < m_scopeList.Count())
|
|
m_window->StopUrls();
|
|
|
|
while (m_idxRunningScope < m_scopeList.Count())
|
|
{
|
|
ReleaseFolderDBRef();
|
|
m_idxRunningScope++;
|
|
}
|
|
//m_idxRunningScope = m_scopeList.Count() so it will make us not run another url
|
|
}
|
|
if (m_backgroundTimer)
|
|
{
|
|
m_backgroundTimer->Cancel();
|
|
NotifyListenersDone(NS_OK); // ### is there a cancelled status?
|
|
|
|
m_backgroundTimer = nsnull;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::PauseSearch()
|
|
{
|
|
if (m_backgroundTimer)
|
|
{
|
|
m_backgroundTimer->Cancel();
|
|
m_searchPaused = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
else
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::ResumeSearch()
|
|
{
|
|
if (m_searchPaused)
|
|
{
|
|
m_searchPaused = PR_FALSE;
|
|
return StartTimer();
|
|
}
|
|
else
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* [noscript] readonly attribute voidStar searchParam; */
|
|
NS_IMETHODIMP nsMsgSearchSession::GetSearchParam(void * *aSearchParam)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* readonly attribute nsMsgSearchType searchType; */
|
|
NS_IMETHODIMP nsMsgSearchSession::GetSearchType(nsMsgSearchType * *aSearchType)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* [noscript] nsMsgSearchType SetSearchParam (in nsMsgSearchType type, in voidStar param); */
|
|
NS_IMETHODIMP nsMsgSearchSession::SetSearchParam(nsMsgSearchType *type, void * param, nsMsgSearchType **_retval)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* readonly attribute long numResults; */
|
|
NS_IMETHODIMP nsMsgSearchSession::GetNumResults(PRInt32 *aNumResults)
|
|
{
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::SetWindow(nsIMsgWindow *aWindow)
|
|
{
|
|
m_window = aWindow;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::GetWindow(nsIMsgWindow **aWindowPtr)
|
|
{
|
|
NS_ENSURE_ARG(aWindowPtr);
|
|
*aWindowPtr = m_window;
|
|
NS_IF_ADDREF(*aWindowPtr);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void OnStartRunningUrl (in nsIURI url); */
|
|
NS_IMETHODIMP nsMsgSearchSession::OnStartRunningUrl(nsIURI *url)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void OnStopRunningUrl (in nsIURI url, in nsresult aExitCode); */
|
|
NS_IMETHODIMP nsMsgSearchSession::OnStopRunningUrl(nsIURI *url, nsresult aExitCode)
|
|
{
|
|
nsCOMPtr <nsIMsgSearchAdapter> runningAdapter;
|
|
|
|
nsresult rv = GetRunningAdapter (getter_AddRefs(runningAdapter));
|
|
// tell the current adapter that the current url has run.
|
|
if (NS_SUCCEEDED(rv) && runningAdapter)
|
|
{
|
|
runningAdapter->CurrentUrlDone(aExitCode);
|
|
EnableFolderNotifications(PR_TRUE);
|
|
ReleaseFolderDBRef();
|
|
}
|
|
m_idxRunningScope++;
|
|
if (++m_urlQueueIndex < m_urlQueue.Count())
|
|
GetNextUrl();
|
|
else if (m_idxRunningScope < m_scopeList.Count())
|
|
DoNextSearch();
|
|
else
|
|
NotifyListenersDone(aExitCode);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsMsgSearchSession::Initialize()
|
|
{
|
|
// Loop over scope terms, initializing an adapter per term. This
|
|
// architecture is necessitated by two things:
|
|
// 1. There might be more than one kind of adapter per if online
|
|
// *and* offline mail mail folders are selected, or if newsgroups
|
|
// belonging to Dredd *and* INN are selected
|
|
// 2. Most of the protocols are only capable of searching one scope at a
|
|
// time, so we'll do each scope in a separate adapter on the client
|
|
|
|
nsMsgSearchScopeTerm *scopeTerm = nsnull;
|
|
nsresult err = NS_OK;
|
|
|
|
PRUint32 numTerms;
|
|
m_termList->Count(&numTerms);
|
|
// Ensure that the FE has added scopes and terms to this search
|
|
NS_ASSERTION(numTerms > 0, "no terms to search!");
|
|
if (numTerms == 0)
|
|
return NS_MSG_ERROR_NO_SEARCH_VALUES;
|
|
|
|
// if we don't have any search scopes to search, return that code.
|
|
if (m_scopeList.Count() == 0)
|
|
return NS_MSG_ERROR_INVALID_SEARCH_SCOPE;
|
|
|
|
m_urlQueue.Clear(); // clear out old urls, if any.
|
|
m_idxRunningScope = 0;
|
|
m_urlQueueIndex = 0;
|
|
|
|
// If this term list (loosely specified here by the first term) should be
|
|
// scheduled in parallel, build up a list of scopes to do the round-robin scheduling
|
|
for (int i = 0; i < m_scopeList.Count() && NS_SUCCEEDED(err); i++)
|
|
{
|
|
scopeTerm = m_scopeList.ElementAt(i);
|
|
// NS_ASSERTION(scopeTerm->IsValid());
|
|
|
|
err = scopeTerm->InitializeAdapter (m_termList);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::BeginSearching()
|
|
{
|
|
// Here's a sloppy way to start the URL, but I don't really have time to
|
|
// unify the scheduling mechanisms. If the first scope is a newsgroup, and
|
|
// it's not Dredd-capable, we build the URL queue. All other searches can be
|
|
// done with one URL
|
|
|
|
if (m_window)
|
|
m_window->SetStopped(PR_FALSE);
|
|
return DoNextSearch();
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::DoNextSearch()
|
|
{
|
|
nsMsgSearchScopeTerm *scope = m_scopeList.ElementAt(m_idxRunningScope);
|
|
if (scope->m_attribute == nsMsgSearchScope::onlineMail ||
|
|
(scope->m_attribute == nsMsgSearchScope::news && scope->m_searchServer))
|
|
return BuildUrlQueue ();
|
|
else
|
|
return SearchWOUrls();
|
|
}
|
|
|
|
|
|
nsresult nsMsgSearchSession::BuildUrlQueue ()
|
|
{
|
|
PRInt32 i;
|
|
for (i = m_idxRunningScope; i < m_scopeList.Count(); i++)
|
|
{
|
|
nsMsgSearchScopeTerm *scope = m_scopeList.ElementAt(i);
|
|
if (scope->m_attribute != nsMsgSearchScope::onlineMail &&
|
|
(scope->m_attribute != nsMsgSearchScope::news && scope->m_searchServer))
|
|
break;
|
|
nsCOMPtr <nsIMsgSearchAdapter> adapter = do_QueryInterface((m_scopeList.ElementAt(i))->m_adapter);
|
|
nsXPIDLCString url;
|
|
if (adapter)
|
|
{
|
|
adapter->GetEncoding(getter_Copies(url));
|
|
AddUrl (url);
|
|
}
|
|
}
|
|
|
|
if (i > 0)
|
|
GetNextUrl();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult nsMsgSearchSession::GetNextUrl()
|
|
{
|
|
nsCString nextUrl;
|
|
nsCOMPtr <nsIMsgMessageService> msgService;
|
|
|
|
|
|
PRBool stopped = PR_FALSE;
|
|
|
|
if (m_window)
|
|
m_window->GetStopped(&stopped);
|
|
if (stopped)
|
|
return NS_OK;
|
|
|
|
m_urlQueue.CStringAt(m_urlQueueIndex, nextUrl);
|
|
nsMsgSearchScopeTerm *currentTerm = GetRunningScope();
|
|
EnableFolderNotifications(PR_FALSE);
|
|
nsCOMPtr <nsIMsgFolder> folder = currentTerm->m_folder;
|
|
if (folder)
|
|
{
|
|
nsXPIDLCString folderUri;
|
|
folder->GetURI(getter_Copies(folderUri));
|
|
nsresult rv = GetMessageServiceFromURI(folderUri.get(), getter_AddRefs(msgService));
|
|
|
|
if (NS_SUCCEEDED(rv) && msgService && currentTerm)
|
|
msgService->Search(this, m_window, currentTerm->m_folder, nextUrl.get());
|
|
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::AddUrl(const char *url)
|
|
{
|
|
nsCString urlCString(url);
|
|
m_urlQueue.AppendCString(urlCString);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* static */ void nsMsgSearchSession::TimerCallback(nsITimer *aTimer, void *aClosure)
|
|
{
|
|
nsMsgSearchSession *searchSession = (nsMsgSearchSession *) aClosure;
|
|
PRBool done;
|
|
PRBool stopped = PR_FALSE;
|
|
|
|
searchSession->TimeSlice(&done);
|
|
if (searchSession->m_window)
|
|
searchSession->m_window->GetStopped(&stopped);
|
|
|
|
if (done || stopped)
|
|
{
|
|
aTimer->Cancel();
|
|
searchSession->m_backgroundTimer = nsnull;
|
|
if (searchSession->m_idxRunningScope < searchSession->m_scopeList.Count())
|
|
searchSession->DoNextSearch();
|
|
else
|
|
searchSession->NotifyListenersDone(NS_OK);
|
|
}
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::StartTimer()
|
|
{
|
|
nsresult err;
|
|
PRBool done;
|
|
|
|
m_backgroundTimer = do_CreateInstance("@mozilla.org/timer;1", &err);
|
|
m_backgroundTimer->InitWithFuncCallback(TimerCallback, (void *) this, 0,
|
|
nsITimer::TYPE_REPEATING_SLACK);
|
|
// ### start meteors?
|
|
return TimeSlice(&done);
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::SearchWOUrls ()
|
|
{
|
|
EnableFolderNotifications(PR_FALSE);
|
|
return StartTimer();
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::GetRunningAdapter (nsIMsgSearchAdapter **aSearchAdapter)
|
|
{
|
|
NS_ENSURE_ARG(aSearchAdapter);
|
|
nsMsgSearchScopeTerm *scope = GetRunningScope();
|
|
if (scope)
|
|
{
|
|
NS_ADDREF(*aSearchAdapter = scope->m_adapter);
|
|
return NS_OK;
|
|
}
|
|
*aSearchAdapter = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::AddSearchHit(nsIMsgDBHdr *header, nsIMsgFolder *folder)
|
|
{
|
|
if (m_listenerList)
|
|
{
|
|
PRUint32 count;
|
|
m_listenerList->Count(&count);
|
|
for (PRUint32 i = 0; i < count; i++)
|
|
{
|
|
nsCOMPtr<nsIMsgSearchNotify> pListener;
|
|
m_listenerList->QueryElementAt(i, NS_GET_IID(nsIMsgSearchNotify),
|
|
(void **)getter_AddRefs(pListener));
|
|
if (pListener)
|
|
pListener->OnSearchHit(header, folder);
|
|
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::NotifyListenersDone(nsresult status)
|
|
{
|
|
if (m_listenerList)
|
|
{
|
|
PRUint32 count;
|
|
m_listenerList->Count(&count);
|
|
for (PRUint32 i = 0; i < count; i++)
|
|
{
|
|
nsCOMPtr<nsIMsgSearchNotify> pListener;
|
|
m_listenerList->QueryElementAt(i, NS_GET_IID(nsIMsgSearchNotify),
|
|
(void **)getter_AddRefs(pListener));
|
|
if (pListener)
|
|
pListener->OnSearchDone(status);
|
|
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP nsMsgSearchSession::AddResultElement (nsMsgResultElement *element)
|
|
{
|
|
NS_ASSERTION(element, "no null elements");
|
|
|
|
m_resultList.AppendElement (element);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
void nsMsgSearchSession::DestroyResultList ()
|
|
{
|
|
nsMsgResultElement *result = nsnull;
|
|
for (int i = 0; i < m_resultList.Count(); i++)
|
|
{
|
|
result = m_resultList.ElementAt(i);
|
|
// NS_ASSERTION (result->IsValid(), "invalid search result");
|
|
delete result;
|
|
}
|
|
m_resultList.Clear();
|
|
}
|
|
|
|
|
|
void nsMsgSearchSession::DestroyScopeList()
|
|
{
|
|
nsMsgSearchScopeTerm *scope = NULL;
|
|
PRInt32 count = m_scopeList.Count();
|
|
|
|
for (PRInt32 i = count-1; i >= 0; i--)
|
|
{
|
|
scope = m_scopeList.ElementAt(i);
|
|
// NS_ASSERTION (scope->IsValid(), "invalid search scope");
|
|
delete scope;
|
|
}
|
|
m_scopeList.Clear();
|
|
}
|
|
|
|
|
|
void nsMsgSearchSession::DestroyTermList ()
|
|
{
|
|
m_termList->Clear();
|
|
}
|
|
|
|
nsMsgSearchScopeTerm *nsMsgSearchSession::GetRunningScope()
|
|
{
|
|
return (nsMsgSearchScopeTerm *) m_scopeList.SafeElementAt(m_idxRunningScope);
|
|
}
|
|
|
|
nsresult nsMsgSearchSession::TimeSlice (PRBool *aDone)
|
|
{
|
|
// we only do serial for now.
|
|
return TimeSliceSerial(aDone);
|
|
}
|
|
|
|
void nsMsgSearchSession::ReleaseFolderDBRef()
|
|
{
|
|
nsMsgSearchScopeTerm *scope = GetRunningScope();
|
|
if (scope)
|
|
{
|
|
PRBool isOpen =PR_FALSE;
|
|
PRUint32 flags;
|
|
nsCOMPtr <nsIMsgFolder> folder;
|
|
scope->GetFolder(getter_AddRefs(folder));
|
|
nsCOMPtr <nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID);
|
|
if (mailSession && folder)
|
|
{
|
|
mailSession->IsFolderOpenInWindow(folder, &isOpen);
|
|
folder->GetFlags(&flags);
|
|
|
|
/*we don't null out the db reference for inbox because inbox is like the "main" folder
|
|
and performance outweighs footprint */
|
|
if (!isOpen && !(MSG_FOLDER_FLAG_INBOX & flags))
|
|
folder->SetMsgDatabase(nsnull);
|
|
}
|
|
}
|
|
}
|
|
nsresult nsMsgSearchSession::TimeSliceSerial (PRBool *aDone)
|
|
{
|
|
// This version of TimeSlice runs each scope term one at a time, and waits until one
|
|
// scope term is finished before starting another one. When we're searching the local
|
|
// disk, this is the fastest way to do it.
|
|
|
|
NS_ENSURE_ARG(aDone);
|
|
nsresult rv = NS_OK;
|
|
nsMsgSearchScopeTerm *scope = GetRunningScope();
|
|
if (scope)
|
|
{
|
|
rv = scope->TimeSlice (aDone);
|
|
if (NS_FAILED(rv))
|
|
*aDone = PR_TRUE;
|
|
if (*aDone || NS_FAILED(rv))
|
|
{
|
|
EnableFolderNotifications(PR_TRUE);
|
|
ReleaseFolderDBRef();
|
|
m_idxRunningScope++;
|
|
EnableFolderNotifications(PR_FALSE);
|
|
// check if the next scope is an online search; if so,
|
|
// set *aDone to true so that we'll try to run the next
|
|
// search in TimerCallback.
|
|
scope = GetRunningScope();
|
|
if (scope && (scope->m_attribute == nsMsgSearchScope::onlineMail ||
|
|
(scope->m_attribute == nsMsgSearchScope::news && scope->m_searchServer)))
|
|
{
|
|
*aDone = PR_TRUE;
|
|
return rv;
|
|
}
|
|
|
|
}
|
|
*aDone = PR_FALSE;
|
|
return rv;
|
|
}
|
|
else
|
|
{
|
|
*aDone = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsMsgSearchSession::EnableFolderNotifications(PRBool aEnable)
|
|
{
|
|
nsMsgSearchScopeTerm *scope = GetRunningScope();
|
|
if (scope)
|
|
{
|
|
nsCOMPtr<nsIMsgFolder> folder;
|
|
scope->GetFolder(getter_AddRefs(folder));
|
|
if (folder) //enable msg count notifications
|
|
folder->EnableNotifications(nsIMsgFolder::allMessageCountNotifications, aEnable, PR_FALSE);
|
|
}
|
|
}
|
|
|
|
//this method is used for adding new hdrs to quick search view
|
|
NS_IMETHODIMP
|
|
nsMsgSearchSession::MatchHdr(nsIMsgDBHdr *aMsgHdr, nsIMsgDatabase *aDatabase, PRBool *aResult)
|
|
{
|
|
nsMsgSearchScopeTerm *scope = (nsMsgSearchScopeTerm *)m_scopeList.SafeElementAt(0);
|
|
if (scope)
|
|
{
|
|
if (!scope->m_adapter)
|
|
scope->InitializeAdapter(m_termList);
|
|
if (scope->m_adapter)
|
|
{
|
|
nsXPIDLString nullCharset, folderCharset;
|
|
scope->m_adapter->GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset));
|
|
NS_ConvertUCS2toUTF8 charset(folderCharset.get());
|
|
nsMsgSearchOfflineMail::MatchTermsForSearch(aMsgHdr, m_termList, charset.get(), scope, aDatabase, &m_expressionTree, aResult);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|