Back to index

lightning-sunbird  0.9+nobinonly
nsMsgSearchSession.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Howard Chu <hyc@symas.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "msgCore.h"
00040 #include "nsMsgSearchCore.h"
00041 #include "nsMsgSearchAdapter.h"
00042 #include "nsMsgSearchBoolExpression.h"
00043 #include "nsMsgSearchSession.h"
00044 #include "nsMsgResultElement.h"
00045 #include "nsMsgSearchTerm.h"
00046 #include "nsMsgSearchScopeTerm.h"
00047 #include "nsIMsgMessageService.h"
00048 #include "nsMsgUtils.h"
00049 #include "nsXPIDLString.h"
00050 #include "nsIMsgSearchNotify.h"
00051 #include "nsIMsgMailSession.h"
00052 #include "nsMsgBaseCID.h"
00053 #include "nsMsgFolderFlags.h"
00054 #include "nsMsgLocalSearch.h"
00055 
00056 NS_IMPL_ISUPPORTS3(nsMsgSearchSession, nsIMsgSearchSession, nsIUrlListener, nsISupportsWeakReference)
00057 
00058 nsMsgSearchSession::nsMsgSearchSession()
00059 {
00060   m_sortAttribute = nsMsgSearchAttrib::Sender;
00061   m_idxRunningScope = 0; 
00062   m_urlQueueIndex = 0;
00063   m_handlingError = PR_FALSE;
00064   m_expressionTree = nsnull;
00065   m_searchPaused = PR_FALSE;
00066   NS_NewISupportsArray(getter_AddRefs(m_termList));
00067 }
00068 
00069 nsMsgSearchSession::~nsMsgSearchSession()
00070 {
00071   InterruptSearch();
00072   delete m_expressionTree;
00073   DestroyResultList ();
00074   DestroyScopeList ();
00075   DestroyTermList ();
00076 }
00077 
00078 /* [noscript] void AddSearchTerm (in nsMsgSearchAttribute attrib, in nsMsgSearchOperator op, in nsMsgSearchValue value, in boolean BooleanAND, in string arbitraryHeader); */
00079 NS_IMETHODIMP
00080 nsMsgSearchSession::AddSearchTerm(nsMsgSearchAttribValue attrib,
00081                                   nsMsgSearchOpValue op,
00082                                   nsIMsgSearchValue * value,
00083                                   PRBool BooleanANDp,
00084                                   const char *arbitraryHeader)
00085 {
00086     // stupid gcc
00087     nsMsgSearchBooleanOperator boolOp;
00088     if (BooleanANDp)
00089         boolOp = (nsMsgSearchBooleanOperator)nsMsgSearchBooleanOp::BooleanAND;
00090     else
00091         boolOp = (nsMsgSearchBooleanOperator)nsMsgSearchBooleanOp::BooleanOR;
00092        nsMsgSearchTerm *pTerm = new nsMsgSearchTerm (attrib, op, value,
00093                                                   boolOp, arbitraryHeader);
00094        if (nsnull == pTerm)
00095               return NS_ERROR_OUT_OF_MEMORY;
00096        m_termList->AppendElement (pTerm);
00097         // force the expression tree to rebuild whenever we change the terms
00098         delete m_expressionTree;
00099         m_expressionTree = nsnull;
00100        return NS_OK;
00101 }
00102 
00103 NS_IMETHODIMP
00104 nsMsgSearchSession::AppendTerm(nsIMsgSearchTerm *aTerm)
00105 {
00106     NS_ENSURE_ARG_POINTER(aTerm);
00107     NS_ENSURE_TRUE(m_termList, NS_ERROR_NOT_INITIALIZED);
00108     delete m_expressionTree;
00109     m_expressionTree = nsnull;
00110     return m_termList->AppendElement(aTerm);
00111 }
00112 
00113 NS_IMETHODIMP
00114 nsMsgSearchSession::GetSearchTerms(nsISupportsArray **aResult)
00115 {
00116     NS_ENSURE_ARG_POINTER(aResult);
00117     *aResult = m_termList;
00118     NS_ADDREF(*aResult);
00119     return NS_OK;
00120 }
00121 
00122 NS_IMETHODIMP
00123 nsMsgSearchSession::CreateTerm(nsIMsgSearchTerm **aResult)
00124 {
00125     nsMsgSearchTerm *term = new nsMsgSearchTerm;
00126     NS_ENSURE_TRUE(term, NS_ERROR_OUT_OF_MEMORY);
00127     
00128     *aResult = NS_STATIC_CAST(nsIMsgSearchTerm*,term);
00129     NS_ADDREF(*aResult);
00130     return NS_OK;
00131 }
00132 
00133 /* void RegisterListener (in nsIMsgSearchNotify listener); */
00134 NS_IMETHODIMP nsMsgSearchSession::RegisterListener(nsIMsgSearchNotify *listener)
00135 {
00136   nsresult ret = NS_OK;
00137   if (!m_listenerList)
00138     ret = NS_NewISupportsArray(getter_AddRefs(m_listenerList));
00139 
00140   if (NS_SUCCEEDED(ret) && m_listenerList)
00141     m_listenerList->AppendElement(listener);
00142   return ret;
00143 }
00144 
00145 /* void UnregisterListener (in nsIMsgSearchNotify listener); */
00146 NS_IMETHODIMP nsMsgSearchSession::UnregisterListener(nsIMsgSearchNotify *listener)
00147 {
00148   if (m_listenerList)
00149     m_listenerList->RemoveElement(listener);
00150   return NS_OK;
00151 }
00152 
00153 /* readonly attribute long numSearchTerms; */
00154 NS_IMETHODIMP nsMsgSearchSession::GetNumSearchTerms(PRUint32 *aNumSearchTerms)
00155 {
00156   NS_ENSURE_ARG(aNumSearchTerms);
00157   return m_termList->Count(aNumSearchTerms);
00158 }
00159 
00160 /* [noscript] void GetNthSearchTerm (in long whichTerm, in nsMsgSearchAttribute attrib, in nsMsgSearchOperator op, in nsMsgSearchValue value); */
00161 NS_IMETHODIMP
00162 nsMsgSearchSession::GetNthSearchTerm(PRInt32 whichTerm,
00163                                      nsMsgSearchAttribValue attrib,
00164                                      nsMsgSearchOpValue op,
00165                                      nsIMsgSearchValue * value)
00166 {
00167     return NS_ERROR_NOT_IMPLEMENTED;
00168 }
00169 
00170 /* long CountSearchScopes (); */
00171 NS_IMETHODIMP nsMsgSearchSession::CountSearchScopes(PRInt32 *_retval)
00172 {
00173   NS_ENSURE_ARG(_retval);
00174   *_retval = m_scopeList.Count();
00175   return NS_OK;
00176 }
00177 
00178   /* void GetNthSearchScope (in long which, out nsMsgSearchScope scopeId, out nsIMsgFolder folder); */
00179 NS_IMETHODIMP
00180 nsMsgSearchSession::GetNthSearchScope(PRInt32 which,
00181                                       nsMsgSearchScopeValue *scopeId,
00182                                       nsIMsgFolder **folder)
00183 {
00184   // argh, does this do an addref?
00185        nsMsgSearchScopeTerm *scopeTerm = (nsMsgSearchScopeTerm *) m_scopeList.SafeElementAt(which);
00186     if (!scopeTerm) return NS_ERROR_INVALID_ARG;
00187        *scopeId = scopeTerm->m_attribute;
00188        *folder = scopeTerm->m_folder;
00189   NS_IF_ADDREF(*folder);
00190   return NS_OK;
00191 }
00192 
00193 /* void AddScopeTerm (in nsMsgSearchScopeValue scope, in nsIMsgFolder folder); */
00194 NS_IMETHODIMP
00195 nsMsgSearchSession::AddScopeTerm(nsMsgSearchScopeValue scope,
00196                                  nsIMsgFolder *folder)
00197 {
00198   if (scope != nsMsgSearchScope::allSearchableGroups)
00199   {
00200     NS_ASSERTION(folder, "need folder if not searching all groups");
00201     if (!folder)
00202       return NS_ERROR_NULL_POINTER;
00203   }
00204 
00205   nsMsgSearchScopeTerm *pScopeTerm = new nsMsgSearchScopeTerm(this, scope, folder);
00206   if (!pScopeTerm)
00207     return NS_ERROR_OUT_OF_MEMORY;
00208 
00209   m_scopeList.AppendElement(pScopeTerm);
00210   return NS_OK;
00211 }
00212 
00213 NS_IMETHODIMP
00214 nsMsgSearchSession::AddDirectoryScopeTerm(nsMsgSearchScopeValue scope)
00215 {
00216        nsMsgSearchScopeTerm *pScopeTerm = new nsMsgSearchScopeTerm(this, scope, nsnull);
00217   if (!pScopeTerm)
00218     return NS_ERROR_OUT_OF_MEMORY;
00219 
00220   m_scopeList.AppendElement(pScopeTerm);
00221   return NS_OK;
00222 }
00223 
00224 NS_IMETHODIMP nsMsgSearchSession::ClearScopes()
00225 {
00226     DestroyScopeList();
00227     return NS_OK;
00228 }
00229 
00230 /* [noscript] boolean ScopeUsesCustomHeaders (in nsMsgSearchScope scope, in voidStar selection, in boolean forFilters); */
00231 NS_IMETHODIMP
00232 nsMsgSearchSession::ScopeUsesCustomHeaders(nsMsgSearchScopeValue scope,
00233                                            void * selection,
00234                                            PRBool forFilters,
00235                                            PRBool *_retval)
00236 {
00237     return NS_ERROR_NOT_IMPLEMENTED;
00238 }
00239 
00240 /* boolean IsStringAttribute (in nsMsgSearchAttribute attrib); */
00241 NS_IMETHODIMP
00242 nsMsgSearchSession::IsStringAttribute(nsMsgSearchAttribValue attrib,
00243                                       PRBool *_retval)
00244 {
00245   NS_ENSURE_ARG(_retval);
00246     return NS_ERROR_NOT_IMPLEMENTED;
00247 }
00248 
00249 /* void AddAllScopes (in nsMsgSearchScope attrib); */
00250 NS_IMETHODIMP
00251 nsMsgSearchSession::AddAllScopes(nsMsgSearchScopeValue attrib)
00252 {
00253   // don't think this is needed.
00254     return NS_ERROR_NOT_IMPLEMENTED;
00255 }
00256 
00257 /* void Search (); */
00258 NS_IMETHODIMP nsMsgSearchSession::Search(nsIMsgWindow *aWindow)
00259 {
00260     nsresult err = Initialize ();
00261     NS_ENSURE_SUCCESS(err,err);
00262     if (m_listenerList) {
00263         PRUint32 count;
00264         m_listenerList->Count(&count);
00265         for (PRUint32 i=0; i<count;i++) {
00266             nsCOMPtr<nsIMsgSearchNotify> listener;
00267             m_listenerList->QueryElementAt(i, NS_GET_IID(nsIMsgSearchNotify),
00268                                            (void **)getter_AddRefs(listener));
00269             if (listener)
00270                 listener->OnNewSearch();
00271         }
00272     }
00273   m_window = aWindow;
00274   if (NS_SUCCEEDED(err))
00275     err = BeginSearching ();
00276   return err;
00277 }
00278 
00279 /* void InterruptSearch (); */
00280 NS_IMETHODIMP nsMsgSearchSession::InterruptSearch()
00281 {
00282   if (m_window)
00283   {
00284     EnableFolderNotifications(PR_TRUE);
00285     if (m_idxRunningScope < m_scopeList.Count())
00286           m_window->StopUrls();
00287 
00288     while (m_idxRunningScope < m_scopeList.Count())
00289     {
00290       ReleaseFolderDBRef();
00291       m_idxRunningScope++;
00292     }
00293     //m_idxRunningScope = m_scopeList.Count() so it will make us not run another url
00294   }
00295   if (m_backgroundTimer)
00296   {
00297     m_backgroundTimer->Cancel();
00298     NotifyListenersDone(NS_OK); // ### is there a cancelled status?
00299 
00300     m_backgroundTimer = nsnull;
00301   }
00302   return NS_OK;
00303 }
00304 
00305 NS_IMETHODIMP nsMsgSearchSession::PauseSearch()
00306 {
00307   if (m_backgroundTimer)
00308   {
00309     m_backgroundTimer->Cancel();
00310     m_searchPaused = PR_TRUE;
00311     return NS_OK;
00312   }
00313   else
00314     return NS_ERROR_FAILURE;
00315 }
00316 
00317 NS_IMETHODIMP nsMsgSearchSession::ResumeSearch()
00318 {
00319   if (m_searchPaused)
00320   {
00321     m_searchPaused = PR_FALSE;
00322     return StartTimer();
00323   }
00324   else
00325     return NS_ERROR_FAILURE;
00326 }
00327 
00328 /* [noscript] readonly attribute voidStar searchParam; */
00329 NS_IMETHODIMP nsMsgSearchSession::GetSearchParam(void * *aSearchParam)
00330 {
00331     return NS_ERROR_NOT_IMPLEMENTED;
00332 }
00333 
00334 /* readonly attribute nsMsgSearchType searchType; */
00335 NS_IMETHODIMP nsMsgSearchSession::GetSearchType(nsMsgSearchType * *aSearchType)
00336 {
00337     return NS_ERROR_NOT_IMPLEMENTED;
00338 }
00339 
00340 /* [noscript] nsMsgSearchType SetSearchParam (in nsMsgSearchType type, in voidStar param); */
00341 NS_IMETHODIMP nsMsgSearchSession::SetSearchParam(nsMsgSearchType *type, void * param, nsMsgSearchType **_retval)
00342 {
00343     return NS_ERROR_NOT_IMPLEMENTED;
00344 }
00345 
00346 /* readonly attribute long numResults; */
00347 NS_IMETHODIMP nsMsgSearchSession::GetNumResults(PRInt32 *aNumResults)
00348 {
00349     return NS_ERROR_NOT_IMPLEMENTED;
00350 }
00351 
00352 NS_IMETHODIMP nsMsgSearchSession::SetWindow(nsIMsgWindow *aWindow)
00353 {
00354   m_window = aWindow;
00355   return NS_OK;
00356 }
00357 
00358 NS_IMETHODIMP nsMsgSearchSession::GetWindow(nsIMsgWindow **aWindowPtr)
00359 {
00360   NS_ENSURE_ARG(aWindowPtr);
00361   *aWindowPtr = m_window;
00362   NS_IF_ADDREF(*aWindowPtr);
00363   return NS_OK;
00364 }
00365 
00366 /* void OnStartRunningUrl (in nsIURI url); */
00367 NS_IMETHODIMP nsMsgSearchSession::OnStartRunningUrl(nsIURI *url)
00368 {
00369     return NS_OK;
00370 }
00371 
00372 /* void OnStopRunningUrl (in nsIURI url, in nsresult aExitCode); */
00373 NS_IMETHODIMP nsMsgSearchSession::OnStopRunningUrl(nsIURI *url, nsresult aExitCode)
00374 {
00375   nsCOMPtr <nsIMsgSearchAdapter> runningAdapter;
00376 
00377   nsresult rv = GetRunningAdapter (getter_AddRefs(runningAdapter));
00378   // tell the current adapter that the current url has run.
00379   if (NS_SUCCEEDED(rv) && runningAdapter)
00380   {
00381     runningAdapter->CurrentUrlDone(aExitCode);
00382     EnableFolderNotifications(PR_TRUE);
00383     ReleaseFolderDBRef();
00384   }
00385   m_idxRunningScope++;
00386   if (++m_urlQueueIndex < m_urlQueue.Count())
00387     GetNextUrl();
00388   else if (m_idxRunningScope < m_scopeList.Count())
00389     DoNextSearch();
00390   else
00391     NotifyListenersDone(aExitCode);
00392   return NS_OK;
00393 }
00394 
00395 
00396 nsresult nsMsgSearchSession::Initialize()
00397 {
00398   // Loop over scope terms, initializing an adapter per term. This 
00399   // architecture is necessitated by two things: 
00400   // 1. There might be more than one kind of adapter per if online 
00401   //    *and* offline mail mail folders are selected, or if newsgroups
00402   //    belonging to Dredd *and* INN are selected
00403   // 2. Most of the protocols are only capable of searching one scope at a
00404   //    time, so we'll do each scope in a separate adapter on the client
00405 
00406   nsMsgSearchScopeTerm *scopeTerm = nsnull;
00407   nsresult err = NS_OK;
00408 
00409   PRUint32 numTerms;
00410   m_termList->Count(&numTerms);
00411   // Ensure that the FE has added scopes and terms to this search
00412   NS_ASSERTION(numTerms > 0, "no terms to search!");
00413   if (numTerms == 0)
00414     return NS_MSG_ERROR_NO_SEARCH_VALUES;
00415 
00416   // if we don't have any search scopes to search, return that code. 
00417   if (m_scopeList.Count() == 0)
00418     return NS_MSG_ERROR_INVALID_SEARCH_SCOPE;
00419 
00420   m_urlQueue.Clear(); // clear out old urls, if any.
00421   m_idxRunningScope = 0; 
00422   m_urlQueueIndex = 0;
00423   
00424   // If this term list (loosely specified here by the first term) should be
00425   // scheduled in parallel, build up a list of scopes to do the round-robin scheduling
00426   for (int i = 0; i < m_scopeList.Count() && NS_SUCCEEDED(err); i++)
00427   {
00428     scopeTerm = m_scopeList.ElementAt(i);
00429     // NS_ASSERTION(scopeTerm->IsValid());
00430     
00431     err = scopeTerm->InitializeAdapter (m_termList);
00432   }
00433   
00434   return err;
00435 }
00436 
00437 nsresult nsMsgSearchSession::BeginSearching()
00438 {
00439   // Here's a sloppy way to start the URL, but I don't really have time to
00440   // unify the scheduling mechanisms. If the first scope is a newsgroup, and
00441   // it's not Dredd-capable, we build the URL queue. All other searches can be
00442   // done with one URL
00443   
00444   if (m_window)
00445     m_window->SetStopped(PR_FALSE);
00446   return DoNextSearch();
00447 }
00448 
00449 nsresult nsMsgSearchSession::DoNextSearch()
00450 {
00451   nsMsgSearchScopeTerm *scope = m_scopeList.ElementAt(m_idxRunningScope);
00452   if (scope->m_attribute == nsMsgSearchScope::onlineMail || 
00453     (scope->m_attribute == nsMsgSearchScope::news && scope->m_searchServer))
00454     return BuildUrlQueue ();
00455   else
00456     return SearchWOUrls();
00457 }
00458 
00459 
00460 nsresult nsMsgSearchSession::BuildUrlQueue ()
00461 {
00462   PRInt32 i;
00463   for (i = m_idxRunningScope; i < m_scopeList.Count(); i++)
00464   {
00465     nsMsgSearchScopeTerm *scope = m_scopeList.ElementAt(i);
00466     if (scope->m_attribute != nsMsgSearchScope::onlineMail && 
00467       (scope->m_attribute != nsMsgSearchScope::news && scope->m_searchServer))
00468       break;
00469     nsCOMPtr <nsIMsgSearchAdapter> adapter = do_QueryInterface((m_scopeList.ElementAt(i))->m_adapter);
00470     nsXPIDLCString url;
00471     if (adapter)
00472     {
00473       adapter->GetEncoding(getter_Copies(url));
00474       AddUrl (url);
00475     }
00476   }
00477   
00478   if (i > 0)
00479     GetNextUrl();
00480   
00481   return NS_OK;
00482 }
00483 
00484 
00485 nsresult nsMsgSearchSession::GetNextUrl()
00486 {
00487   nsCString nextUrl;
00488   nsCOMPtr <nsIMsgMessageService> msgService;
00489 
00490 
00491   PRBool stopped = PR_FALSE;
00492 
00493   if (m_window)
00494     m_window->GetStopped(&stopped);
00495   if (stopped)
00496     return NS_OK;
00497 
00498   m_urlQueue.CStringAt(m_urlQueueIndex, nextUrl);
00499   nsMsgSearchScopeTerm *currentTerm = GetRunningScope();
00500   EnableFolderNotifications(PR_FALSE);
00501   nsCOMPtr <nsIMsgFolder> folder = currentTerm->m_folder;
00502   if (folder)
00503   {
00504     nsXPIDLCString folderUri;
00505     folder->GetURI(getter_Copies(folderUri));
00506     nsresult rv = GetMessageServiceFromURI(folderUri.get(), getter_AddRefs(msgService));
00507 
00508     if (NS_SUCCEEDED(rv) && msgService && currentTerm)
00509       msgService->Search(this, m_window, currentTerm->m_folder, nextUrl.get());
00510 
00511     return rv;
00512   }
00513   return NS_OK;
00514 }
00515 
00516 nsresult nsMsgSearchSession::AddUrl(const char *url)
00517 {
00518   nsCString urlCString(url);
00519   m_urlQueue.AppendCString(urlCString);
00520   return NS_OK;
00521 }
00522 
00523 /* static */ void nsMsgSearchSession::TimerCallback(nsITimer *aTimer, void *aClosure)
00524 {
00525   nsMsgSearchSession *searchSession = (nsMsgSearchSession *) aClosure;
00526   PRBool done;
00527   PRBool stopped = PR_FALSE;
00528 
00529   searchSession->TimeSlice(&done);
00530   if (searchSession->m_window)
00531     searchSession->m_window->GetStopped(&stopped);
00532 
00533   if (done || stopped)
00534   {
00535     aTimer->Cancel();
00536     searchSession->m_backgroundTimer = nsnull;
00537     if (searchSession->m_idxRunningScope < searchSession->m_scopeList.Count())
00538       searchSession->DoNextSearch();
00539     else
00540       searchSession->NotifyListenersDone(NS_OK);
00541   }
00542 }
00543 
00544 nsresult nsMsgSearchSession::StartTimer()
00545 {
00546   nsresult err;
00547   PRBool done;
00548 
00549   m_backgroundTimer = do_CreateInstance("@mozilla.org/timer;1", &err);
00550   m_backgroundTimer->InitWithFuncCallback(TimerCallback, (void *) this, 0, 
00551                                           nsITimer::TYPE_REPEATING_SLACK);
00552   // ### start meteors?
00553   return TimeSlice(&done);
00554 }
00555 
00556 nsresult nsMsgSearchSession::SearchWOUrls ()
00557 {
00558   EnableFolderNotifications(PR_FALSE);
00559   return StartTimer();
00560 }
00561 
00562 NS_IMETHODIMP nsMsgSearchSession::GetRunningAdapter (nsIMsgSearchAdapter **aSearchAdapter)
00563 {
00564   NS_ENSURE_ARG(aSearchAdapter);
00565   nsMsgSearchScopeTerm *scope = GetRunningScope();
00566   if (scope)
00567   {
00568     NS_ADDREF(*aSearchAdapter = scope->m_adapter);
00569     return NS_OK;
00570   }
00571   *aSearchAdapter = nsnull;
00572   return NS_OK;
00573 }
00574 
00575 NS_IMETHODIMP nsMsgSearchSession::AddSearchHit(nsIMsgDBHdr *header, nsIMsgFolder *folder)
00576 {
00577   if (m_listenerList)
00578   {
00579     PRUint32 count;
00580     m_listenerList->Count(&count);
00581     for (PRUint32 i = 0; i < count; i++)
00582     {
00583       nsCOMPtr<nsIMsgSearchNotify> pListener;
00584       m_listenerList->QueryElementAt(i, NS_GET_IID(nsIMsgSearchNotify),
00585                                (void **)getter_AddRefs(pListener));
00586       if (pListener)
00587         pListener->OnSearchHit(header, folder);
00588 
00589     }
00590   }
00591        return NS_OK;
00592 }
00593 
00594 nsresult nsMsgSearchSession::NotifyListenersDone(nsresult status)
00595 {
00596   if (m_listenerList)
00597   {
00598     PRUint32 count;
00599     m_listenerList->Count(&count);
00600     for (PRUint32 i = 0; i < count; i++)
00601     {
00602       nsCOMPtr<nsIMsgSearchNotify> pListener;
00603       m_listenerList->QueryElementAt(i, NS_GET_IID(nsIMsgSearchNotify),
00604                                (void **)getter_AddRefs(pListener));
00605       if (pListener)
00606         pListener->OnSearchDone(status);
00607 
00608     }
00609   }
00610   return NS_OK;
00611 }
00612 
00613 
00614 NS_IMETHODIMP nsMsgSearchSession::AddResultElement (nsMsgResultElement *element)
00615 {
00616   NS_ASSERTION(element, "no null elements");
00617 
00618   m_resultList.AppendElement (element);
00619 
00620   return NS_OK;
00621 }
00622 
00623 
00624 void nsMsgSearchSession::DestroyResultList ()
00625 {
00626   nsMsgResultElement *result = nsnull;
00627   for (int i = 0; i < m_resultList.Count(); i++)
00628   {
00629     result = m_resultList.ElementAt(i);
00630     //        NS_ASSERTION (result->IsValid(), "invalid search result");
00631     delete result;
00632   }
00633   m_resultList.Clear();
00634 }
00635 
00636 
00637 void nsMsgSearchSession::DestroyScopeList()
00638 {
00639   nsMsgSearchScopeTerm *scope = NULL;
00640   PRInt32 count = m_scopeList.Count();
00641   
00642   for (PRInt32 i = count-1; i >= 0; i--)
00643   {
00644     scope = m_scopeList.ElementAt(i);
00645     //        NS_ASSERTION (scope->IsValid(), "invalid search scope");
00646     delete scope;
00647   }
00648   m_scopeList.Clear();
00649 }
00650 
00651 
00652 void nsMsgSearchSession::DestroyTermList ()
00653 {
00654     m_termList->Clear();
00655 }
00656 
00657 nsMsgSearchScopeTerm *nsMsgSearchSession::GetRunningScope()
00658 {
00659     return (nsMsgSearchScopeTerm *) m_scopeList.SafeElementAt(m_idxRunningScope); 
00660 }
00661 
00662 nsresult nsMsgSearchSession::TimeSlice (PRBool *aDone)
00663 {
00664   // we only do serial for now.
00665   return TimeSliceSerial(aDone);
00666 }
00667 
00668 void nsMsgSearchSession::ReleaseFolderDBRef()  
00669 {
00670   nsMsgSearchScopeTerm *scope = GetRunningScope();
00671   if (scope)
00672   {
00673     PRBool isOpen =PR_FALSE;
00674     PRUint32 flags;
00675     nsCOMPtr <nsIMsgFolder> folder;
00676     scope->GetFolder(getter_AddRefs(folder));
00677     nsCOMPtr <nsIMsgMailSession> mailSession = do_GetService(NS_MSGMAILSESSION_CONTRACTID);
00678     if (mailSession && folder)
00679     {
00680       mailSession->IsFolderOpenInWindow(folder, &isOpen);
00681       folder->GetFlags(&flags);
00682 
00683       /*we don't null out the db reference for inbox because inbox is like the "main" folder
00684        and performance outweighs footprint */
00685       if (!isOpen && !(MSG_FOLDER_FLAG_INBOX & flags)) 
00686         folder->SetMsgDatabase(nsnull);
00687     }
00688   }
00689 }
00690 nsresult nsMsgSearchSession::TimeSliceSerial (PRBool *aDone)
00691 {
00692   // This version of TimeSlice runs each scope term one at a time, and waits until one
00693   // scope term is finished before starting another one. When we're searching the local
00694   // disk, this is the fastest way to do it.
00695 
00696   NS_ENSURE_ARG(aDone);
00697   nsresult rv = NS_OK;
00698   nsMsgSearchScopeTerm *scope = GetRunningScope();
00699   if (scope)
00700   {
00701     rv = scope->TimeSlice (aDone);
00702     if (NS_FAILED(rv))
00703       *aDone = PR_TRUE;
00704     if (*aDone || NS_FAILED(rv))
00705     {
00706       EnableFolderNotifications(PR_TRUE);
00707       ReleaseFolderDBRef();
00708       m_idxRunningScope++;
00709       EnableFolderNotifications(PR_FALSE);
00710       // check if the next scope is an online search; if so,
00711       // set *aDone to true so that we'll try to run the next
00712       // search in TimerCallback.
00713       scope = GetRunningScope();
00714       if (scope && (scope->m_attribute == nsMsgSearchScope::onlineMail || 
00715         (scope->m_attribute == nsMsgSearchScope::news && scope->m_searchServer)))
00716       {
00717         *aDone = PR_TRUE;
00718         return rv;
00719       }
00720 
00721     }
00722     *aDone = PR_FALSE;
00723     return rv;
00724   }
00725   else
00726   {
00727     *aDone = PR_TRUE;
00728     return NS_OK;
00729   }
00730 }
00731 
00732 void 
00733 nsMsgSearchSession::EnableFolderNotifications(PRBool aEnable)
00734 {
00735   nsMsgSearchScopeTerm *scope = GetRunningScope();
00736   if (scope)
00737   {
00738     nsCOMPtr<nsIMsgFolder> folder;
00739     scope->GetFolder(getter_AddRefs(folder));
00740     if (folder)  //enable msg count notifications
00741       folder->EnableNotifications(nsIMsgFolder::allMessageCountNotifications, aEnable, PR_FALSE);
00742   }
00743 }
00744 
00745 //this method is used for adding new hdrs to quick search view
00746 NS_IMETHODIMP
00747 nsMsgSearchSession::MatchHdr(nsIMsgDBHdr *aMsgHdr, nsIMsgDatabase *aDatabase, PRBool *aResult)
00748 {
00749   nsMsgSearchScopeTerm *scope = (nsMsgSearchScopeTerm *)m_scopeList.SafeElementAt(0);
00750   if (scope)
00751   {
00752     if (!scope->m_adapter)
00753       scope->InitializeAdapter(m_termList);
00754     if (scope->m_adapter)
00755     {  
00756       nsXPIDLString nullCharset, folderCharset;
00757       scope->m_adapter->GetSearchCharsets(getter_Copies(nullCharset), getter_Copies(folderCharset));
00758       NS_ConvertUCS2toUTF8 charset(folderCharset.get());
00759       nsMsgSearchOfflineMail::MatchTermsForSearch(aMsgHdr, m_termList, charset.get(), scope, aDatabase, &m_expressionTree, aResult);
00760     }
00761   }
00762   return NS_OK;
00763 }
00764