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 #include "msgCore.h"
6 #include "nsMsgSearchAdapter.h"
7 #include "nsUnicharUtils.h"
8 #include "nsMsgSearchScopeTerm.h"
9 #include "nsMsgResultElement.h"
10 #include "nsMsgSearchTerm.h"
11 #include "nsIMsgHdr.h"
12 #include "nsMsgSearchNews.h"
13 #include "nsIDBFolderInfo.h"
14 #include "prprf.h"
15 #include "nsIMsgDatabase.h"
16 #include "nsMemory.h"
17 #include <ctype.h>
18
19 // Implementation of search for IMAP mail folders
20
21 // Implementation of search for newsgroups
22
23 //-----------------------------------------------------------------------------
24 //----------- Adapter class for searching XPAT-capable news servers -----------
25 //-----------------------------------------------------------------------------
26
27 const char* nsMsgSearchNews::m_kNntpFrom = "FROM ";
28 const char* nsMsgSearchNews::m_kNntpSubject = "SUBJECT ";
29 const char* nsMsgSearchNews::m_kTermSeparator = "/";
30
nsMsgSearchNews(nsMsgSearchScopeTerm * scope,nsTArray<RefPtr<nsIMsgSearchTerm>> const & termList)31 nsMsgSearchNews::nsMsgSearchNews(
32 nsMsgSearchScopeTerm* scope,
33 nsTArray<RefPtr<nsIMsgSearchTerm>> const& termList)
34 : nsMsgSearchAdapter(scope, termList) {
35 m_searchType = ST_UNINITIALIZED;
36 }
37
~nsMsgSearchNews()38 nsMsgSearchNews::~nsMsgSearchNews() {}
39
ValidateTerms()40 nsresult nsMsgSearchNews::ValidateTerms() {
41 nsresult err = nsMsgSearchAdapter::ValidateTerms();
42 if (NS_OK == err) {
43 err = Encode(&m_encoding);
44 }
45
46 return err;
47 }
48
Search(bool * aDone)49 nsresult nsMsgSearchNews::Search(bool* aDone) {
50 // the state machine runs in the news: handler
51 nsresult err = NS_ERROR_NOT_IMPLEMENTED;
52 return err;
53 }
54
EncodeToWildmat(const char16_t * value)55 char16_t* nsMsgSearchNews::EncodeToWildmat(const char16_t* value) {
56 // Here we take advantage of XPAT's use of the wildmat format, which allows
57 // a case-insensitive match by specifying each case possibility for each
58 // character So, "FooBar" is encoded as "[Ff][Oo][Bb][Aa][Rr]"
59
60 char16_t* caseInsensitiveValue =
61 (char16_t*)moz_xmalloc(sizeof(char16_t) * ((4 * NS_strlen(value)) + 1));
62 if (caseInsensitiveValue) {
63 char16_t* walkValue = caseInsensitiveValue;
64 while (*value) {
65 if (isalpha(*value)) {
66 *walkValue++ = (char16_t)'[';
67 *walkValue++ = ToUpperCase((char16_t)*value);
68 *walkValue++ = ToLowerCase((char16_t)*value);
69 *walkValue++ = (char16_t)']';
70 } else
71 *walkValue++ = *value;
72 value++;
73 }
74 *walkValue = 0;
75 }
76 return caseInsensitiveValue;
77 }
78
EncodeTerm(nsIMsgSearchTerm * term)79 char* nsMsgSearchNews::EncodeTerm(nsIMsgSearchTerm* term) {
80 // Develop an XPAT-style encoding for the search term
81
82 NS_ASSERTION(term, "null term");
83 if (!term) return nullptr;
84
85 // Find a string to represent the attribute
86 const char* attribEncoding = nullptr;
87 nsMsgSearchAttribValue attrib;
88
89 term->GetAttrib(&attrib);
90
91 switch (attrib) {
92 case nsMsgSearchAttrib::Sender:
93 attribEncoding = m_kNntpFrom;
94 break;
95 case nsMsgSearchAttrib::Subject:
96 attribEncoding = m_kNntpSubject;
97 break;
98 default:
99 nsCString header;
100 term->GetArbitraryHeader(header);
101 if (header.IsEmpty()) {
102 NS_ASSERTION(false, "malformed search"); // malformed search term?
103 return nullptr;
104 }
105 attribEncoding = header.get();
106 }
107
108 // Build a string to represent the string pattern
109 bool leadingStar = false;
110 bool trailingStar = false;
111 nsMsgSearchOpValue op;
112 term->GetOp(&op);
113
114 switch (op) {
115 case nsMsgSearchOp::Contains:
116 leadingStar = true;
117 trailingStar = true;
118 break;
119 case nsMsgSearchOp::Is:
120 break;
121 case nsMsgSearchOp::BeginsWith:
122 trailingStar = true;
123 break;
124 case nsMsgSearchOp::EndsWith:
125 leadingStar = true;
126 break;
127 default:
128 NS_ASSERTION(false, "malformed search"); // malformed search term?
129 return nullptr;
130 }
131
132 // ### i18N problem Get the csid from FE, which is the correct csid for term
133 // int16 wincsid = INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel);
134
135 // Do INTL_FormatNNTPXPATInRFC1522Format trick for non-ASCII string
136 // unsigned char *intlNonRFC1522Value = INTL_FormatNNTPXPATInNonRFC1522Format
137 // (wincsid, (unsigned char*)term->m_value.u.string);
138 nsCOMPtr<nsIMsgSearchValue> searchValue;
139
140 nsresult rv = term->GetValue(getter_AddRefs(searchValue));
141 if (NS_FAILED(rv) || !searchValue) return nullptr;
142
143 nsString intlNonRFC1522Value;
144 rv = searchValue->GetStr(intlNonRFC1522Value);
145 if (NS_FAILED(rv) || intlNonRFC1522Value.IsEmpty()) return nullptr;
146
147 char16_t* caseInsensitiveValue = EncodeToWildmat(intlNonRFC1522Value.get());
148 if (!caseInsensitiveValue) return nullptr;
149
150 // TO DO: Do INTL_FormatNNTPXPATInRFC1522Format trick for non-ASCII string
151 // Unfortunately, we currently do not handle xxx or xxx search in XPAT
152 // Need to add the INTL_FormatNNTPXPATInRFC1522Format call after we can do
153 // that so we should search a string in either RFC1522 format and non-RFC1522
154 // format
155
156 char16_t* escapedValue = EscapeSearchUrl(caseInsensitiveValue);
157 free(caseInsensitiveValue);
158 if (!escapedValue) return nullptr;
159
160 nsAutoCString pattern;
161
162 if (leadingStar) pattern.Append('*');
163 pattern.Append(NS_ConvertUTF16toUTF8(escapedValue));
164 if (trailingStar) pattern.Append('*');
165
166 // Combine the XPAT command syntax with the attribute and the pattern to
167 // form the term encoding
168 const char xpatTemplate[] = "XPAT %s 1- %s";
169 int termLength = (sizeof(xpatTemplate) - 1) + strlen(attribEncoding) +
170 pattern.Length() + 1;
171 char* termEncoding = new char[termLength];
172 if (termEncoding)
173 PR_snprintf(termEncoding, termLength, xpatTemplate, attribEncoding,
174 pattern.get());
175
176 return termEncoding;
177 }
178
GetEncoding(char ** result)179 nsresult nsMsgSearchNews::GetEncoding(char** result) {
180 NS_ENSURE_ARG(result);
181 *result = ToNewCString(m_encoding);
182 return (*result) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
183 }
184
Encode(nsCString * outEncoding)185 nsresult nsMsgSearchNews::Encode(nsCString* outEncoding) {
186 NS_ASSERTION(outEncoding, "no out encoding");
187 if (!outEncoding) return NS_ERROR_NULL_POINTER;
188
189 nsresult err = NS_OK;
190
191 uint32_t numTerms = m_searchTerms.Length();
192
193 char** intermediateEncodings = new char*[numTerms];
194 if (intermediateEncodings) {
195 // Build an XPAT command for each term
196 int encodingLength = 0;
197 for (uint32_t i = 0; i < numTerms; i++) {
198 nsIMsgSearchTerm* pTerm = m_searchTerms[i];
199 // set boolean OR term if any of the search terms are an OR...this only
200 // works if we are using homogeneous boolean operators.
201 bool isBooleanOpAnd;
202 pTerm->GetBooleanAnd(&isBooleanOpAnd);
203 m_searchType = isBooleanOpAnd ? ST_AND_SEARCH : ST_OR_SEARCH;
204
205 intermediateEncodings[i] = EncodeTerm(pTerm);
206 if (intermediateEncodings[i])
207 encodingLength +=
208 strlen(intermediateEncodings[i]) + strlen(m_kTermSeparator);
209 }
210 encodingLength += strlen("?search");
211 // Combine all the term encodings into one big encoding
212 char* encoding = new char[encodingLength + 1];
213 if (encoding) {
214 PL_strcpy(encoding, "?search");
215
216 for (uint32_t i = 0; i < numTerms; i++) {
217 if (intermediateEncodings[i]) {
218 PL_strcat(encoding, m_kTermSeparator);
219 PL_strcat(encoding, intermediateEncodings[i]);
220 delete[] intermediateEncodings[i];
221 }
222 }
223 *outEncoding = encoding;
224 } else
225 err = NS_ERROR_OUT_OF_MEMORY;
226 } else
227 err = NS_ERROR_OUT_OF_MEMORY;
228 delete[] intermediateEncodings;
229
230 return err;
231 }
232
AddHit(nsMsgKey key)233 NS_IMETHODIMP nsMsgSearchNews::AddHit(nsMsgKey key) {
234 m_candidateHits.AppendElement(key);
235 return NS_OK;
236 }
237
238 /* void CurrentUrlDone (in nsresult exitCode); */
CurrentUrlDone(nsresult exitCode)239 NS_IMETHODIMP nsMsgSearchNews::CurrentUrlDone(nsresult exitCode) {
240 CollateHits();
241 ReportHits();
242 return NS_OK;
243 }
244
245 #if 0 // need to switch this to a notify stop loading handler, I think.
246 void nsMsgSearchNews::PreExitFunction (URL_Struct * /*url*/, int status, MWContext *context)
247 {
248 MSG_SearchFrame *frame = MSG_SearchFrame::FromContext (context);
249 nsMsgSearchNews *adapter = (nsMsgSearchNews*) frame->GetRunningAdapter();
250 adapter->CollateHits();
251 adapter->ReportHits();
252
253 if (status == MK_INTERRUPTED)
254 {
255 adapter->Abort();
256 frame->EndCylonMode();
257 }
258 else
259 {
260 frame->m_idxRunningScope++;
261 if (frame->m_idxRunningScope >= frame->m_scopeList.Count())
262 frame->EndCylonMode();
263 }
264 }
265 #endif // 0
266
CollateHits()267 void nsMsgSearchNews::CollateHits() {
268 // Since the XPAT commands are processed one at a time, the result set for the
269 // entire query is the intersection of results for each XPAT command if an AND
270 // search, otherwise we want the union of all the search hits (minus the
271 // duplicates of course).
272
273 uint32_t size = m_candidateHits.Length();
274 if (!size) return;
275
276 // Sort the article numbers first, so it's easy to tell how many hits
277 // on a given article we got
278 m_candidateHits.Sort();
279
280 // For an OR search we only need to count the first occurrence of a candidate.
281 uint32_t termCount = 1;
282 MOZ_ASSERT(m_searchType != ST_UNINITIALIZED,
283 "m_searchType accessed without being set");
284 if (m_searchType == ST_AND_SEARCH) {
285 // We have a traditional AND search which must be collated. In order to
286 // get promoted into the hits list, a candidate article number must appear
287 // in the results of each XPAT command. So if we fire 3 XPAT commands (one
288 // per search term), the article number must appear 3 times. If it appears
289 // fewer than 3 times, it matched some search terms, but not all.
290 termCount = m_searchTerms.Length();
291 }
292 uint32_t candidateCount = 0;
293 uint32_t candidate = m_candidateHits[0];
294 for (uint32_t index = 0; index < size; ++index) {
295 uint32_t possibleCandidate = m_candidateHits[index];
296 if (candidate == possibleCandidate) {
297 ++candidateCount;
298 } else {
299 candidateCount = 1;
300 candidate = possibleCandidate;
301 }
302 if (candidateCount == termCount) m_hits.AppendElement(candidate);
303 }
304 }
305
ReportHits()306 void nsMsgSearchNews::ReportHits() {
307 nsCOMPtr<nsIMsgDatabase> db;
308 nsCOMPtr<nsIDBFolderInfo> folderInfo;
309 nsCOMPtr<nsIMsgFolder> scopeFolder;
310
311 nsresult err = m_scope->GetFolder(getter_AddRefs(scopeFolder));
312 if (NS_SUCCEEDED(err) && scopeFolder) {
313 err = scopeFolder->GetDBFolderInfoAndDB(getter_AddRefs(folderInfo),
314 getter_AddRefs(db));
315 }
316
317 if (db) {
318 uint32_t size = m_hits.Length();
319 for (uint32_t i = 0; i < size; ++i) {
320 nsCOMPtr<nsIMsgDBHdr> header;
321
322 db->GetMsgHdrForKey(m_hits.ElementAt(i), getter_AddRefs(header));
323 if (header) ReportHit(header, scopeFolder);
324 }
325 }
326 }
327
328 // ### this should take an nsIMsgFolder instead of a string location.
ReportHit(nsIMsgDBHdr * pHeaders,nsIMsgFolder * folder)329 void nsMsgSearchNews::ReportHit(nsIMsgDBHdr* pHeaders, nsIMsgFolder* folder) {
330 // this is totally filched from msg_SearchOfflineMail until I decide whether
331 // the right thing is to get them from the db or from NNTP
332 nsCOMPtr<nsIMsgSearchSession> session;
333 nsCOMPtr<nsIMsgFolder> scopeFolder;
334 m_scope->GetFolder(getter_AddRefs(scopeFolder));
335 m_scope->GetSearchSession(getter_AddRefs(session));
336 if (session) session->AddSearchHit(pHeaders, scopeFolder);
337 }
338
InitNewsTable()339 nsresult nsMsgSearchValidityManager::InitNewsTable() {
340 NS_ASSERTION(nullptr == m_newsTable, "don't call this twice!");
341 nsresult rv = NewTable(getter_AddRefs(m_newsTable));
342
343 if (NS_SUCCEEDED(rv)) {
344 // clang-format off
345 m_newsTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
346 m_newsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
347 m_newsTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
348 m_newsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
349 m_newsTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
350 m_newsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
351 m_newsTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
352 m_newsTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
353
354 m_newsTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
355 m_newsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
356 m_newsTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
357 m_newsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
358 m_newsTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
359 m_newsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
360 m_newsTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
361 m_newsTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
362
363 #if 0
364 // Size should be handled after the fact...
365 m_newsTable->SetAvailable(nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1);
366 m_newsTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1);
367 m_newsTable->SetAvailable(nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
368 m_newsTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
369 #endif
370 m_newsTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
371 m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
372 m_newsTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
373 m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
374 m_newsTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1);
375 m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1);
376 m_newsTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
377 m_newsTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
378 // clang-format on
379 }
380
381 return rv;
382 }
383
InitNewsFilterTable()384 nsresult nsMsgSearchValidityManager::InitNewsFilterTable() {
385 NS_ASSERTION(nullptr == m_newsFilterTable,
386 "news filter table already initted");
387 nsresult rv = NewTable(getter_AddRefs(m_newsFilterTable));
388
389 if (NS_SUCCEEDED(rv)) {
390 // clang-format off
391 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
392 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Contains, 1);
393 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1);
394 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::DoesntContain, 1);
395 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
396 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Is, 1);
397 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1);
398 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::Isnt, 1);
399 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
400 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::BeginsWith, 1);
401 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
402 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::EndsWith, 1);
403
404 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1);
405 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsInAB, 1);
406 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
407 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Sender, nsMsgSearchOp::IsntInAB, 1);
408
409 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
410 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Contains, 1);
411 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1);
412 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::DoesntContain, 1);
413 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
414 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Is, 1);
415 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1);
416 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::Isnt, 1);
417 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
418 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::BeginsWith, 1);
419 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
420 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Subject, nsMsgSearchOp::EndsWith, 1);
421
422 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1);
423 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsBefore, 1);
424 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1);
425 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::IsAfter, 1);
426 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1);
427 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Is, 1);
428 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1);
429 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Date, nsMsgSearchOp::Isnt, 1);
430
431 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1);
432 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsGreaterThan, 1);
433 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
434 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::Size, nsMsgSearchOp::IsLessThan, 1);
435
436 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
437 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Contains, 1);
438 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1);
439 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::DoesntContain, 1);
440 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
441 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Is, 1);
442 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Isnt, 1);
443 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::Isnt, 1);
444 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1);
445 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::BeginsWith, 1);
446 m_newsFilterTable->SetAvailable(nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
447 m_newsFilterTable->SetEnabled (nsMsgSearchAttrib::OtherHeader, nsMsgSearchOp::EndsWith, 1);
448 // clang-format on
449 }
450
451 return rv;
452 }
453