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 #include "msgCore.h"
7 #include "nsTextFormatter.h"
8 #include "nsMsgSearchCore.h"
9 #include "nsMsgSearchAdapter.h"
10 #include "nsMsgSearchScopeTerm.h"
11 #include "nsMsgI18N.h"
12 #include "nsIPrefService.h"
13 #include "nsIPrefBranch.h"
14 #include "nsIPrefLocalizedString.h"
15 #include "nsMsgSearchTerm.h"
16 #include "nsMsgSearchBoolExpression.h"
17 #include "nsIIOService.h"
18 #include "nsNetCID.h"
19 #include "prprf.h"
20 #include "mozilla/UniquePtr.h"
21 #include "prmem.h"
22 #include "MailNewsTypes.h"
23 #include "nsComponentManagerUtils.h"
24 #include "nsServiceManagerUtils.h"
25 #include "nsMemory.h"
26 #include "nsMsgMessageFlags.h"
27 #include "mozilla/Attributes.h"
28 #include "nsIMsgNewsFolder.h"
29
30 // This stuff lives in the base class because the IMAP search syntax
31 // is used by the Dredd SEARCH command as well as IMAP itself
32
33 // km - the NOT and HEADER strings are not encoded with a trailing
34 // <space> because they always precede a mnemonic that has a
35 // preceding <space> and double <space> characters cause some
36 // imap servers to return an error.
37 const char* nsMsgSearchAdapter::m_kImapBefore = " SENTBEFORE ";
38 const char* nsMsgSearchAdapter::m_kImapBody = " BODY ";
39 const char* nsMsgSearchAdapter::m_kImapCC = " CC ";
40 const char* nsMsgSearchAdapter::m_kImapFrom = " FROM ";
41 const char* nsMsgSearchAdapter::m_kImapNot = " NOT";
42 const char* nsMsgSearchAdapter::m_kImapUnDeleted = " UNDELETED";
43 const char* nsMsgSearchAdapter::m_kImapOr = " OR";
44 const char* nsMsgSearchAdapter::m_kImapSince = " SENTSINCE ";
45 const char* nsMsgSearchAdapter::m_kImapSubject = " SUBJECT ";
46 const char* nsMsgSearchAdapter::m_kImapTo = " TO ";
47 const char* nsMsgSearchAdapter::m_kImapHeader = " HEADER";
48 const char* nsMsgSearchAdapter::m_kImapAnyText = " TEXT ";
49 const char* nsMsgSearchAdapter::m_kImapKeyword = " KEYWORD ";
50 const char* nsMsgSearchAdapter::m_kNntpKeywords = " KEYWORDS "; // ggrrrr...
51 const char* nsMsgSearchAdapter::m_kImapSentOn = " SENTON ";
52 const char* nsMsgSearchAdapter::m_kImapSeen = " SEEN ";
53 const char* nsMsgSearchAdapter::m_kImapAnswered = " ANSWERED ";
54 const char* nsMsgSearchAdapter::m_kImapNotSeen = " UNSEEN ";
55 const char* nsMsgSearchAdapter::m_kImapNotAnswered = " UNANSWERED ";
56 const char* nsMsgSearchAdapter::m_kImapCharset = " CHARSET ";
57 const char* nsMsgSearchAdapter::m_kImapSizeSmaller = " SMALLER ";
58 const char* nsMsgSearchAdapter::m_kImapSizeLarger = " LARGER ";
59 const char* nsMsgSearchAdapter::m_kImapNew = " NEW ";
60 const char* nsMsgSearchAdapter::m_kImapNotNew = " OLD SEEN ";
61 const char* nsMsgSearchAdapter::m_kImapFlagged = " FLAGGED ";
62 const char* nsMsgSearchAdapter::m_kImapNotFlagged = " UNFLAGGED ";
63
64 #define PREF_CUSTOM_HEADERS "mailnews.customHeaders"
65
FindTargetFolder(const nsMsgResultElement *,nsIMsgFolder **)66 NS_IMETHODIMP nsMsgSearchAdapter::FindTargetFolder(const nsMsgResultElement*,
67 nsIMsgFolder**) {
68 return NS_ERROR_NOT_IMPLEMENTED;
69 }
70
ModifyResultElement(nsMsgResultElement *,nsMsgSearchValue *)71 NS_IMETHODIMP nsMsgSearchAdapter::ModifyResultElement(nsMsgResultElement*,
72 nsMsgSearchValue*) {
73 return NS_ERROR_NOT_IMPLEMENTED;
74 }
75
OpenResultElement(nsMsgResultElement *)76 NS_IMETHODIMP nsMsgSearchAdapter::OpenResultElement(nsMsgResultElement*) {
77 return NS_ERROR_NOT_IMPLEMENTED;
78 }
79
NS_IMPL_ISUPPORTS(nsMsgSearchAdapter,nsIMsgSearchAdapter)80 NS_IMPL_ISUPPORTS(nsMsgSearchAdapter, nsIMsgSearchAdapter)
81
82 nsMsgSearchAdapter::nsMsgSearchAdapter(
83 nsIMsgSearchScopeTerm* scope,
84 nsTArray<RefPtr<nsIMsgSearchTerm>> const& searchTerms)
85 : m_scope(scope), m_searchTerms(searchTerms.Clone()) {}
86
~nsMsgSearchAdapter()87 nsMsgSearchAdapter::~nsMsgSearchAdapter() {}
88
ClearScope()89 NS_IMETHODIMP nsMsgSearchAdapter::ClearScope() {
90 if (m_scope) {
91 m_scope->CloseInputStream();
92 m_scope = nullptr;
93 }
94 return NS_OK;
95 }
96
ValidateTerms()97 NS_IMETHODIMP nsMsgSearchAdapter::ValidateTerms() {
98 // all this used to do is check if the object had been deleted - we can skip
99 // that.
100 return NS_OK;
101 }
102
Abort()103 NS_IMETHODIMP nsMsgSearchAdapter::Abort() { return NS_ERROR_NOT_IMPLEMENTED; }
Search(bool * aDone)104 NS_IMETHODIMP nsMsgSearchAdapter::Search(bool* aDone) { return NS_OK; }
105
SendUrl()106 NS_IMETHODIMP nsMsgSearchAdapter::SendUrl() { return NS_OK; }
107
108 /* void CurrentUrlDone (in nsresult exitCode); */
CurrentUrlDone(nsresult exitCode)109 NS_IMETHODIMP nsMsgSearchAdapter::CurrentUrlDone(nsresult exitCode) {
110 // base implementation doesn't need to do anything.
111 return NS_OK;
112 }
113
GetEncoding(char ** encoding)114 NS_IMETHODIMP nsMsgSearchAdapter::GetEncoding(char** encoding) { return NS_OK; }
115
AddResultElement(nsIMsgDBHdr * pHeaders)116 NS_IMETHODIMP nsMsgSearchAdapter::AddResultElement(nsIMsgDBHdr* pHeaders) {
117 NS_ASSERTION(false, "shouldn't call this base class impl");
118 return NS_ERROR_FAILURE;
119 }
120
AddHit(nsMsgKey key)121 NS_IMETHODIMP nsMsgSearchAdapter::AddHit(nsMsgKey key) {
122 NS_ASSERTION(false, "shouldn't call this base class impl");
123 return NS_ERROR_FAILURE;
124 }
125
GetImapCharsetParam(const char16_t * destCharset)126 char* nsMsgSearchAdapter::GetImapCharsetParam(const char16_t* destCharset) {
127 char* result = nullptr;
128
129 // Specify a character set unless we happen to be US-ASCII.
130 if (NS_strcmp(destCharset, u"us-ascii"))
131 result = PR_smprintf("%s%s", nsMsgSearchAdapter::m_kImapCharset,
132 NS_ConvertUTF16toUTF8(destCharset).get());
133
134 return result;
135 }
136
137 /*
138 09/21/2000 - taka@netscape.com
139 This method is bogus. Escape must be done against char * not char16_t *
140 should be rewritten later.
141 for now, just duplicate the string.
142 */
EscapeSearchUrl(const char16_t * nntpCommand)143 char16_t* nsMsgSearchAdapter::EscapeSearchUrl(const char16_t* nntpCommand) {
144 return nntpCommand ? NS_xstrdup(nntpCommand) : nullptr;
145 }
146
147 /*
148 09/21/2000 - taka@netscape.com
149 This method is bogus. Escape must be done against char * not char16_t *
150 should be rewritten later.
151 for now, just duplicate the string.
152 */
EscapeImapSearchProtocol(const char16_t * imapCommand)153 char16_t* nsMsgSearchAdapter::EscapeImapSearchProtocol(
154 const char16_t* imapCommand) {
155 return imapCommand ? NS_xstrdup(imapCommand) : nullptr;
156 }
157
158 /*
159 09/21/2000 - taka@netscape.com
160 This method is bogus. Escape must be done against char * not char16_t *
161 should be rewritten later.
162 for now, just duplicate the string.
163 */
EscapeQuoteImapSearchProtocol(const char16_t * imapCommand)164 char16_t* nsMsgSearchAdapter::EscapeQuoteImapSearchProtocol(
165 const char16_t* imapCommand) {
166 return imapCommand ? NS_xstrdup(imapCommand) : nullptr;
167 }
168
UnEscapeSearchUrl(const char * commandSpecificData)169 char* nsMsgSearchAdapter::UnEscapeSearchUrl(const char* commandSpecificData) {
170 char* result = (char*)PR_Malloc(strlen(commandSpecificData) + 1);
171 if (result) {
172 char* resultPtr = result;
173 while (1) {
174 char ch = *commandSpecificData++;
175 if (!ch) break;
176 if (ch == '\\') {
177 char scratchBuf[3];
178 scratchBuf[0] = (char)*commandSpecificData++;
179 scratchBuf[1] = (char)*commandSpecificData++;
180 scratchBuf[2] = '\0';
181 unsigned int accum = 0;
182 sscanf(scratchBuf, "%X", &accum);
183 *resultPtr++ = (char)accum;
184 } else
185 *resultPtr++ = ch;
186 }
187 *resultPtr = '\0';
188 }
189 return result;
190 }
191
GetSearchCharsets(nsAString & srcCharset,nsAString & dstCharset)192 nsresult nsMsgSearchAdapter::GetSearchCharsets(nsAString& srcCharset,
193 nsAString& dstCharset) {
194 nsresult rv;
195 bool forceAsciiSearch = false;
196
197 nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
198 if (NS_SUCCEEDED(rv)) {
199 prefs->GetBoolPref("mailnews.force_ascii_search", &forceAsciiSearch);
200 }
201
202 srcCharset = m_defaultCharset;
203 dstCharset.Assign(srcCharset);
204
205 if (m_scope) {
206 nsCOMPtr<nsIMsgFolder> folder;
207 rv = m_scope->GetFolder(getter_AddRefs(folder));
208 if (NS_SUCCEEDED(rv) && folder) {
209 nsCOMPtr<nsIMsgNewsFolder> newsfolder(do_QueryInterface(folder));
210 if (newsfolder) {
211 nsCString folderCharset;
212 rv = newsfolder->GetCharset(folderCharset);
213 if (NS_SUCCEEDED(rv))
214 dstCharset.Assign(NS_ConvertASCIItoUTF16(folderCharset));
215 }
216 }
217 }
218
219 if (forceAsciiSearch) {
220 // Special cases to use in order to force US-ASCII searching with Latin1
221 // or MacRoman text. Eurgh. This only has to happen because IMAP
222 // and Dredd servers currently (4/23/97) only support US-ASCII.
223 //
224 // If the dest csid is ISO Latin 1 or MacRoman, attempt to convert the
225 // source text to US-ASCII. (Not for now.)
226 // if ((dst_csid == CS_LATIN1) || (dst_csid == CS_MAC_ROMAN))
227 dstCharset.AssignLiteral("us-ascii");
228 }
229
230 return NS_OK;
231 }
232
EncodeImapTerm(nsIMsgSearchTerm * term,bool reallyDredd,const char16_t * srcCharset,const char16_t * destCharset,char ** ppOutTerm)233 nsresult nsMsgSearchAdapter::EncodeImapTerm(nsIMsgSearchTerm* term,
234 bool reallyDredd,
235 const char16_t* srcCharset,
236 const char16_t* destCharset,
237 char** ppOutTerm) {
238 NS_ENSURE_ARG_POINTER(term);
239 NS_ENSURE_ARG_POINTER(ppOutTerm);
240
241 nsresult err = NS_OK;
242 bool useNot = false;
243 bool useQuotes = false;
244 bool ignoreValue = false;
245 nsAutoCString arbitraryHeader;
246 const char* whichMnemonic = nullptr;
247 const char* orHeaderMnemonic = nullptr;
248
249 *ppOutTerm = nullptr;
250
251 nsCOMPtr<nsIMsgSearchValue> searchValue;
252 nsresult rv = term->GetValue(getter_AddRefs(searchValue));
253
254 NS_ENSURE_SUCCESS(rv, rv);
255
256 nsMsgSearchOpValue op;
257 term->GetOp(&op);
258
259 if (op == nsMsgSearchOp::DoesntContain || op == nsMsgSearchOp::Isnt)
260 useNot = true;
261
262 nsMsgSearchAttribValue attrib;
263 term->GetAttrib(&attrib);
264
265 switch (attrib) {
266 case nsMsgSearchAttrib::ToOrCC:
267 orHeaderMnemonic = m_kImapCC;
268 // fall through to case nsMsgSearchAttrib::To:
269 [[fallthrough]];
270 case nsMsgSearchAttrib::To:
271 whichMnemonic = m_kImapTo;
272 break;
273 case nsMsgSearchAttrib::CC:
274 whichMnemonic = m_kImapCC;
275 break;
276 case nsMsgSearchAttrib::Sender:
277 whichMnemonic = m_kImapFrom;
278 break;
279 case nsMsgSearchAttrib::Subject:
280 whichMnemonic = m_kImapSubject;
281 break;
282 case nsMsgSearchAttrib::Body:
283 whichMnemonic = m_kImapBody;
284 break;
285 case nsMsgSearchAttrib::AgeInDays: // added for searching online for age in
286 // days...
287 // for AgeInDays, we are actually going to perform a search by date, so
288 // convert the operations for age to the IMAP mnemonics that we would use
289 // for date!
290 {
291 // If we have a future date, the > and < are reversed.
292 // e.g. ageInDays > 2 means more than 2 days old ("date before X")
293 // whereas
294 // ageInDays > -2 should be more than 2 days in the future ("date
295 // after X")
296 int32_t ageInDays;
297 searchValue->GetAge(&ageInDays);
298 bool dateInFuture = (ageInDays < 0);
299 switch (op) {
300 case nsMsgSearchOp::IsGreaterThan:
301 whichMnemonic = (!dateInFuture) ? m_kImapBefore : m_kImapSince;
302 break;
303 case nsMsgSearchOp::IsLessThan:
304 whichMnemonic = (!dateInFuture) ? m_kImapSince : m_kImapBefore;
305 break;
306 case nsMsgSearchOp::Is:
307 whichMnemonic = m_kImapSentOn;
308 break;
309 default:
310 NS_ASSERTION(false, "invalid search operator");
311 return NS_ERROR_INVALID_ARG;
312 }
313 }
314 break;
315 case nsMsgSearchAttrib::Size:
316 switch (op) {
317 case nsMsgSearchOp::IsGreaterThan:
318 whichMnemonic = m_kImapSizeLarger;
319 break;
320 case nsMsgSearchOp::IsLessThan:
321 whichMnemonic = m_kImapSizeSmaller;
322 break;
323 default:
324 NS_ASSERTION(false, "invalid search operator");
325 return NS_ERROR_INVALID_ARG;
326 }
327 break;
328 case nsMsgSearchAttrib::Date:
329 switch (op) {
330 case nsMsgSearchOp::IsBefore:
331 whichMnemonic = m_kImapBefore;
332 break;
333 case nsMsgSearchOp::IsAfter:
334 whichMnemonic = m_kImapSince;
335 break;
336 case nsMsgSearchOp::Isnt: /* we've already added the "Not" so just
337 process it like it was a date is search */
338 case nsMsgSearchOp::Is:
339 whichMnemonic = m_kImapSentOn;
340 break;
341 default:
342 NS_ASSERTION(false, "invalid search operator");
343 return NS_ERROR_INVALID_ARG;
344 }
345 break;
346 case nsMsgSearchAttrib::AnyText:
347 whichMnemonic = m_kImapAnyText;
348 break;
349 case nsMsgSearchAttrib::Keywords:
350 whichMnemonic = m_kImapKeyword;
351 break;
352 case nsMsgSearchAttrib::MsgStatus:
353 useNot = false; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
354 ignoreValue = true; // the mnemonic is all we need
355 uint32_t status;
356 searchValue->GetStatus(&status);
357
358 switch (status) {
359 case nsMsgMessageFlags::Read:
360 whichMnemonic =
361 op == nsMsgSearchOp::Is ? m_kImapSeen : m_kImapNotSeen;
362 break;
363 case nsMsgMessageFlags::Replied:
364 whichMnemonic =
365 op == nsMsgSearchOp::Is ? m_kImapAnswered : m_kImapNotAnswered;
366 break;
367 case nsMsgMessageFlags::New:
368 whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapNew : m_kImapNotNew;
369 break;
370 case nsMsgMessageFlags::Marked:
371 whichMnemonic =
372 op == nsMsgSearchOp::Is ? m_kImapFlagged : m_kImapNotFlagged;
373 break;
374 default:
375 NS_ASSERTION(false, "invalid search operator");
376 return NS_ERROR_INVALID_ARG;
377 }
378 break;
379 default:
380 if (attrib > nsMsgSearchAttrib::OtherHeader &&
381 attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes) {
382 nsCString arbitraryHeaderTerm;
383 term->GetArbitraryHeader(arbitraryHeaderTerm);
384 if (!arbitraryHeaderTerm.IsEmpty()) {
385 arbitraryHeader.AssignLiteral(" \"");
386 arbitraryHeader.Append(arbitraryHeaderTerm);
387 arbitraryHeader.AppendLiteral("\" ");
388 whichMnemonic = arbitraryHeader.get();
389 } else
390 return NS_ERROR_FAILURE;
391 } else {
392 NS_ASSERTION(false, "invalid search operator");
393 return NS_ERROR_INVALID_ARG;
394 }
395 }
396
397 char* value = nullptr;
398 char dateBuf[100];
399 dateBuf[0] = '\0';
400
401 bool valueWasAllocated = false;
402 if (attrib == nsMsgSearchAttrib::Date) {
403 // note that there used to be code here that encoded an RFC822 date for imap
404 // searches. The IMAP RFC 2060 is misleading to the point that it looks like
405 // it requires an RFC822 date but really it expects dd-mmm-yyyy, like dredd,
406 // and refers to the RFC822 date only in that the dd-mmm-yyyy date will
407 // match the RFC822 date within the message.
408
409 PRTime adjustedDate;
410 searchValue->GetDate(&adjustedDate);
411 if (whichMnemonic == m_kImapSince) {
412 // it looks like the IMAP server searches on Since includes the date in
413 // question... our UI presents Is, IsGreater and IsLessThan. For the
414 // IsGreater case (m_kImapSince) we need to adjust the date so we get
415 // greater than and not greater than or equal to which is what the IMAP
416 // server wants to search on won't work on Mac.
417 adjustedDate += PR_USEC_PER_DAY;
418 }
419
420 PRExplodedTime exploded;
421 PR_ExplodeTime(adjustedDate, PR_LocalTimeParameters, &exploded);
422 PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%d-%b-%Y", &exploded);
423 // strftime (dateBuf, sizeof(dateBuf), "%d-%b-%Y", localtime (/*
424 // &term->m_value.u.date */ &adjustedDate));
425 value = dateBuf;
426 } else {
427 if (attrib == nsMsgSearchAttrib::AgeInDays) {
428 // okay, take the current date, subtract off the age in days, then do an
429 // appropriate Date search on the resulting day.
430 int32_t ageInDays;
431
432 searchValue->GetAge(&ageInDays);
433
434 PRTime now = PR_Now();
435 PRTime matchDay = now - ageInDays * PR_USEC_PER_DAY;
436
437 PRExplodedTime exploded;
438 PR_ExplodeTime(matchDay, PR_LocalTimeParameters, &exploded);
439 PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%d-%b-%Y", &exploded);
440 // strftime (dateBuf, sizeof(dateBuf), "%d-%b-%Y", localtime
441 // (&matchDay));
442 value = dateBuf;
443 } else if (attrib == nsMsgSearchAttrib::Size) {
444 uint32_t sizeValue;
445 nsAutoCString searchTermValue;
446 searchValue->GetSize(&sizeValue);
447
448 // Multiply by 1024 to get into kb resolution
449 sizeValue *= 1024;
450
451 // Ensure that greater than is really greater than
452 // in kb resolution.
453 if (op == nsMsgSearchOp::IsGreaterThan) sizeValue += 1024;
454
455 searchTermValue.AppendInt(sizeValue);
456
457 value = ToNewCString(searchTermValue);
458 valueWasAllocated = true;
459 } else
460
461 if (IS_STRING_ATTRIBUTE(attrib)) {
462 char16_t*
463 convertedValue; // = reallyDredd ? MSG_EscapeSearchUrl
464 // (term->m_value.u.string) :
465 // msg_EscapeImapSearchProtocol(term->m_value.u.string);
466 nsString searchTermValue;
467 searchValue->GetStr(searchTermValue);
468 // Ugly switch for Korean mail/news charsets.
469 // We want to do this here because here is where
470 // we know what charset we want to use.
471 #ifdef DOING_CHARSET
472 if (reallyDredd)
473 dest_csid = INTL_DefaultNewsCharSetID(dest_csid);
474 else
475 dest_csid = INTL_DefaultMailCharSetID(dest_csid);
476 #endif
477
478 // do all sorts of crazy escaping
479 convertedValue = reallyDredd
480 ? EscapeSearchUrl(searchTermValue.get())
481 : EscapeImapSearchProtocol(searchTermValue.get());
482 useQuotes =
483 ((!reallyDredd ||
484 (nsDependentString(convertedValue).FindChar(char16_t(' ')) !=
485 -1)) &&
486 (attrib != nsMsgSearchAttrib::Keywords));
487 // now convert to char* and escape quoted_specials
488 nsAutoCString valueStr;
489 nsresult rv = nsMsgI18NConvertFromUnicode(
490 NS_LossyConvertUTF16toASCII(destCharset),
491 nsDependentString(convertedValue), valueStr);
492 if (NS_SUCCEEDED(rv)) {
493 const char* vptr = valueStr.get();
494 // max escaped length is one extra character for every character in the
495 // cmd.
496 mozilla::UniquePtr<char[]> newValue =
497 mozilla::MakeUnique<char[]>(2 * strlen(vptr) + 1);
498 if (newValue) {
499 char* p = newValue.get();
500 while (1) {
501 char ch = *vptr++;
502 if (!ch) break;
503 if ((useQuotes ? ch == '"' : 0) || ch == '\\') *p++ = '\\';
504 *p++ = ch;
505 }
506 *p = '\0';
507 value = strdup(newValue.get()); // realloc down to smaller size
508 }
509 } else
510 value = strdup("");
511 free(convertedValue);
512 valueWasAllocated = true;
513 }
514 }
515
516 // this should be rewritten to use nsCString
517 int subLen = (value ? strlen(value) : 0) + (useNot ? strlen(m_kImapNot) : 0) +
518 strlen(m_kImapHeader);
519 int len =
520 strlen(whichMnemonic) + subLen + (useQuotes ? 2 : 0) +
521 (orHeaderMnemonic
522 ? (subLen + strlen(m_kImapOr) + strlen(orHeaderMnemonic) + 2 /*""*/)
523 : 0) +
524 10; // add slough for imap string literals
525 char* encoding = new char[len];
526 if (encoding) {
527 encoding[0] = '\0';
528 // Remember: if ToOrCC and useNot then the expression becomes NOT To AND Not
529 // CC as opposed to (NOT TO) || (NOT CC)
530 if (orHeaderMnemonic && !useNot) PL_strcat(encoding, m_kImapOr);
531 if (useNot) PL_strcat(encoding, m_kImapNot);
532 if (!arbitraryHeader.IsEmpty()) PL_strcat(encoding, m_kImapHeader);
533 PL_strcat(encoding, whichMnemonic);
534 if (!ignoreValue)
535 err = EncodeImapValue(encoding, value, useQuotes, reallyDredd);
536
537 if (orHeaderMnemonic) {
538 if (useNot) PL_strcat(encoding, m_kImapNot);
539
540 PL_strcat(encoding, m_kImapHeader);
541
542 PL_strcat(encoding, orHeaderMnemonic);
543 if (!ignoreValue)
544 err = EncodeImapValue(encoding, value, useQuotes, reallyDredd);
545 }
546
547 // kmcentee, don't let the encoding end with whitespace,
548 // this throws off later url STRCMP
549 if (*encoding && *(encoding + strlen(encoding) - 1) == ' ')
550 *(encoding + strlen(encoding) - 1) = '\0';
551 }
552
553 if (value && valueWasAllocated) free(value);
554
555 *ppOutTerm = encoding;
556
557 return err;
558 }
559
EncodeImapValue(char * encoding,const char * value,bool useQuotes,bool reallyDredd)560 nsresult nsMsgSearchAdapter::EncodeImapValue(char* encoding, const char* value,
561 bool useQuotes, bool reallyDredd) {
562 // By NNTP RFC, SEARCH HEADER SUBJECT "" is legal and means 'find messages
563 // without a subject header'
564 if (!reallyDredd) {
565 // By IMAP RFC, SEARCH HEADER SUBJECT "" is illegal and will generate an
566 // error from the server
567 if (!value || !value[0]) return NS_ERROR_NULL_POINTER;
568 }
569
570 if (!NS_IsAscii(value)) {
571 nsAutoCString lengthStr;
572 PL_strcat(encoding, "{");
573 lengthStr.AppendInt((int32_t)strlen(value));
574 PL_strcat(encoding, lengthStr.get());
575 PL_strcat(encoding, "}" CRLF);
576 PL_strcat(encoding, value);
577 return NS_OK;
578 }
579 if (useQuotes) PL_strcat(encoding, "\"");
580 PL_strcat(encoding, value);
581 if (useQuotes) PL_strcat(encoding, "\"");
582
583 return NS_OK;
584 }
585
EncodeImap(char ** ppOutEncoding,nsTArray<RefPtr<nsIMsgSearchTerm>> const & searchTerms,const char16_t * srcCharset,const char16_t * destCharset,bool reallyDredd)586 nsresult nsMsgSearchAdapter::EncodeImap(
587 char** ppOutEncoding, nsTArray<RefPtr<nsIMsgSearchTerm>> const& searchTerms,
588 const char16_t* srcCharset, const char16_t* destCharset, bool reallyDredd) {
589 // i've left the old code (before using CBoolExpression for debugging purposes
590 // to make sure that the new code generates the same encoding string as the
591 // old code.....
592
593 nsresult err = NS_OK;
594 *ppOutEncoding = nullptr;
595
596 // create our expression
597 nsMsgSearchBoolExpression* expression = new nsMsgSearchBoolExpression();
598 if (!expression) return NS_ERROR_OUT_OF_MEMORY;
599
600 for (nsIMsgSearchTerm* pTerm : searchTerms) {
601 bool matchAll;
602 pTerm->GetMatchAll(&matchAll);
603 if (matchAll) continue;
604 char* termEncoding;
605 err = EncodeImapTerm(pTerm, reallyDredd, srcCharset, destCharset,
606 &termEncoding);
607 if (NS_SUCCEEDED(err) && nullptr != termEncoding) {
608 expression = nsMsgSearchBoolExpression::AddSearchTerm(expression, pTerm,
609 termEncoding);
610 delete[] termEncoding;
611 } else {
612 break;
613 }
614 }
615
616 if (NS_SUCCEEDED(err)) {
617 // Catenate the intermediate encodings together into a big string
618 nsAutoCString encodingBuff;
619
620 if (!reallyDredd) encodingBuff.Append(m_kImapUnDeleted);
621
622 expression->GenerateEncodeStr(&encodingBuff);
623 *ppOutEncoding = ToNewCString(encodingBuff);
624 }
625
626 delete expression;
627
628 return err;
629 }
630
TransformSpacesToStars(const char * spaceString,msg_TransformType transformType)631 char* nsMsgSearchAdapter::TransformSpacesToStars(
632 const char* spaceString, msg_TransformType transformType) {
633 char* starString;
634
635 if (transformType == kOverwrite) {
636 if ((starString = strdup(spaceString)) != nullptr) {
637 char* star = starString;
638 while ((star = PL_strchr(star, ' ')) != nullptr) *star = '*';
639 }
640 } else {
641 int i, count;
642
643 for (i = 0, count = 0; spaceString[i];) {
644 if (spaceString[i++] == ' ') {
645 count++;
646 while (spaceString[i] && spaceString[i] == ' ') i++;
647 }
648 }
649
650 if (transformType == kSurround) count *= 2;
651
652 if (count > 0) {
653 if ((starString = (char*)PR_Malloc(i + count + 1)) != nullptr) {
654 int j;
655
656 for (i = 0, j = 0; spaceString[i];) {
657 if (spaceString[i] == ' ') {
658 starString[j++] = '*';
659 starString[j++] = ' ';
660 if (transformType == kSurround) starString[j++] = '*';
661
662 i++;
663 while (spaceString[i] && spaceString[i] == ' ') i++;
664 } else
665 starString[j++] = spaceString[i++];
666 }
667 starString[j] = 0;
668 }
669 } else
670 starString = strdup(spaceString);
671 }
672
673 return starString;
674 }
675
676 //-----------------------------------------------------------------------------
677 //------------------- Validity checking for menu items etc. -------------------
678 //-----------------------------------------------------------------------------
679
nsMsgSearchValidityTable()680 nsMsgSearchValidityTable::nsMsgSearchValidityTable() {
681 // Set everything to be unavailable and disabled
682 for (int i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++)
683 for (int j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++) {
684 SetAvailable(i, j, false);
685 SetEnabled(i, j, false);
686 SetValidButNotShown(i, j, false);
687 }
688 m_numAvailAttribs =
689 0; // # of attributes marked with at least one available operator
690 // assume default is Subject, which it is for mail and news search
691 // it's not for LDAP, so we'll call SetDefaultAttrib()
692 m_defaultAttrib = nsMsgSearchAttrib::Subject;
693 }
694
NS_IMPL_ISUPPORTS(nsMsgSearchValidityTable,nsIMsgSearchValidityTable)695 NS_IMPL_ISUPPORTS(nsMsgSearchValidityTable, nsIMsgSearchValidityTable)
696
697 nsresult nsMsgSearchValidityTable::GetNumAvailAttribs(int32_t* aResult) {
698 m_numAvailAttribs = 0;
699 for (int i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++)
700 for (int j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++) {
701 bool available;
702 GetAvailable(i, j, &available);
703 if (available) {
704 m_numAvailAttribs++;
705 break;
706 }
707 }
708 *aResult = m_numAvailAttribs;
709 return NS_OK;
710 }
711
GetAvailableAttributes(nsTArray<nsMsgSearchAttribValue> & aResult)712 nsresult nsMsgSearchValidityTable::GetAvailableAttributes(
713 nsTArray<nsMsgSearchAttribValue>& aResult) {
714 aResult.Clear();
715 int32_t i, j;
716 for (i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++) {
717 for (j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++) {
718 if (m_table[i][j].bitAvailable) {
719 aResult.AppendElement(static_cast<nsMsgSearchAttribValue>(i));
720 break;
721 }
722 }
723 }
724 return NS_OK;
725 }
726
GetAvailableOperators(nsMsgSearchAttribValue aAttribute,nsTArray<nsMsgSearchOpValue> & aResult)727 nsresult nsMsgSearchValidityTable::GetAvailableOperators(
728 nsMsgSearchAttribValue aAttribute, nsTArray<nsMsgSearchOpValue>& aResult) {
729 aResult.Clear();
730
731 nsMsgSearchAttribValue attr;
732 if (aAttribute == nsMsgSearchAttrib::Default)
733 attr = m_defaultAttrib;
734 else
735 attr = std::min(aAttribute,
736 (nsMsgSearchAttribValue)nsMsgSearchAttrib::OtherHeader);
737
738 int32_t i;
739 for (i = 0; i < nsMsgSearchOp::kNumMsgSearchOperators; i++) {
740 if (m_table[attr][i].bitAvailable) {
741 aResult.AppendElement(static_cast<nsMsgSearchOpValue>(i));
742 }
743 }
744 return NS_OK;
745 }
746
747 NS_IMETHODIMP
SetDefaultAttrib(nsMsgSearchAttribValue aAttribute)748 nsMsgSearchValidityTable::SetDefaultAttrib(nsMsgSearchAttribValue aAttribute) {
749 m_defaultAttrib = aAttribute;
750 return NS_OK;
751 }
752
nsMsgSearchValidityManager()753 nsMsgSearchValidityManager::nsMsgSearchValidityManager() {}
754
~nsMsgSearchValidityManager()755 nsMsgSearchValidityManager::~nsMsgSearchValidityManager() {
756 // tables released by nsCOMPtr
757 }
758
NS_IMPL_ISUPPORTS(nsMsgSearchValidityManager,nsIMsgSearchValidityManager)759 NS_IMPL_ISUPPORTS(nsMsgSearchValidityManager, nsIMsgSearchValidityManager)
760
761 //-----------------------------------------------------------------------------
762 // Bottleneck accesses to the objects so we can allocate and initialize them
763 // lazily. This way, there's no heap overhead for the validity tables until the
764 // user actually searches that scope.
765 //-----------------------------------------------------------------------------
766
767 NS_IMETHODIMP nsMsgSearchValidityManager::GetTable(
768 int whichTable, nsIMsgSearchValidityTable** ppOutTable) {
769 NS_ENSURE_ARG_POINTER(ppOutTable);
770
771 nsresult rv;
772 *ppOutTable = nullptr;
773
774 nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
775 nsCString customHeaders;
776 if (NS_SUCCEEDED(rv)) pref->GetCharPref(PREF_CUSTOM_HEADERS, customHeaders);
777
778 switch (whichTable) {
779 case nsMsgSearchScope::offlineMail:
780 if (!m_offlineMailTable) rv = InitOfflineMailTable();
781 if (m_offlineMailTable)
782 rv = SetOtherHeadersInTable(m_offlineMailTable, customHeaders.get());
783 *ppOutTable = m_offlineMailTable;
784 break;
785 case nsMsgSearchScope::offlineMailFilter:
786 if (!m_offlineMailFilterTable) rv = InitOfflineMailFilterTable();
787 if (m_offlineMailFilterTable)
788 rv = SetOtherHeadersInTable(m_offlineMailFilterTable,
789 customHeaders.get());
790 *ppOutTable = m_offlineMailFilterTable;
791 break;
792 case nsMsgSearchScope::onlineMail:
793 if (!m_onlineMailTable) rv = InitOnlineMailTable();
794 if (m_onlineMailTable)
795 rv = SetOtherHeadersInTable(m_onlineMailTable, customHeaders.get());
796 *ppOutTable = m_onlineMailTable;
797 break;
798 case nsMsgSearchScope::onlineMailFilter:
799 if (!m_onlineMailFilterTable) rv = InitOnlineMailFilterTable();
800 if (m_onlineMailFilterTable)
801 rv = SetOtherHeadersInTable(m_onlineMailFilterTable,
802 customHeaders.get());
803 *ppOutTable = m_onlineMailFilterTable;
804 break;
805 case nsMsgSearchScope::news:
806 if (!m_newsTable) rv = InitNewsTable();
807 if (m_newsTable)
808 rv = SetOtherHeadersInTable(m_newsTable, customHeaders.get());
809 *ppOutTable = m_newsTable;
810 break;
811 case nsMsgSearchScope::newsFilter:
812 if (!m_newsFilterTable) rv = InitNewsFilterTable();
813 if (m_newsFilterTable)
814 rv = SetOtherHeadersInTable(m_newsFilterTable, customHeaders.get());
815 *ppOutTable = m_newsFilterTable;
816 break;
817 case nsMsgSearchScope::localNews:
818 if (!m_localNewsTable) rv = InitLocalNewsTable();
819 if (m_localNewsTable)
820 rv = SetOtherHeadersInTable(m_localNewsTable, customHeaders.get());
821 *ppOutTable = m_localNewsTable;
822 break;
823 case nsMsgSearchScope::localNewsJunk:
824 if (!m_localNewsJunkTable) rv = InitLocalNewsJunkTable();
825 if (m_localNewsJunkTable)
826 rv = SetOtherHeadersInTable(m_localNewsJunkTable, customHeaders.get());
827 *ppOutTable = m_localNewsJunkTable;
828 break;
829 case nsMsgSearchScope::localNewsBody:
830 if (!m_localNewsBodyTable) rv = InitLocalNewsBodyTable();
831 if (m_localNewsBodyTable)
832 rv = SetOtherHeadersInTable(m_localNewsBodyTable, customHeaders.get());
833 *ppOutTable = m_localNewsBodyTable;
834 break;
835 case nsMsgSearchScope::localNewsJunkBody:
836 if (!m_localNewsJunkBodyTable) rv = InitLocalNewsJunkBodyTable();
837 if (m_localNewsJunkBodyTable)
838 rv = SetOtherHeadersInTable(m_localNewsJunkBodyTable,
839 customHeaders.get());
840 *ppOutTable = m_localNewsJunkBodyTable;
841 break;
842
843 case nsMsgSearchScope::onlineManual:
844 if (!m_onlineManualFilterTable) rv = InitOnlineManualFilterTable();
845 if (m_onlineManualFilterTable)
846 rv = SetOtherHeadersInTable(m_onlineManualFilterTable,
847 customHeaders.get());
848 *ppOutTable = m_onlineManualFilterTable;
849 break;
850 case nsMsgSearchScope::LDAP:
851 if (!m_ldapTable) rv = InitLdapTable();
852 *ppOutTable = m_ldapTable;
853 break;
854 case nsMsgSearchScope::LDAPAnd:
855 if (!m_ldapAndTable) rv = InitLdapAndTable();
856 *ppOutTable = m_ldapAndTable;
857 break;
858 case nsMsgSearchScope::LocalAB:
859 if (!m_localABTable) rv = InitLocalABTable();
860 *ppOutTable = m_localABTable;
861 break;
862 case nsMsgSearchScope::LocalABAnd:
863 if (!m_localABAndTable) rv = InitLocalABAndTable();
864 *ppOutTable = m_localABAndTable;
865 break;
866 default:
867 NS_ASSERTION(false, "invalid table type");
868 rv = NS_MSG_ERROR_INVALID_SEARCH_TERM;
869 }
870
871 NS_IF_ADDREF(*ppOutTable); // Was populated from member variable.
872 return rv;
873 }
874
875 // mapping between ordered attribute values, and property strings
876 // see search-attributes.properties
877 static struct {
878 nsMsgSearchAttribValue id;
879 const char* property;
880 } nsMsgSearchAttribMap[] = {
881 {nsMsgSearchAttrib::Subject, "Subject"},
882 {nsMsgSearchAttrib::Sender, "From"},
883 {nsMsgSearchAttrib::Body, "Body"},
884 {nsMsgSearchAttrib::Date, "Date"},
885 {nsMsgSearchAttrib::Priority, "Priority"},
886 {nsMsgSearchAttrib::MsgStatus, "Status"},
887 {nsMsgSearchAttrib::To, "To"},
888 {nsMsgSearchAttrib::CC, "Cc"},
889 {nsMsgSearchAttrib::ToOrCC, "ToOrCc"},
890 {nsMsgSearchAttrib::AgeInDays, "AgeInDays"},
891 {nsMsgSearchAttrib::Size, "SizeKB"},
892 {nsMsgSearchAttrib::Keywords, "Tags"},
893 {nsMsgSearchAttrib::Name, "AnyName"},
894 {nsMsgSearchAttrib::DisplayName, "DisplayName"},
895 {nsMsgSearchAttrib::Nickname, "Nickname"},
896 {nsMsgSearchAttrib::ScreenName, "ScreenName"},
897 {nsMsgSearchAttrib::Email, "Email"},
898 {nsMsgSearchAttrib::AdditionalEmail, "AdditionalEmail"},
899 {nsMsgSearchAttrib::PhoneNumber, "AnyNumber"},
900 {nsMsgSearchAttrib::WorkPhone, "WorkPhone"},
901 {nsMsgSearchAttrib::HomePhone, "HomePhone"},
902 {nsMsgSearchAttrib::Fax, "Fax"},
903 {nsMsgSearchAttrib::Pager, "Pager"},
904 {nsMsgSearchAttrib::Mobile, "Mobile"},
905 {nsMsgSearchAttrib::City, "City"},
906 {nsMsgSearchAttrib::Street, "Street"},
907 {nsMsgSearchAttrib::Title, "Title"},
908 {nsMsgSearchAttrib::Organization, "Organization"},
909 {nsMsgSearchAttrib::Department, "Department"},
910 {nsMsgSearchAttrib::AllAddresses, "FromToCcOrBcc"},
911 {nsMsgSearchAttrib::JunkScoreOrigin, "JunkScoreOrigin"},
912 {nsMsgSearchAttrib::JunkPercent, "JunkPercent"},
913 {nsMsgSearchAttrib::HasAttachmentStatus, "AttachmentStatus"},
914 {nsMsgSearchAttrib::JunkStatus, "JunkStatus"},
915 {nsMsgSearchAttrib::Label, "Label"},
916 {nsMsgSearchAttrib::OtherHeader, "Customize"},
917 // the last id is -1 to denote end of table
918 {-1, ""}};
919
920 NS_IMETHODIMP
GetAttributeProperty(nsMsgSearchAttribValue aSearchAttribute,nsAString & aProperty)921 nsMsgSearchValidityManager::GetAttributeProperty(
922 nsMsgSearchAttribValue aSearchAttribute, nsAString& aProperty) {
923 for (int32_t i = 0; nsMsgSearchAttribMap[i].id >= 0; ++i) {
924 if (nsMsgSearchAttribMap[i].id == aSearchAttribute) {
925 aProperty.Assign(NS_ConvertUTF8toUTF16(nsMsgSearchAttribMap[i].property));
926 return NS_OK;
927 }
928 }
929 return NS_ERROR_FAILURE;
930 }
931
NewTable(nsIMsgSearchValidityTable ** aTable)932 nsresult nsMsgSearchValidityManager::NewTable(
933 nsIMsgSearchValidityTable** aTable) {
934 NS_ENSURE_ARG_POINTER(aTable);
935 NS_ADDREF(*aTable = new nsMsgSearchValidityTable);
936 return NS_OK;
937 }
938
SetOtherHeadersInTable(nsIMsgSearchValidityTable * aTable,const char * customHeaders)939 nsresult nsMsgSearchValidityManager::SetOtherHeadersInTable(
940 nsIMsgSearchValidityTable* aTable, const char* customHeaders) {
941 uint32_t customHeadersLength = strlen(customHeaders);
942 uint32_t numHeaders = 0;
943 if (customHeadersLength) {
944 nsAutoCString hdrStr(customHeaders);
945 hdrStr.StripWhitespace(); // remove whitespace before parsing
946 char* newStr = hdrStr.BeginWriting();
947 char* token = NS_strtok(":", &newStr);
948 while (token) {
949 numHeaders++;
950 token = NS_strtok(":", &newStr);
951 }
952 }
953
954 NS_ASSERTION(nsMsgSearchAttrib::OtherHeader + numHeaders <
955 nsMsgSearchAttrib::kNumMsgSearchAttributes,
956 "more headers than the table can hold");
957
958 uint32_t maxHdrs =
959 std::min(nsMsgSearchAttrib::OtherHeader + numHeaders + 1,
960 (uint32_t)nsMsgSearchAttrib::kNumMsgSearchAttributes);
961 for (uint32_t i = nsMsgSearchAttrib::OtherHeader + 1; i < maxHdrs; i++) {
962 // clang-format off
963 aTable->SetAvailable(i, nsMsgSearchOp::Contains, 1); // added for arbitrary headers
964 aTable->SetEnabled (i, nsMsgSearchOp::Contains, 1);
965 aTable->SetAvailable(i, nsMsgSearchOp::DoesntContain, 1);
966 aTable->SetEnabled (i, nsMsgSearchOp::DoesntContain, 1);
967 aTable->SetAvailable(i, nsMsgSearchOp::Is, 1);
968 aTable->SetEnabled (i, nsMsgSearchOp::Is, 1);
969 aTable->SetAvailable(i, nsMsgSearchOp::Isnt, 1);
970 aTable->SetEnabled (i, nsMsgSearchOp::Isnt, 1);
971 // clang-format on
972 }
973 // because custom headers can change; so reset the table for those which are
974 // no longer used.
975 for (uint32_t j = maxHdrs; j < nsMsgSearchAttrib::kNumMsgSearchAttributes;
976 j++) {
977 for (uint32_t k = 0; k < nsMsgSearchOp::kNumMsgSearchOperators; k++) {
978 aTable->SetAvailable(j, k, 0);
979 aTable->SetEnabled(j, k, 0);
980 }
981 }
982 return NS_OK;
983 }
984
EnableDirectoryAttribute(nsIMsgSearchValidityTable * table,nsMsgSearchAttribValue aSearchAttrib)985 nsresult nsMsgSearchValidityManager::EnableDirectoryAttribute(
986 nsIMsgSearchValidityTable* table, nsMsgSearchAttribValue aSearchAttrib) {
987 // clang-format off
988 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::Contains, 1);
989 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::Contains, 1);
990 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::DoesntContain, 1);
991 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::DoesntContain, 1);
992 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::Is, 1);
993 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::Is, 1);
994 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::Isnt, 1);
995 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::Isnt, 1);
996 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::BeginsWith, 1);
997 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::BeginsWith, 1);
998 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::EndsWith, 1);
999 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::EndsWith, 1);
1000 table->SetAvailable(aSearchAttrib, nsMsgSearchOp::SoundsLike, 1);
1001 table->SetEnabled (aSearchAttrib, nsMsgSearchOp::SoundsLike, 1);
1002 // clang-format on
1003 return NS_OK;
1004 }
1005
InitLdapTable()1006 nsresult nsMsgSearchValidityManager::InitLdapTable() {
1007 NS_ASSERTION(!m_ldapTable, "don't call this twice!");
1008
1009 nsresult rv = NewTable(getter_AddRefs(m_ldapTable));
1010 NS_ENSURE_SUCCESS(rv, rv);
1011
1012 rv = SetUpABTable(m_ldapTable, true);
1013 NS_ENSURE_SUCCESS(rv, rv);
1014 return rv;
1015 }
1016
InitLdapAndTable()1017 nsresult nsMsgSearchValidityManager::InitLdapAndTable() {
1018 NS_ASSERTION(!m_ldapAndTable, "don't call this twice!");
1019
1020 nsresult rv = NewTable(getter_AddRefs(m_ldapAndTable));
1021 NS_ENSURE_SUCCESS(rv, rv);
1022
1023 rv = SetUpABTable(m_ldapAndTable, false);
1024 NS_ENSURE_SUCCESS(rv, rv);
1025 return rv;
1026 }
1027
InitLocalABTable()1028 nsresult nsMsgSearchValidityManager::InitLocalABTable() {
1029 NS_ASSERTION(!m_localABTable, "don't call this twice!");
1030
1031 nsresult rv = NewTable(getter_AddRefs(m_localABTable));
1032 NS_ENSURE_SUCCESS(rv, rv);
1033
1034 rv = SetUpABTable(m_localABTable, true);
1035 NS_ENSURE_SUCCESS(rv, rv);
1036 return rv;
1037 }
1038
InitLocalABAndTable()1039 nsresult nsMsgSearchValidityManager::InitLocalABAndTable() {
1040 NS_ASSERTION(!m_localABAndTable, "don't call this twice!");
1041
1042 nsresult rv = NewTable(getter_AddRefs(m_localABAndTable));
1043 NS_ENSURE_SUCCESS(rv, rv);
1044
1045 rv = SetUpABTable(m_localABAndTable, false);
1046 NS_ENSURE_SUCCESS(rv, rv);
1047 return rv;
1048 }
1049
SetUpABTable(nsIMsgSearchValidityTable * aTable,bool isOrTable)1050 nsresult nsMsgSearchValidityManager::SetUpABTable(
1051 nsIMsgSearchValidityTable* aTable, bool isOrTable) {
1052 nsresult rv = aTable->SetDefaultAttrib(
1053 isOrTable ? nsMsgSearchAttrib::Name : nsMsgSearchAttrib::DisplayName);
1054 NS_ENSURE_SUCCESS(rv, rv);
1055
1056 if (isOrTable) {
1057 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Name);
1058 NS_ENSURE_SUCCESS(rv, rv);
1059
1060 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::PhoneNumber);
1061 NS_ENSURE_SUCCESS(rv, rv);
1062 }
1063
1064 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::DisplayName);
1065 NS_ENSURE_SUCCESS(rv, rv);
1066
1067 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Email);
1068 NS_ENSURE_SUCCESS(rv, rv);
1069
1070 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::AdditionalEmail);
1071 NS_ENSURE_SUCCESS(rv, rv);
1072
1073 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::ScreenName);
1074 NS_ENSURE_SUCCESS(rv, rv);
1075
1076 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Street);
1077 NS_ENSURE_SUCCESS(rv, rv);
1078
1079 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::City);
1080 NS_ENSURE_SUCCESS(rv, rv);
1081
1082 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Title);
1083 NS_ENSURE_SUCCESS(rv, rv);
1084
1085 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Organization);
1086 NS_ENSURE_SUCCESS(rv, rv);
1087
1088 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Department);
1089 NS_ENSURE_SUCCESS(rv, rv);
1090
1091 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Nickname);
1092 NS_ENSURE_SUCCESS(rv, rv);
1093
1094 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::WorkPhone);
1095 NS_ENSURE_SUCCESS(rv, rv);
1096
1097 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::HomePhone);
1098 NS_ENSURE_SUCCESS(rv, rv);
1099
1100 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Fax);
1101 NS_ENSURE_SUCCESS(rv, rv);
1102
1103 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Pager);
1104 NS_ENSURE_SUCCESS(rv, rv);
1105
1106 rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Mobile);
1107 NS_ENSURE_SUCCESS(rv, rv);
1108
1109 return rv;
1110 }
1111