1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 // Implementation of db search for POP and offline IMAP mail folders
7
8 #include "msgCore.h"
9 #include "nsIMsgDatabase.h"
10 #include "nsMsgSearchCore.h"
11 #include "nsMsgLocalSearch.h"
12 #include "nsIStreamListener.h"
13 #include "nsMsgSearchBoolExpression.h"
14 #include "nsMsgSearchTerm.h"
15 #include "nsMsgResultElement.h"
16 #include "nsIDBFolderInfo.h"
17 #include "nsMsgBaseCID.h"
18 #include "nsMsgSearchValue.h"
19 #include "nsIMsgLocalMailFolder.h"
20 #include "nsIMsgWindow.h"
21 #include "nsIMsgHdr.h"
22 #include "nsIMsgFilterPlugin.h"
23 #include "nsMsgMessageFlags.h"
24 #include "nsMsgUtils.h"
25 #include "nsIMsgFolder.h"
26
27 extern "C" {
28 extern int MK_MSG_SEARCH_STATUS;
29 extern int MK_MSG_CANT_SEARCH_IF_NO_SUMMARY;
30 extern int MK_MSG_SEARCH_HITS_NOT_IN_DB;
31 }
32
33 //----------------------------------------------------------------------------
34 // Class definitions for the boolean expression structure....
35 //----------------------------------------------------------------------------
36
AddSearchTerm(nsMsgSearchBoolExpression * aOrigExpr,nsIMsgSearchTerm * aNewTerm,char * aEncodingStr)37 nsMsgSearchBoolExpression* nsMsgSearchBoolExpression::AddSearchTerm(
38 nsMsgSearchBoolExpression* aOrigExpr, nsIMsgSearchTerm* aNewTerm,
39 char* aEncodingStr)
40 // appropriately add the search term to the current expression and return a
41 // pointer to the new expression. The encodingStr is the IMAP/NNTP encoding
42 // string for newTerm.
43 {
44 return aOrigExpr->leftToRightAddTerm(aNewTerm, aEncodingStr);
45 }
46
AddExpressionTree(nsMsgSearchBoolExpression * aOrigExpr,nsMsgSearchBoolExpression * aExpression,bool aBoolOp)47 nsMsgSearchBoolExpression* nsMsgSearchBoolExpression::AddExpressionTree(
48 nsMsgSearchBoolExpression* aOrigExpr,
49 nsMsgSearchBoolExpression* aExpression, bool aBoolOp) {
50 if (!aOrigExpr->m_term && !aOrigExpr->m_leftChild &&
51 !aOrigExpr->m_rightChild) {
52 // just use the original expression tree...
53 // delete the original since we have a new original to use
54 delete aOrigExpr;
55 return aExpression;
56 }
57
58 nsMsgSearchBoolExpression* newExpr =
59 new nsMsgSearchBoolExpression(aOrigExpr, aExpression, aBoolOp);
60 return (newExpr) ? newExpr : aOrigExpr;
61 }
62
nsMsgSearchBoolExpression()63 nsMsgSearchBoolExpression::nsMsgSearchBoolExpression() {
64 m_term = nullptr;
65 m_boolOp = nsMsgSearchBooleanOp::BooleanAND;
66 m_leftChild = nullptr;
67 m_rightChild = nullptr;
68 }
69
nsMsgSearchBoolExpression(nsIMsgSearchTerm * newTerm,char * encodingStr)70 nsMsgSearchBoolExpression::nsMsgSearchBoolExpression(nsIMsgSearchTerm* newTerm,
71 char* encodingStr)
72 // we are creating an expression which contains a single search term (newTerm)
73 // and the search term's IMAP or NNTP encoding value for online search
74 // expressions AND a boolean evaluation value which is used for offline search
75 // expressions.
76 {
77 m_term = newTerm;
78 m_encodingStr = encodingStr;
79 m_boolOp = nsMsgSearchBooleanOp::BooleanAND;
80
81 // this expression does not contain sub expressions
82 m_leftChild = nullptr;
83 m_rightChild = nullptr;
84 }
85
nsMsgSearchBoolExpression(nsMsgSearchBoolExpression * expr1,nsMsgSearchBoolExpression * expr2,nsMsgSearchBooleanOperator boolOp)86 nsMsgSearchBoolExpression::nsMsgSearchBoolExpression(
87 nsMsgSearchBoolExpression* expr1, nsMsgSearchBoolExpression* expr2,
88 nsMsgSearchBooleanOperator boolOp)
89 // we are creating an expression which contains two sub expressions and a
90 // boolean operator used to combine them.
91 {
92 m_leftChild = expr1;
93 m_rightChild = expr2;
94 m_boolOp = boolOp;
95
96 m_term = nullptr;
97 }
98
~nsMsgSearchBoolExpression()99 nsMsgSearchBoolExpression::~nsMsgSearchBoolExpression() {
100 // we must recursively destroy all sub expressions before we destroy
101 // ourself.....We leave search terms alone!
102 delete m_leftChild;
103 delete m_rightChild;
104 }
105
leftToRightAddTerm(nsIMsgSearchTerm * newTerm,char * encodingStr)106 nsMsgSearchBoolExpression* nsMsgSearchBoolExpression::leftToRightAddTerm(
107 nsIMsgSearchTerm* newTerm, char* encodingStr) {
108 // we have a base case where this is the first term being added to the
109 // expression:
110 if (!m_term && !m_leftChild && !m_rightChild) {
111 m_term = newTerm;
112 m_encodingStr = encodingStr;
113 return this;
114 }
115
116 nsMsgSearchBoolExpression* tempExpr =
117 new nsMsgSearchBoolExpression(newTerm, encodingStr);
118 if (tempExpr) // make sure creation succeeded
119 {
120 bool booleanAnd;
121 newTerm->GetBooleanAnd(&booleanAnd);
122 nsMsgSearchBoolExpression* newExpr =
123 new nsMsgSearchBoolExpression(this, tempExpr, booleanAnd);
124 if (newExpr)
125 return newExpr;
126 else
127 delete tempExpr; // clean up memory allocation in case of failure
128 }
129 return this; // in case we failed to create a new expression, return self
130 }
131
132 // returns true or false depending on what the current expression evaluates to.
OfflineEvaluate(nsIMsgDBHdr * msgToMatch,const char * defaultCharset,nsIMsgSearchScopeTerm * scope,nsIMsgDatabase * db,const nsACString & headers,bool Filtering)133 bool nsMsgSearchBoolExpression::OfflineEvaluate(nsIMsgDBHdr* msgToMatch,
134 const char* defaultCharset,
135 nsIMsgSearchScopeTerm* scope,
136 nsIMsgDatabase* db,
137 const nsACString& headers,
138 bool Filtering) {
139 bool result = true; // always default to false positives
140 bool isAnd;
141
142 if (m_term) // do we contain just a search term?
143 {
144 nsMsgSearchOfflineMail::ProcessSearchTerm(msgToMatch, m_term,
145 defaultCharset, scope, db,
146 headers, Filtering, &result);
147 return result;
148 }
149
150 // otherwise we must recursively determine the value of our sub expressions
151
152 isAnd = (m_boolOp == nsMsgSearchBooleanOp::BooleanAND);
153
154 if (m_leftChild) {
155 result = m_leftChild->OfflineEvaluate(msgToMatch, defaultCharset, scope, db,
156 headers, Filtering);
157 if ((result && !isAnd) || (!result && isAnd)) return result;
158 }
159
160 // If we got this far, either there was no leftChild (which is impossible)
161 // or we got (FALSE and OR) or (TRUE and AND) from the first result. That
162 // means the outcome depends entirely on the rightChild.
163 if (m_rightChild)
164 result = m_rightChild->OfflineEvaluate(msgToMatch, defaultCharset, scope,
165 db, headers, Filtering);
166
167 return result;
168 }
169
170 // ### Maybe we can get rid of these because of our use of nsString???
171 // constants used for online searching with IMAP/NNTP encoded search terms.
172 // the + 1 is to account for null terminators we add at each stage of assembling
173 // the expression...
174 const int sizeOfORTerm =
175 6 + 1; // 6 bytes if we are combining two sub expressions with an OR term
176 const int sizeOfANDTerm =
177 1 + 1; // 1 byte if we are combining two sub expressions with an AND term
178
CalcEncodeStrSize()179 int32_t nsMsgSearchBoolExpression::CalcEncodeStrSize()
180 // recursively examine each sub expression and calculate a final size for the
181 // entire IMAP/NNTP encoding
182 {
183 if (!m_term && (!m_leftChild || !m_rightChild)) // is the expression empty?
184 return 0;
185 if (m_term) // are we a leaf node?
186 return m_encodingStr.Length();
187 if (m_boolOp == nsMsgSearchBooleanOp::BooleanOR)
188 return sizeOfORTerm + m_leftChild->CalcEncodeStrSize() +
189 m_rightChild->CalcEncodeStrSize();
190 if (m_boolOp == nsMsgSearchBooleanOp::BooleanAND)
191 return sizeOfANDTerm + m_leftChild->CalcEncodeStrSize() +
192 m_rightChild->CalcEncodeStrSize();
193 return 0;
194 }
195
GenerateEncodeStr(nsCString * buffer)196 void nsMsgSearchBoolExpression::GenerateEncodeStr(nsCString* buffer)
197 // recursively combine sub expressions to form a single IMAP/NNTP encoded string
198 {
199 if ((!m_term && (!m_leftChild || !m_rightChild))) // is expression empty?
200 return;
201
202 if (m_term) // are we a leaf expression?
203 {
204 *buffer += m_encodingStr;
205 return;
206 }
207
208 // add encode strings of each sub expression
209 if (m_boolOp == nsMsgSearchBooleanOp::BooleanOR) {
210 *buffer += " (OR";
211
212 m_leftChild->GenerateEncodeStr(
213 buffer); // insert left expression into the buffer
214 m_rightChild->GenerateEncodeStr(
215 buffer); // insert right expression into the buffer
216
217 // HACK ALERT!!! if last returned character in the buffer is now a ' ' then
218 // we need to remove it because we don't want a ' ' to preceded the closing
219 // paren in the OR encoding.
220 uint32_t lastCharPos = buffer->Length() - 1;
221 if (buffer->CharAt(lastCharPos) == ' ') {
222 buffer->SetLength(lastCharPos);
223 }
224
225 *buffer += ')';
226 } else if (m_boolOp == nsMsgSearchBooleanOp::BooleanAND) {
227 m_leftChild->GenerateEncodeStr(buffer); // insert left expression
228 m_rightChild->GenerateEncodeStr(buffer);
229 }
230 return;
231 }
232
233 //-----------------------------------------------------------------------------
234 //---------------- Adapter class for searching offline folders ----------------
235 //-----------------------------------------------------------------------------
236
NS_IMPL_ISUPPORTS_INHERITED(nsMsgSearchOfflineMail,nsMsgSearchAdapter,nsIUrlListener)237 NS_IMPL_ISUPPORTS_INHERITED(nsMsgSearchOfflineMail, nsMsgSearchAdapter,
238 nsIUrlListener)
239
240 nsMsgSearchOfflineMail::nsMsgSearchOfflineMail(
241 nsIMsgSearchScopeTerm* scope,
242 nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList)
243 : nsMsgSearchAdapter(scope, termList) {}
244
~nsMsgSearchOfflineMail()245 nsMsgSearchOfflineMail::~nsMsgSearchOfflineMail() {
246 // Database should have been closed when the scope term finished.
247 CleanUpScope();
248 NS_ASSERTION(!m_db, "db not closed");
249 }
250
ValidateTerms()251 nsresult nsMsgSearchOfflineMail::ValidateTerms() {
252 return nsMsgSearchAdapter::ValidateTerms();
253 }
254
OpenSummaryFile()255 nsresult nsMsgSearchOfflineMail::OpenSummaryFile() {
256 nsCOMPtr<nsIMsgDatabase> mailDB;
257
258 nsresult err = NS_OK;
259 // do password protection of local cache thing.
260 #ifdef DOING_FOLDER_CACHE_PASSWORDS
261 if (m_scope->m_folder &&
262 m_scope->m_folder->UserNeedsToAuthenticateForFolder(false) &&
263 m_scope->m_folder->GetMaster()->PromptForHostPassword(
264 m_scope->m_frame->GetContext(), m_scope->m_folder) != 0) {
265 m_scope->m_frame->StopRunning();
266 return SearchError_ScopeDone;
267 }
268 #endif
269 nsCOMPtr<nsIDBFolderInfo> folderInfo;
270 nsCOMPtr<nsIMsgFolder> scopeFolder;
271 err = m_scope->GetFolder(getter_AddRefs(scopeFolder));
272 if (NS_SUCCEEDED(err) && scopeFolder) {
273 err = scopeFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo),
274 getter_AddRefs(m_db));
275 } else
276 return err; // not sure why m_folder wouldn't be set.
277
278 if (NS_SUCCEEDED(err)) return NS_OK;
279
280 if ((err == NS_MSG_ERROR_FOLDER_SUMMARY_MISSING) ||
281 (err == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE)) {
282 nsCOMPtr<nsIMsgLocalMailFolder> localFolder =
283 do_QueryInterface(scopeFolder, &err);
284 if (NS_SUCCEEDED(err) && localFolder) {
285 nsCOMPtr<nsIMsgSearchSession> searchSession;
286 m_scope->GetSearchSession(getter_AddRefs(searchSession));
287 if (searchSession) {
288 nsCOMPtr<nsIMsgWindow> searchWindow;
289
290 searchSession->GetWindow(getter_AddRefs(searchWindow));
291 searchSession->PauseSearch();
292 localFolder->ParseFolder(searchWindow, this);
293 }
294 }
295 } else {
296 NS_ASSERTION(false, "unexpected error opening db");
297 }
298
299 return err;
300 }
301
MatchTermsForFilter(nsIMsgDBHdr * msgToMatch,nsTArray<RefPtr<nsIMsgSearchTerm>> const & termList,const char * defaultCharset,nsIMsgSearchScopeTerm * scope,nsIMsgDatabase * db,const nsACString & headers,nsMsgSearchBoolExpression ** aExpressionTree,bool * pResult)302 nsresult nsMsgSearchOfflineMail::MatchTermsForFilter(
303 nsIMsgDBHdr* msgToMatch, nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList,
304 const char* defaultCharset, nsIMsgSearchScopeTerm* scope,
305 nsIMsgDatabase* db, const nsACString& headers,
306 nsMsgSearchBoolExpression** aExpressionTree, bool* pResult) {
307 return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, headers,
308 true, aExpressionTree, pResult);
309 }
310
311 // static method which matches a header against a list of search terms.
MatchTermsForSearch(nsIMsgDBHdr * msgToMatch,nsTArray<RefPtr<nsIMsgSearchTerm>> const & termList,const char * defaultCharset,nsIMsgSearchScopeTerm * scope,nsIMsgDatabase * db,nsMsgSearchBoolExpression ** aExpressionTree,bool * pResult)312 nsresult nsMsgSearchOfflineMail::MatchTermsForSearch(
313 nsIMsgDBHdr* msgToMatch, nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList,
314 const char* defaultCharset, nsIMsgSearchScopeTerm* scope,
315 nsIMsgDatabase* db, nsMsgSearchBoolExpression** aExpressionTree,
316 bool* pResult) {
317 return MatchTerms(msgToMatch, termList, defaultCharset, scope, db,
318 EmptyCString(), false, aExpressionTree, pResult);
319 }
320
ConstructExpressionTree(nsTArray<RefPtr<nsIMsgSearchTerm>> const & termList,uint32_t termCount,uint32_t & aStartPosInList,nsMsgSearchBoolExpression ** aExpressionTree)321 nsresult nsMsgSearchOfflineMail::ConstructExpressionTree(
322 nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList, uint32_t termCount,
323 uint32_t& aStartPosInList, nsMsgSearchBoolExpression** aExpressionTree) {
324 nsMsgSearchBoolExpression* finalExpression = *aExpressionTree;
325
326 if (!finalExpression) finalExpression = new nsMsgSearchBoolExpression();
327
328 while (aStartPosInList < termCount) {
329 nsIMsgSearchTerm* pTerm = termList[aStartPosInList];
330 NS_ASSERTION(pTerm, "couldn't get term to match");
331
332 bool beginsGrouping;
333 bool endsGrouping;
334 pTerm->GetBeginsGrouping(&beginsGrouping);
335 pTerm->GetEndsGrouping(&endsGrouping);
336
337 if (beginsGrouping) {
338 // temporarily turn off the grouping for our recursive call
339 pTerm->SetBeginsGrouping(false);
340 nsMsgSearchBoolExpression* innerExpression =
341 new nsMsgSearchBoolExpression();
342
343 // the first search term in the grouping is the one that holds the
344 // operator for how this search term should be joined with the expressions
345 // to it's left.
346 bool booleanAnd;
347 pTerm->GetBooleanAnd(&booleanAnd);
348
349 // now add this expression tree to our overall expression tree...
350 finalExpression = nsMsgSearchBoolExpression::AddExpressionTree(
351 finalExpression, innerExpression, booleanAnd);
352
353 // recursively process this inner expression
354 ConstructExpressionTree(termList, termCount, aStartPosInList,
355 &finalExpression->m_rightChild);
356
357 // undo our damage
358 pTerm->SetBeginsGrouping(true);
359
360 } else {
361 finalExpression = nsMsgSearchBoolExpression::AddSearchTerm(
362 finalExpression, pTerm,
363 nullptr); // add the term to the expression tree
364
365 if (endsGrouping) break;
366 }
367
368 aStartPosInList++;
369 } // while we still have terms to process in this group
370
371 *aExpressionTree = finalExpression;
372
373 return NS_OK;
374 }
375
ProcessSearchTerm(nsIMsgDBHdr * msgToMatch,nsIMsgSearchTerm * aTerm,const char * defaultCharset,nsIMsgSearchScopeTerm * scope,nsIMsgDatabase * db,const nsACString & headers,bool Filtering,bool * pResult)376 nsresult nsMsgSearchOfflineMail::ProcessSearchTerm(
377 nsIMsgDBHdr* msgToMatch, nsIMsgSearchTerm* aTerm,
378 const char* defaultCharset, nsIMsgSearchScopeTerm* scope,
379 nsIMsgDatabase* db, const nsACString& headers, bool Filtering,
380 bool* pResult) {
381 nsresult err = NS_OK;
382 nsCString recipients;
383 nsCString ccList;
384 nsCString matchString;
385 nsCString msgCharset;
386 const char* charset;
387 bool charsetOverride = false; /* XXX BUG 68706 */
388 uint32_t msgFlags;
389 bool result;
390 bool matchAll;
391
392 NS_ENSURE_ARG_POINTER(pResult);
393
394 aTerm->GetMatchAll(&matchAll);
395 if (matchAll) {
396 *pResult = true;
397 return NS_OK;
398 }
399 *pResult = false;
400
401 nsMsgSearchAttribValue attrib;
402 aTerm->GetAttrib(&attrib);
403 msgToMatch->GetCharset(getter_Copies(msgCharset));
404 charset = msgCharset.get();
405 if (!charset || !*charset) charset = (const char*)defaultCharset;
406 msgToMatch->GetFlags(&msgFlags);
407
408 switch (attrib) {
409 case nsMsgSearchAttrib::Sender:
410 msgToMatch->GetAuthor(getter_Copies(matchString));
411 err = aTerm->MatchRfc822String(matchString, charset, &result);
412 break;
413 case nsMsgSearchAttrib::Subject: {
414 msgToMatch->GetSubject(getter_Copies(matchString) /* , true */);
415 if (msgFlags & nsMsgMessageFlags::HasRe) {
416 // Make sure we pass along the "Re: " part of the subject if this is a
417 // reply.
418 nsCString reString;
419 reString.AssignLiteral("Re: ");
420 reString.Append(matchString);
421 err = aTerm->MatchRfc2047String(reString, charset, charsetOverride,
422 &result);
423 } else
424 err = aTerm->MatchRfc2047String(matchString, charset, charsetOverride,
425 &result);
426 break;
427 }
428 case nsMsgSearchAttrib::ToOrCC: {
429 bool boolKeepGoing;
430 aTerm->GetMatchAllBeforeDeciding(&boolKeepGoing);
431 msgToMatch->GetRecipients(getter_Copies(recipients));
432 err = aTerm->MatchRfc822String(recipients, charset, &result);
433 if (boolKeepGoing == result) {
434 msgToMatch->GetCcList(getter_Copies(ccList));
435 err = aTerm->MatchRfc822String(ccList, charset, &result);
436 }
437 break;
438 }
439 case nsMsgSearchAttrib::AllAddresses: {
440 bool boolKeepGoing;
441 aTerm->GetMatchAllBeforeDeciding(&boolKeepGoing);
442 msgToMatch->GetRecipients(getter_Copies(recipients));
443 err = aTerm->MatchRfc822String(recipients, charset, &result);
444 if (boolKeepGoing == result) {
445 msgToMatch->GetCcList(getter_Copies(ccList));
446 err = aTerm->MatchRfc822String(ccList, charset, &result);
447 }
448 if (boolKeepGoing == result) {
449 msgToMatch->GetAuthor(getter_Copies(matchString));
450 err = aTerm->MatchRfc822String(matchString, charset, &result);
451 }
452 if (boolKeepGoing == result) {
453 nsCString bccList;
454 msgToMatch->GetBccList(getter_Copies(bccList));
455 err = aTerm->MatchRfc822String(bccList, charset, &result);
456 }
457 break;
458 }
459 case nsMsgSearchAttrib::Body: {
460 uint64_t messageOffset;
461 uint32_t lineCount;
462 msgToMatch->GetMessageOffset(&messageOffset);
463 msgToMatch->GetLineCount(&lineCount);
464 err = aTerm->MatchBody(scope, messageOffset, lineCount, charset,
465 msgToMatch, db, &result);
466 break;
467 }
468 case nsMsgSearchAttrib::Date: {
469 PRTime date;
470 msgToMatch->GetDate(&date);
471 err = aTerm->MatchDate(date, &result);
472
473 break;
474 }
475 case nsMsgSearchAttrib::HasAttachmentStatus:
476 case nsMsgSearchAttrib::MsgStatus:
477 err = aTerm->MatchStatus(msgFlags, &result);
478 break;
479 case nsMsgSearchAttrib::Priority: {
480 nsMsgPriorityValue msgPriority;
481 msgToMatch->GetPriority(&msgPriority);
482 err = aTerm->MatchPriority(msgPriority, &result);
483 break;
484 }
485 case nsMsgSearchAttrib::Size: {
486 uint32_t messageSize;
487 msgToMatch->GetMessageSize(&messageSize);
488 err = aTerm->MatchSize(messageSize, &result);
489 break;
490 }
491 case nsMsgSearchAttrib::To:
492 msgToMatch->GetRecipients(getter_Copies(recipients));
493 err = aTerm->MatchRfc822String(recipients, charset, &result);
494 break;
495 case nsMsgSearchAttrib::CC:
496 msgToMatch->GetCcList(getter_Copies(ccList));
497 err = aTerm->MatchRfc822String(ccList, charset, &result);
498 break;
499 case nsMsgSearchAttrib::AgeInDays: {
500 PRTime date;
501 msgToMatch->GetDate(&date);
502 err = aTerm->MatchAge(date, &result);
503 break;
504 }
505 case nsMsgSearchAttrib::Label: {
506 nsMsgLabelValue label;
507 msgToMatch->GetLabel(&label);
508 err = aTerm->MatchLabel(label, &result);
509 break;
510 }
511 case nsMsgSearchAttrib::Keywords: {
512 nsCString keywords;
513 nsMsgLabelValue label;
514 msgToMatch->GetStringProperty("keywords", getter_Copies(keywords));
515 msgToMatch->GetLabel(&label);
516 if (label >= 1) {
517 if (!keywords.IsEmpty()) keywords.Append(' ');
518 keywords.AppendLiteral("$label");
519 keywords.Append(label + '0');
520 }
521 err = aTerm->MatchKeyword(keywords, &result);
522 break;
523 }
524 case nsMsgSearchAttrib::JunkStatus: {
525 nsCString junkScoreStr;
526 msgToMatch->GetStringProperty("junkscore", getter_Copies(junkScoreStr));
527 err = aTerm->MatchJunkStatus(junkScoreStr.get(), &result);
528 break;
529 }
530 case nsMsgSearchAttrib::JunkPercent: {
531 // When the junk status is set by the plugin, use junkpercent (if
532 // available) Otherwise, use the limits (0 or 100) depending on the
533 // junkscore.
534 uint32_t junkPercent;
535 nsresult rv;
536 nsCString junkScoreOriginStr;
537 nsCString junkPercentStr;
538 msgToMatch->GetStringProperty("junkscoreorigin",
539 getter_Copies(junkScoreOriginStr));
540 msgToMatch->GetStringProperty("junkpercent",
541 getter_Copies(junkPercentStr));
542 if (junkScoreOriginStr.EqualsLiteral("plugin") &&
543 !junkPercentStr.IsEmpty()) {
544 junkPercent = junkPercentStr.ToInteger(&rv);
545 NS_ENSURE_SUCCESS(rv, rv);
546 } else {
547 nsCString junkScoreStr;
548 msgToMatch->GetStringProperty("junkscore", getter_Copies(junkScoreStr));
549 // When junk status is not set (uncertain) we'll set the value to ham.
550 if (junkScoreStr.IsEmpty())
551 junkPercent = nsIJunkMailPlugin::IS_HAM_SCORE;
552 else {
553 junkPercent = junkScoreStr.ToInteger(&rv);
554 NS_ENSURE_SUCCESS(rv, rv);
555 }
556 }
557 err = aTerm->MatchJunkPercent(junkPercent, &result);
558 break;
559 }
560 case nsMsgSearchAttrib::JunkScoreOrigin: {
561 nsCString junkScoreOriginStr;
562 msgToMatch->GetStringProperty("junkscoreorigin",
563 getter_Copies(junkScoreOriginStr));
564 err = aTerm->MatchJunkScoreOrigin(junkScoreOriginStr.get(), &result);
565 break;
566 }
567 case nsMsgSearchAttrib::HdrProperty: {
568 err = aTerm->MatchHdrProperty(msgToMatch, &result);
569 break;
570 }
571 case nsMsgSearchAttrib::Uint32HdrProperty: {
572 err = aTerm->MatchUint32HdrProperty(msgToMatch, &result);
573 break;
574 }
575 case nsMsgSearchAttrib::Custom: {
576 err = aTerm->MatchCustom(msgToMatch, &result);
577 break;
578 }
579 case nsMsgSearchAttrib::FolderFlag: {
580 err = aTerm->MatchFolderFlag(msgToMatch, &result);
581 break;
582 }
583 default:
584 // XXX todo
585 // for the temporary return receipts filters, we use a custom header for
586 // Content-Type but unlike the other custom headers, this one doesn't show
587 // up in the search / filter UI. we set the attrib to be
588 // nsMsgSearchAttrib::OtherHeader, where as for user defined custom
589 // headers start at nsMsgSearchAttrib::OtherHeader + 1 Not sure if there
590 // is a better way to do this yet. Maybe reserve the last custom header
591 // for ::Content-Type? But if we do, make sure that change doesn't cause
592 // nsMsgFilter::GetTerm() to change, and start making us ask IMAP servers
593 // for the Content-Type header on all messages.
594 if (attrib >= nsMsgSearchAttrib::OtherHeader &&
595 attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes) {
596 uint32_t lineCount;
597 msgToMatch->GetLineCount(&lineCount);
598 uint64_t messageOffset;
599 msgToMatch->GetMessageOffset(&messageOffset);
600 err = aTerm->MatchArbitraryHeader(scope, lineCount, charset,
601 charsetOverride, msgToMatch, db,
602 headers, Filtering, &result);
603 } else {
604 err = NS_ERROR_INVALID_ARG; // ### was SearchError_InvalidAttribute
605 result = false;
606 }
607 }
608
609 *pResult = result;
610 return err;
611 }
612
MatchTerms(nsIMsgDBHdr * msgToMatch,nsTArray<RefPtr<nsIMsgSearchTerm>> const & termList,const char * defaultCharset,nsIMsgSearchScopeTerm * scope,nsIMsgDatabase * db,const nsACString & headers,bool Filtering,nsMsgSearchBoolExpression ** aExpressionTree,bool * pResult)613 nsresult nsMsgSearchOfflineMail::MatchTerms(
614 nsIMsgDBHdr* msgToMatch, nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList,
615 const char* defaultCharset, nsIMsgSearchScopeTerm* scope,
616 nsIMsgDatabase* db, const nsACString& headers, bool Filtering,
617 nsMsgSearchBoolExpression** aExpressionTree, bool* pResult) {
618 NS_ENSURE_ARG(aExpressionTree);
619 nsresult err;
620
621 if (!*aExpressionTree) {
622 uint32_t initialPos = 0;
623 uint32_t count = termList.Length();
624 err = ConstructExpressionTree(termList, count, initialPos, aExpressionTree);
625 if (NS_FAILED(err)) return err;
626 }
627
628 // evaluate the expression tree and return the result
629 *pResult = (*aExpressionTree)
630 ? (*aExpressionTree)
631 ->OfflineEvaluate(msgToMatch, defaultCharset, scope, db,
632 headers, Filtering)
633 : true; // vacuously true...
634
635 return NS_OK;
636 }
637
Search(bool * aDone)638 nsresult nsMsgSearchOfflineMail::Search(bool* aDone) {
639 nsresult err = NS_OK;
640
641 NS_ENSURE_ARG(aDone);
642 nsresult dbErr = NS_OK;
643 nsMsgSearchBoolExpression* expressionTree = nullptr;
644
645 const uint32_t kTimeSliceInMS = 200;
646
647 *aDone = false;
648 // Try to open the DB lazily. This will set up a parser if one is required
649 if (!m_db) err = OpenSummaryFile();
650 if (!m_db) // must be reparsing.
651 return err;
652
653 // Reparsing is unnecessary or completed
654 if (NS_SUCCEEDED(err)) {
655 if (!m_listContext)
656 dbErr = m_db->ReverseEnumerateMessages(getter_AddRefs(m_listContext));
657 if (NS_SUCCEEDED(dbErr) && m_listContext) {
658 PRIntervalTime startTime = PR_IntervalNow();
659 while (!*aDone) // we'll break out of the loop after kTimeSliceInMS
660 // milliseconds
661 {
662 nsCOMPtr<nsIMsgDBHdr> msgDBHdr;
663 dbErr = m_listContext->GetNext(getter_AddRefs(msgDBHdr));
664 if (NS_FAILED(dbErr))
665 *aDone = true; //###phil dbErr is dropped on the floor. just note
666 // that we did have an error so we'll clean up later
667 else {
668 bool match = false;
669 nsAutoString nullCharset, folderCharset;
670 GetSearchCharsets(nullCharset, folderCharset);
671 NS_ConvertUTF16toUTF8 charset(folderCharset);
672 // Is this message a hit?
673 err = MatchTermsForSearch(msgDBHdr, m_searchTerms, charset.get(),
674 m_scope, m_db, &expressionTree, &match);
675 // Add search hits to the results list
676 if (NS_SUCCEEDED(err) && match) {
677 AddResultElement(msgDBHdr);
678 }
679 PRIntervalTime elapsedTime = PR_IntervalNow() - startTime;
680 // check if more than kTimeSliceInMS milliseconds have elapsed in this
681 // time slice started
682 if (PR_IntervalToMilliseconds(elapsedTime) > kTimeSliceInMS) break;
683 }
684 }
685 }
686 } else
687 *aDone = true; // we couldn't open up the DB. This is an unrecoverable
688 // error so mark the scope as done.
689
690 delete expressionTree;
691
692 // in the past an error here would cause an "infinite" search because the url
693 // would continue to run... i.e. if we couldn't open the database, it returns
694 // an error code but the caller of this function says, oh, we did not finish
695 // so continue...what we really want is to treat this current scope as done
696 if (*aDone) CleanUpScope(); // Do clean up for end-of-scope processing
697 return err;
698 }
699
CleanUpScope()700 void nsMsgSearchOfflineMail::CleanUpScope() {
701 // Let go of the DB when we're done with it so we don't kill the db cache
702 if (m_db) {
703 m_listContext = nullptr;
704 m_db->Close(false);
705 }
706 m_db = nullptr;
707
708 if (m_scope) m_scope->CloseInputStream();
709 }
710
AddResultElement(nsIMsgDBHdr * pHeaders)711 NS_IMETHODIMP nsMsgSearchOfflineMail::AddResultElement(nsIMsgDBHdr* pHeaders) {
712 nsresult err = NS_OK;
713
714 nsCOMPtr<nsIMsgSearchSession> searchSession;
715 m_scope->GetSearchSession(getter_AddRefs(searchSession));
716 if (searchSession) {
717 nsCOMPtr<nsIMsgFolder> scopeFolder;
718 err = m_scope->GetFolder(getter_AddRefs(scopeFolder));
719 searchSession->AddSearchHit(pHeaders, scopeFolder);
720 }
721 return err;
722 }
723
724 NS_IMETHODIMP
Abort()725 nsMsgSearchOfflineMail::Abort() {
726 // Let go of the DB when we're done with it so we don't kill the db cache
727 if (m_db) m_db->Close(true /* commit in case we downloaded new headers */);
728 m_db = nullptr;
729 return nsMsgSearchAdapter::Abort();
730 }
731
732 /* void OnStartRunningUrl (in nsIURI url); */
OnStartRunningUrl(nsIURI * url)733 NS_IMETHODIMP nsMsgSearchOfflineMail::OnStartRunningUrl(nsIURI* url) {
734 return NS_OK;
735 }
736
737 /* void OnStopRunningUrl (in nsIURI url, in nsresult aExitCode); */
OnStopRunningUrl(nsIURI * url,nsresult aExitCode)738 NS_IMETHODIMP nsMsgSearchOfflineMail::OnStopRunningUrl(nsIURI* url,
739 nsresult aExitCode) {
740 nsCOMPtr<nsIMsgSearchSession> searchSession;
741 if (m_scope) m_scope->GetSearchSession(getter_AddRefs(searchSession));
742 if (searchSession) searchSession->ResumeSearch();
743
744 return NS_OK;
745 }
746
nsMsgSearchOfflineNews(nsIMsgSearchScopeTerm * scope,nsTArray<RefPtr<nsIMsgSearchTerm>> const & termList)747 nsMsgSearchOfflineNews::nsMsgSearchOfflineNews(
748 nsIMsgSearchScopeTerm* scope,
749 nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList)
750 : nsMsgSearchOfflineMail(scope, termList) {}
751
~nsMsgSearchOfflineNews()752 nsMsgSearchOfflineNews::~nsMsgSearchOfflineNews() {}
753
OpenSummaryFile()754 nsresult nsMsgSearchOfflineNews::OpenSummaryFile() {
755 nsresult err = NS_OK;
756 nsCOMPtr<nsIDBFolderInfo> folderInfo;
757 nsCOMPtr<nsIMsgFolder> scopeFolder;
758 err = m_scope->GetFolder(getter_AddRefs(scopeFolder));
759 // code here used to check if offline store existed, which breaks offline
760 // news.
761 if (NS_SUCCEEDED(err) && scopeFolder)
762 err = scopeFolder->GetMsgDatabase(getter_AddRefs(m_db));
763 return err;
764 }
765
ValidateTerms()766 nsresult nsMsgSearchOfflineNews::ValidateTerms() {
767 return nsMsgSearchOfflineMail::ValidateTerms();
768 }
769
770 // local helper functions to set subsets of the validity table
771 // clang-format off
SetJunk(nsIMsgSearchValidityTable * aTable)772 nsresult SetJunk(nsIMsgSearchValidityTable *aTable) {
773 NS_ENSURE_ARG_POINTER(aTable);
774
775 aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
776 aTable->SetEnabled (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Is, 1);
777 aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
778 aTable->SetEnabled (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::Isnt, 1);
779 aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
780 aTable->SetEnabled (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsEmpty, 1);
781 aTable->SetAvailable(nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
782 aTable->SetEnabled (nsMsgSearchAttrib::JunkStatus, nsMsgSearchOp::IsntEmpty, 1);
783
784 aTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
785 aTable->SetEnabled (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsGreaterThan, 1);
786 aTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
787 aTable->SetEnabled (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::IsLessThan, 1);
788 aTable->SetAvailable(nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
789 aTable->SetEnabled (nsMsgSearchAttrib::JunkPercent, nsMsgSearchOp::Is, 1);
790
791 aTable->SetAvailable(nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Is, 1);
792 aTable->SetEnabled (nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Is, 1);
793 aTable->SetAvailable(nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Isnt, 1);
794 aTable->SetEnabled (nsMsgSearchAttrib::JunkScoreOrigin, nsMsgSearchOp::Isnt, 1);
795
796 return NS_OK;
797 }
798
SetBody(nsIMsgSearchValidityTable * aTable)799 nsresult SetBody(nsIMsgSearchValidityTable* aTable) {
800 NS_ENSURE_ARG_POINTER(aTable);
801
802 aTable->SetAvailable(nsMsgSearchAttrib::Body, nsMsgSearchOp::Contains, 1);
803 aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Contains, 1);
804 aTable->SetAvailable(nsMsgSearchAttrib::Body, nsMsgSearchOp::DoesntContain, 1);
805 aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::DoesntContain, 1);
806 aTable->SetAvailable(nsMsgSearchAttrib::Body, nsMsgSearchOp::Is, 1);
807 aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Is, 1);
808 aTable->SetAvailable(nsMsgSearchAttrib::Body, nsMsgSearchOp::Isnt, 1);
809 aTable->SetEnabled (nsMsgSearchAttrib::Body, nsMsgSearchOp::Isnt, 1);
810
811 return NS_OK;
812 }
813
814 // set the base validity table values for local news
SetLocalNews(nsIMsgSearchValidityTable * aTable)815 nsresult SetLocalNews(nsIMsgSearchValidityTable* aTable) {
816 NS_ENSURE_ARG_POINTER(aTable);
817
818 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
819 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
820 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1);
821 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1);
822 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
823 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
824 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1);
825 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1);
826 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
827 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
828 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
829 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
830 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1);
831 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1);
832 aTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
833 aTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
834
835 aTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
836 aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
837 aTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1);
838 aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1);
839 aTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
840 aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
841 aTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1);
842 aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1);
843 aTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
844 aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
845 aTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
846 aTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
847
848 aTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1);
849 aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1);
850 aTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1);
851 aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1);
852 aTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1);
853 aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1);
854 aTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1);
855 aTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1);
856
857 aTable->SetAvailable(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, 1);
858 aTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsGreaterThan, 1);
859 aTable->SetAvailable(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1);
860 aTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, 1);
861 aTable->SetAvailable(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1);
862 aTable->SetEnabled (nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::Is, 1);
863
864 aTable->SetAvailable(nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Is, 1);
865 aTable->SetEnabled (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Is, 1);
866 aTable->SetAvailable(nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, 1);
867 aTable->SetEnabled (nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, 1);
868
869 aTable->SetAvailable(nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1);
870 aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Contains, 1);
871 aTable->SetAvailable(nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1);
872 aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::DoesntContain, 1);
873 aTable->SetAvailable(nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1);
874 aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Is, 1);
875 aTable->SetAvailable(nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1);
876 aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::Isnt, 1);
877 aTable->SetAvailable(nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsEmpty, 1);
878 aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsEmpty, 1);
879 aTable->SetAvailable(nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsntEmpty, 1);
880 aTable->SetEnabled (nsMsgSearchAttrib::Keywords, nsMsgSearchOp::IsntEmpty, 1);
881
882 aTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
883 aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
884 aTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1);
885 aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1);
886 aTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
887 aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
888 aTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Isnt, 1);
889 aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Isnt, 1);
890 aTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1);
891 aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1);
892 aTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
893 aTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
894 return NS_OK;
895 }
896 // clang-format on
897
InitLocalNewsTable()898 nsresult nsMsgSearchValidityManager::InitLocalNewsTable() {
899 NS_ASSERTION(nullptr == m_localNewsTable,
900 "already have local news validity table");
901 nsresult rv = NewTable(getter_AddRefs(m_localNewsTable));
902 NS_ENSURE_SUCCESS(rv, rv);
903 return SetLocalNews(m_localNewsTable);
904 }
905
InitLocalNewsBodyTable()906 nsresult nsMsgSearchValidityManager::InitLocalNewsBodyTable() {
907 NS_ASSERTION(nullptr == m_localNewsBodyTable,
908 "already have local news+body validity table");
909 nsresult rv = NewTable(getter_AddRefs(m_localNewsBodyTable));
910 NS_ENSURE_SUCCESS(rv, rv);
911 rv = SetLocalNews(m_localNewsBodyTable);
912 NS_ENSURE_SUCCESS(rv, rv);
913 return SetBody(m_localNewsBodyTable);
914 }
915
InitLocalNewsJunkTable()916 nsresult nsMsgSearchValidityManager::InitLocalNewsJunkTable() {
917 NS_ASSERTION(nullptr == m_localNewsJunkTable,
918 "already have local news+junk validity table");
919 nsresult rv = NewTable(getter_AddRefs(m_localNewsJunkTable));
920 NS_ENSURE_SUCCESS(rv, rv);
921 rv = SetLocalNews(m_localNewsJunkTable);
922 NS_ENSURE_SUCCESS(rv, rv);
923 return SetJunk(m_localNewsJunkTable);
924 }
925
InitLocalNewsJunkBodyTable()926 nsresult nsMsgSearchValidityManager::InitLocalNewsJunkBodyTable() {
927 NS_ASSERTION(nullptr == m_localNewsJunkBodyTable,
928 "already have local news+junk+body validity table");
929 nsresult rv = NewTable(getter_AddRefs(m_localNewsJunkBodyTable));
930 NS_ENSURE_SUCCESS(rv, rv);
931 rv = SetLocalNews(m_localNewsJunkBodyTable);
932 NS_ENSURE_SUCCESS(rv, rv);
933 rv = SetJunk(m_localNewsJunkBodyTable);
934 NS_ENSURE_SUCCESS(rv, rv);
935 return SetBody(m_localNewsJunkBodyTable);
936 }
937