summaryrefslogtreecommitdiffstats
path: root/mailnews/base/search/src/nsMsgSearchAdapter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/base/search/src/nsMsgSearchAdapter.cpp')
-rw-r--r--mailnews/base/search/src/nsMsgSearchAdapter.cpp1332
1 files changed, 1332 insertions, 0 deletions
diff --git a/mailnews/base/search/src/nsMsgSearchAdapter.cpp b/mailnews/base/search/src/nsMsgSearchAdapter.cpp
new file mode 100644
index 000000000..a6f877830
--- /dev/null
+++ b/mailnews/base/search/src/nsMsgSearchAdapter.cpp
@@ -0,0 +1,1332 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "msgCore.h"
+#include "nsTextFormatter.h"
+#include "nsMsgSearchCore.h"
+#include "nsMsgSearchAdapter.h"
+#include "nsMsgSearchScopeTerm.h"
+#include "nsMsgI18N.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsMsgSearchTerm.h"
+#include "nsMsgSearchBoolExpression.h"
+#include "nsIIOService.h"
+#include "nsNetCID.h"
+#include "prprf.h"
+#include "mozilla/UniquePtr.h"
+#include "prmem.h"
+#include "MailNewsTypes.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsMemory.h"
+#include "nsMsgMessageFlags.h"
+// Disable deprecation warnings generated by nsISupportsArray and associated
+// classes.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(_MSC_VER)
+#pragma warning (disable : 4996)
+#endif
+#include "nsISupportsArray.h"
+#include "nsAlgorithm.h"
+#include <algorithm>
+#include "mozilla/Attributes.h"
+
+// This stuff lives in the base class because the IMAP search syntax
+// is used by the Dredd SEARCH command as well as IMAP itself
+
+// km - the NOT and HEADER strings are not encoded with a trailing
+// <space> because they always precede a mnemonic that has a
+// preceding <space> and double <space> characters cause some
+// imap servers to return an error.
+const char *nsMsgSearchAdapter::m_kImapBefore = " SENTBEFORE ";
+const char *nsMsgSearchAdapter::m_kImapBody = " BODY ";
+const char *nsMsgSearchAdapter::m_kImapCC = " CC ";
+const char *nsMsgSearchAdapter::m_kImapFrom = " FROM ";
+const char *nsMsgSearchAdapter::m_kImapNot = " NOT";
+const char *nsMsgSearchAdapter::m_kImapUnDeleted= " UNDELETED";
+const char *nsMsgSearchAdapter::m_kImapOr = " OR";
+const char *nsMsgSearchAdapter::m_kImapSince = " SENTSINCE ";
+const char *nsMsgSearchAdapter::m_kImapSubject = " SUBJECT ";
+const char *nsMsgSearchAdapter::m_kImapTo = " TO ";
+const char *nsMsgSearchAdapter::m_kImapHeader = " HEADER";
+const char *nsMsgSearchAdapter::m_kImapAnyText = " TEXT ";
+const char *nsMsgSearchAdapter::m_kImapKeyword = " KEYWORD ";
+const char *nsMsgSearchAdapter::m_kNntpKeywords = " KEYWORDS "; //ggrrrr...
+const char *nsMsgSearchAdapter::m_kImapSentOn = " SENTON ";
+const char *nsMsgSearchAdapter::m_kImapSeen = " SEEN ";
+const char *nsMsgSearchAdapter::m_kImapAnswered = " ANSWERED ";
+const char *nsMsgSearchAdapter::m_kImapNotSeen = " UNSEEN ";
+const char *nsMsgSearchAdapter::m_kImapNotAnswered = " UNANSWERED ";
+const char *nsMsgSearchAdapter::m_kImapCharset = " CHARSET ";
+const char *nsMsgSearchAdapter::m_kImapSizeSmaller = " SMALLER ";
+const char *nsMsgSearchAdapter::m_kImapSizeLarger = " LARGER ";
+const char *nsMsgSearchAdapter::m_kImapNew = " NEW ";
+const char *nsMsgSearchAdapter::m_kImapNotNew = " OLD SEEN ";
+const char *nsMsgSearchAdapter::m_kImapFlagged = " FLAGGED ";
+const char *nsMsgSearchAdapter::m_kImapNotFlagged = " UNFLAGGED ";
+
+#define PREF_CUSTOM_HEADERS "mailnews.customHeaders"
+
+NS_IMETHODIMP nsMsgSearchAdapter::FindTargetFolder(const nsMsgResultElement *,nsIMsgFolder * *)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::ModifyResultElement(nsMsgResultElement *, nsMsgSearchValue *)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::OpenResultElement(nsMsgResultElement *)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMPL_ISUPPORTS(nsMsgSearchAdapter, nsIMsgSearchAdapter)
+
+nsMsgSearchAdapter::nsMsgSearchAdapter(nsIMsgSearchScopeTerm *scope, nsISupportsArray *searchTerms)
+ : m_searchTerms(searchTerms)
+{
+ m_scope = scope;
+}
+
+nsMsgSearchAdapter::~nsMsgSearchAdapter()
+{
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::ClearScope()
+{
+ if (m_scope)
+ {
+ m_scope->CloseInputStream();
+ m_scope = nullptr;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::ValidateTerms ()
+{
+ // all this used to do is check if the object had been deleted - we can skip that.
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::Abort ()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+}
+NS_IMETHODIMP nsMsgSearchAdapter::Search (bool *aDone)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::SendUrl ()
+{
+ return NS_OK;
+}
+
+/* void CurrentUrlDone (in nsresult exitCode); */
+NS_IMETHODIMP nsMsgSearchAdapter::CurrentUrlDone(nsresult exitCode)
+{
+ // base implementation doesn't need to do anything.
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::GetEncoding (char **encoding)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsMsgSearchAdapter::AddResultElement (nsIMsgDBHdr *pHeaders)
+{
+ NS_ASSERTION(false, "shouldn't call this base class impl");
+ return NS_ERROR_FAILURE;
+}
+
+
+NS_IMETHODIMP nsMsgSearchAdapter::AddHit(nsMsgKey key)
+{
+ NS_ASSERTION(false, "shouldn't call this base class impl");
+ return NS_ERROR_FAILURE;
+}
+
+
+char *
+nsMsgSearchAdapter::GetImapCharsetParam(const char16_t *destCharset)
+{
+ char *result = nullptr;
+
+ // Specify a character set unless we happen to be US-ASCII.
+ if (NS_strcmp(destCharset, u"us-ascii"))
+ result = PR_smprintf("%s%s", nsMsgSearchAdapter::m_kImapCharset, NS_ConvertUTF16toUTF8(destCharset).get());
+
+ return result;
+}
+
+/*
+ 09/21/2000 - taka@netscape.com
+ This method is bogus. Escape must be done against char * not char16_t *
+ should be rewritten later.
+ for now, just duplicate the string.
+*/
+char16_t *nsMsgSearchAdapter::EscapeSearchUrl (const char16_t *nntpCommand)
+{
+ return nntpCommand ? NS_strdup(nntpCommand) : nullptr;
+}
+
+/*
+ 09/21/2000 - taka@netscape.com
+ This method is bogus. Escape must be done against char * not char16_t *
+ should be rewritten later.
+ for now, just duplicate the string.
+*/
+char16_t *
+nsMsgSearchAdapter::EscapeImapSearchProtocol(const char16_t *imapCommand)
+{
+ return imapCommand ? NS_strdup(imapCommand) : nullptr;
+}
+
+/*
+ 09/21/2000 - taka@netscape.com
+ This method is bogus. Escape must be done against char * not char16_t *
+ should be rewritten later.
+ for now, just duplicate the string.
+*/
+char16_t *
+nsMsgSearchAdapter::EscapeQuoteImapSearchProtocol(const char16_t *imapCommand)
+{
+ return imapCommand ? NS_strdup(imapCommand) : nullptr;
+}
+
+char *nsMsgSearchAdapter::UnEscapeSearchUrl (const char *commandSpecificData)
+{
+ char *result = (char*) PR_Malloc (strlen(commandSpecificData) + 1);
+ if (result)
+ {
+ char *resultPtr = result;
+ while (1)
+ {
+ char ch = *commandSpecificData++;
+ if (!ch)
+ break;
+ if (ch == '\\')
+ {
+ char scratchBuf[3];
+ scratchBuf[0] = (char) *commandSpecificData++;
+ scratchBuf[1] = (char) *commandSpecificData++;
+ scratchBuf[2] = '\0';
+ unsigned int accum = 0;
+ sscanf (scratchBuf, "%X", &accum);
+ *resultPtr++ = (char) accum;
+ }
+ else
+ *resultPtr++ = ch;
+ }
+ *resultPtr = '\0';
+ }
+ return result;
+}
+
+
+nsresult
+nsMsgSearchAdapter::GetSearchCharsets(nsAString &srcCharset, nsAString &dstCharset)
+{
+ nsresult rv;
+
+ if (m_defaultCharset.IsEmpty())
+ {
+ m_forceAsciiSearch = false; // set the default value in case of error
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIPrefLocalizedString> localizedstr;
+ rv = prefs->GetComplexValue("mailnews.view_default_charset", NS_GET_IID(nsIPrefLocalizedString),
+ getter_AddRefs(localizedstr));
+ if (NS_SUCCEEDED(rv))
+ localizedstr->GetData(getter_Copies(m_defaultCharset));
+
+ prefs->GetBoolPref("mailnews.force_ascii_search", &m_forceAsciiSearch);
+ }
+ }
+ srcCharset = m_defaultCharset.IsEmpty() ?
+ static_cast<const nsAString&>(NS_LITERAL_STRING("ISO-8859-1")) :
+ m_defaultCharset;
+
+ if (m_scope)
+ {
+ // ### DMB is there a way to get the charset for the "window"?
+
+ nsCOMPtr<nsIMsgFolder> folder;
+ rv = m_scope->GetFolder(getter_AddRefs(folder));
+
+ // Ask the newsgroup/folder for its csid.
+ if (NS_SUCCEEDED(rv) && folder)
+ {
+ nsCString folderCharset;
+ folder->GetCharset(folderCharset);
+ dstCharset.Append(NS_ConvertASCIItoUTF16(folderCharset));
+ }
+ }
+ else
+ dstCharset.Assign(srcCharset);
+
+ // If
+ // the destination is still CS_DEFAULT, make the destination match
+ // the source. (CS_DEFAULT is an indication that the charset
+ // was undefined or unavailable.)
+ // ### well, it's not really anymore. Is there an equivalent?
+ if (dstCharset.Equals(m_defaultCharset))
+ {
+ dstCharset.Assign(srcCharset);
+ }
+
+ if (m_forceAsciiSearch)
+ {
+ // Special cases to use in order to force US-ASCII searching with Latin1
+ // or MacRoman text. Eurgh. This only has to happen because IMAP
+ // and Dredd servers currently (4/23/97) only support US-ASCII.
+ //
+ // If the dest csid is ISO Latin 1 or MacRoman, attempt to convert the
+ // source text to US-ASCII. (Not for now.)
+ // if ((dst_csid == CS_LATIN1) || (dst_csid == CS_MAC_ROMAN))
+ dstCharset.AssignLiteral("us-ascii");
+ }
+
+ return NS_OK;
+}
+
+nsresult nsMsgSearchAdapter::EncodeImapTerm (nsIMsgSearchTerm *term, bool reallyDredd, const char16_t *srcCharset, const char16_t *destCharset, char **ppOutTerm)
+{
+ NS_ENSURE_ARG_POINTER(term);
+ NS_ENSURE_ARG_POINTER(ppOutTerm);
+
+ nsresult err = NS_OK;
+ bool useNot = false;
+ bool useQuotes = false;
+ bool ignoreValue = false;
+ nsAutoCString arbitraryHeader;
+ const char *whichMnemonic = nullptr;
+ const char *orHeaderMnemonic = nullptr;
+
+ *ppOutTerm = nullptr;
+
+ nsCOMPtr <nsIMsgSearchValue> searchValue;
+ nsresult rv = term->GetValue(getter_AddRefs(searchValue));
+
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ nsMsgSearchOpValue op;
+ term->GetOp(&op);
+
+ if (op == nsMsgSearchOp::DoesntContain || op == nsMsgSearchOp::Isnt)
+ useNot = true;
+
+ nsMsgSearchAttribValue attrib;
+ term->GetAttrib(&attrib);
+
+ switch (attrib)
+ {
+ case nsMsgSearchAttrib::ToOrCC:
+ orHeaderMnemonic = m_kImapCC;
+ // fall through to case nsMsgSearchAttrib::To:
+ MOZ_FALLTHROUGH;
+ case nsMsgSearchAttrib::To:
+ whichMnemonic = m_kImapTo;
+ break;
+ case nsMsgSearchAttrib::CC:
+ whichMnemonic = m_kImapCC;
+ break;
+ case nsMsgSearchAttrib::Sender:
+ whichMnemonic = m_kImapFrom;
+ break;
+ case nsMsgSearchAttrib::Subject:
+ whichMnemonic = m_kImapSubject;
+ break;
+ case nsMsgSearchAttrib::Body:
+ whichMnemonic = m_kImapBody;
+ break;
+ case nsMsgSearchAttrib::AgeInDays: // added for searching online for age in days...
+ // for AgeInDays, we are actually going to perform a search by date, so convert the operations for age
+ // to the IMAP mnemonics that we would use for date!
+ {
+ // If we have a future date, the > and < are reversed.
+ // e.g. ageInDays > 2 means more than 2 days old ("date before X") whereas
+ // ageInDays > -2 should be more than 2 days in the future ("date after X")
+ int32_t ageInDays;
+ searchValue->GetAge(&ageInDays);
+ bool dateInFuture = (ageInDays < 0);
+ switch (op)
+ {
+ case nsMsgSearchOp::IsGreaterThan:
+ whichMnemonic = (!dateInFuture) ? m_kImapBefore : m_kImapSince;
+ break;
+ case nsMsgSearchOp::IsLessThan:
+ whichMnemonic = (!dateInFuture) ? m_kImapSince : m_kImapBefore;
+ break;
+ case nsMsgSearchOp::Is:
+ whichMnemonic = m_kImapSentOn;
+ break;
+ default:
+ NS_ASSERTION(false, "invalid search operator");
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+ break;
+ case nsMsgSearchAttrib::Size:
+ switch (op)
+ {
+ case nsMsgSearchOp::IsGreaterThan:
+ whichMnemonic = m_kImapSizeLarger;
+ break;
+ case nsMsgSearchOp::IsLessThan:
+ whichMnemonic = m_kImapSizeSmaller;
+ break;
+ default:
+ NS_ASSERTION(false, "invalid search operator");
+ return NS_ERROR_INVALID_ARG;
+ }
+ break;
+ case nsMsgSearchAttrib::Date:
+ switch (op)
+ {
+ case nsMsgSearchOp::IsBefore:
+ whichMnemonic = m_kImapBefore;
+ break;
+ case nsMsgSearchOp::IsAfter:
+ whichMnemonic = m_kImapSince;
+ break;
+ case nsMsgSearchOp::Isnt: /* we've already added the "Not" so just process it like it was a date is search */
+ case nsMsgSearchOp::Is:
+ whichMnemonic = m_kImapSentOn;
+ break;
+ default:
+ NS_ASSERTION(false, "invalid search operator");
+ return NS_ERROR_INVALID_ARG;
+ }
+ break;
+ case nsMsgSearchAttrib::AnyText:
+ whichMnemonic = m_kImapAnyText;
+ break;
+ case nsMsgSearchAttrib::Keywords:
+ whichMnemonic = m_kImapKeyword;
+ break;
+ case nsMsgSearchAttrib::MsgStatus:
+ useNot = false; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
+ ignoreValue = true; // the mnemonic is all we need
+ uint32_t status;
+ searchValue->GetStatus(&status);
+
+ switch (status)
+ {
+ case nsMsgMessageFlags::Read:
+ whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapSeen : m_kImapNotSeen;
+ break;
+ case nsMsgMessageFlags::Replied:
+ whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapAnswered : m_kImapNotAnswered;
+ break;
+ case nsMsgMessageFlags::New:
+ whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapNew : m_kImapNotNew;
+ break;
+ case nsMsgMessageFlags::Marked:
+ whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapFlagged : m_kImapNotFlagged;
+ break;
+ default:
+ NS_ASSERTION(false, "invalid search operator");
+ return NS_ERROR_INVALID_ARG;
+ }
+ break;
+ default:
+ if ( attrib > nsMsgSearchAttrib::OtherHeader && attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes)
+ {
+ nsCString arbitraryHeaderTerm;
+ term->GetArbitraryHeader(arbitraryHeaderTerm);
+ if (!arbitraryHeaderTerm.IsEmpty())
+ {
+ arbitraryHeader.AssignLiteral(" \"");
+ arbitraryHeader.Append(arbitraryHeaderTerm);
+ arbitraryHeader.AppendLiteral("\" ");
+ whichMnemonic = arbitraryHeader.get();
+ }
+ else
+ return NS_ERROR_FAILURE;
+ }
+ else
+ {
+ NS_ASSERTION(false, "invalid search operator");
+ return NS_ERROR_INVALID_ARG;
+ }
+ }
+
+ char *value = nullptr;
+ char dateBuf[100];
+ dateBuf[0] = '\0';
+
+ bool valueWasAllocated = false;
+ if (attrib == nsMsgSearchAttrib::Date)
+ {
+ // note that there used to be code here that encoded an RFC822 date for imap searches.
+ // The IMAP RFC 2060 is misleading to the point that it looks like it requires an RFC822
+ // date but really it expects dd-mmm-yyyy, like dredd, and refers to the RFC822 date only in that the
+ // dd-mmm-yyyy date will match the RFC822 date within the message.
+
+ PRTime adjustedDate;
+ searchValue->GetDate(&adjustedDate);
+ if (whichMnemonic == m_kImapSince)
+ {
+ // it looks like the IMAP server searches on Since includes the date in question...
+ // our UI presents Is, IsGreater and IsLessThan. For the IsGreater case (m_kImapSince)
+ // we need to adjust the date so we get greater than and not greater than or equal to which
+ // is what the IMAP server wants to search on
+ // won't work on Mac.
+ adjustedDate += PR_USEC_PER_DAY;
+ }
+
+ PRExplodedTime exploded;
+ PR_ExplodeTime(adjustedDate, PR_LocalTimeParameters, &exploded);
+ PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%d-%b-%Y", &exploded);
+ // strftime (dateBuf, sizeof(dateBuf), "%d-%b-%Y", localtime (/* &term->m_value.u.date */ &adjustedDate));
+ value = dateBuf;
+ }
+ else
+ {
+ if (attrib == nsMsgSearchAttrib::AgeInDays)
+ {
+ // okay, take the current date, subtract off the age in days, then do an appropriate Date search on
+ // the resulting day.
+ int32_t ageInDays;
+
+ searchValue->GetAge(&ageInDays);
+
+ PRTime now = PR_Now();
+ PRTime matchDay = now - ageInDays * PR_USEC_PER_DAY;
+
+ PRExplodedTime exploded;
+ PR_ExplodeTime(matchDay, PR_LocalTimeParameters, &exploded);
+ PR_FormatTimeUSEnglish(dateBuf, sizeof(dateBuf), "%d-%b-%Y", &exploded);
+ // strftime (dateBuf, sizeof(dateBuf), "%d-%b-%Y", localtime (&matchDay));
+ value = dateBuf;
+ }
+ else if (attrib == nsMsgSearchAttrib::Size)
+ {
+ uint32_t sizeValue;
+ nsAutoCString searchTermValue;
+ searchValue->GetSize(&sizeValue);
+
+ // Multiply by 1024 to get into kb resolution
+ sizeValue *= 1024;
+
+ // Ensure that greater than is really greater than
+ // in kb resolution.
+ if (op == nsMsgSearchOp::IsGreaterThan)
+ sizeValue += 1024;
+
+ searchTermValue.AppendInt(sizeValue);
+
+ value = ToNewCString(searchTermValue);
+ valueWasAllocated = true;
+ }
+ else
+
+ if (IS_STRING_ATTRIBUTE(attrib))
+ {
+ char16_t *convertedValue; // = reallyDredd ? MSG_EscapeSearchUrl (term->m_value.u.string) : msg_EscapeImapSearchProtocol(term->m_value.u.string);
+ nsString searchTermValue;
+ searchValue->GetStr(searchTermValue);
+ // Ugly switch for Korean mail/news charsets.
+ // We want to do this here because here is where
+ // we know what charset we want to use.
+#ifdef DOING_CHARSET
+ if (reallyDredd)
+ dest_csid = INTL_DefaultNewsCharSetID(dest_csid);
+ else
+ dest_csid = INTL_DefaultMailCharSetID(dest_csid);
+#endif
+
+ // do all sorts of crazy escaping
+ convertedValue = reallyDredd ? EscapeSearchUrl (searchTermValue.get()) :
+ EscapeImapSearchProtocol(searchTermValue.get());
+ useQuotes = ((!reallyDredd ||
+ (nsDependentString(convertedValue).FindChar(char16_t(' ')) != -1)) &&
+ (attrib != nsMsgSearchAttrib::Keywords));
+ // now convert to char* and escape quoted_specials
+ nsAutoCString valueStr;
+ nsresult rv = ConvertFromUnicode(NS_LossyConvertUTF16toASCII(destCharset).get(),
+ nsDependentString(convertedValue), valueStr);
+ if (NS_SUCCEEDED(rv))
+ {
+ const char *vptr = valueStr.get();
+ // max escaped length is one extra character for every character in the cmd.
+ mozilla::UniquePtr<char[]> newValue = mozilla::MakeUnique<char[]>(2*strlen(vptr) + 1);
+ if (newValue)
+ {
+ char *p = newValue.get();
+ while (1)
+ {
+ char ch = *vptr++;
+ if (!ch)
+ break;
+ if ((useQuotes ? ch == '"' : 0) || ch == '\\')
+ *p++ = '\\';
+ *p++ = ch;
+ }
+ *p = '\0';
+ value = strdup(newValue.get()); // realloc down to smaller size
+ }
+ }
+ else
+ value = strdup("");
+ NS_Free(convertedValue);
+ valueWasAllocated = true;
+
+ }
+ }
+
+ // this should be rewritten to use nsCString
+ int subLen =
+ (value ? strlen(value) : 0) +
+ (useNot ? strlen(m_kImapNot) : 0) +
+ strlen(m_kImapHeader);
+ int len = strlen(whichMnemonic) + subLen + (useQuotes ? 2 : 0) +
+ (orHeaderMnemonic
+ ? (subLen + strlen(m_kImapOr) + strlen(orHeaderMnemonic) + 2 /*""*/)
+ : 0) +
+ 10; // add slough for imap string literals
+ char *encoding = new char[len];
+ if (encoding)
+ {
+ encoding[0] = '\0';
+ // Remember: if ToOrCC and useNot then the expression becomes NOT To AND Not CC as opposed to (NOT TO) || (NOT CC)
+ if (orHeaderMnemonic && !useNot)
+ PL_strcat(encoding, m_kImapOr);
+ if (useNot)
+ PL_strcat (encoding, m_kImapNot);
+ if (!arbitraryHeader.IsEmpty())
+ PL_strcat (encoding, m_kImapHeader);
+ PL_strcat (encoding, whichMnemonic);
+ if (!ignoreValue)
+ err = EncodeImapValue(encoding, value, useQuotes, reallyDredd);
+
+ if (orHeaderMnemonic)
+ {
+ if (useNot)
+ PL_strcat(encoding, m_kImapNot);
+
+ PL_strcat (encoding, m_kImapHeader);
+
+ PL_strcat (encoding, orHeaderMnemonic);
+ if (!ignoreValue)
+ err = EncodeImapValue(encoding, value, useQuotes, reallyDredd);
+ }
+
+ // kmcentee, don't let the encoding end with whitespace,
+ // this throws off later url STRCMP
+ if (*encoding && *(encoding + strlen(encoding) - 1) == ' ')
+ *(encoding + strlen(encoding) - 1) = '\0';
+ }
+
+ if (value && valueWasAllocated)
+ NS_Free (value);
+
+ *ppOutTerm = encoding;
+
+ return err;
+}
+
+nsresult nsMsgSearchAdapter::EncodeImapValue(char *encoding, const char *value, bool useQuotes, bool reallyDredd)
+{
+ // By NNTP RFC, SEARCH HEADER SUBJECT "" is legal and means 'find messages without a subject header'
+ if (!reallyDredd)
+ {
+ // By IMAP RFC, SEARCH HEADER SUBJECT "" is illegal and will generate an error from the server
+ if (!value || !value[0])
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ if (!NS_IsAscii(value))
+ {
+ nsAutoCString lengthStr;
+ PL_strcat(encoding, "{");
+ lengthStr.AppendInt((int32_t) strlen(value));
+ PL_strcat(encoding, lengthStr.get());
+ PL_strcat(encoding, "}" CRLF);
+ PL_strcat(encoding, value);
+ return NS_OK;
+ }
+ if (useQuotes)
+ PL_strcat(encoding, "\"");
+ PL_strcat (encoding, value);
+ if (useQuotes)
+ PL_strcat(encoding, "\"");
+
+ return NS_OK;
+}
+
+
+nsresult nsMsgSearchAdapter::EncodeImap (char **ppOutEncoding, nsISupportsArray *searchTerms, const char16_t *srcCharset, const char16_t *destCharset, bool reallyDredd)
+{
+ // i've left the old code (before using CBoolExpression for debugging purposes to make sure that
+ // the new code generates the same encoding string as the old code.....
+
+ nsresult err = NS_OK;
+ *ppOutEncoding = nullptr;
+
+ uint32_t termCount;
+ searchTerms->Count(&termCount);
+ uint32_t i = 0;
+
+ // create our expression
+ nsMsgSearchBoolExpression * expression = new nsMsgSearchBoolExpression();
+ if (!expression)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ for (i = 0; i < termCount && NS_SUCCEEDED(err); i++)
+ {
+ char *termEncoding;
+ bool matchAll;
+ nsCOMPtr<nsIMsgSearchTerm> pTerm;
+ searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
+ (void **)getter_AddRefs(pTerm));
+ pTerm->GetMatchAll(&matchAll);
+ if (matchAll)
+ continue;
+ err = EncodeImapTerm (pTerm, reallyDredd, srcCharset, destCharset, &termEncoding);
+ if (NS_SUCCEEDED(err) && nullptr != termEncoding)
+ {
+ expression = nsMsgSearchBoolExpression::AddSearchTerm(expression, pTerm, termEncoding);
+ delete [] termEncoding;
+ }
+ }
+
+ if (NS_SUCCEEDED(err))
+ {
+ // Catenate the intermediate encodings together into a big string
+ nsAutoCString encodingBuff;
+
+ if (!reallyDredd)
+ encodingBuff.Append(m_kImapUnDeleted);
+
+ expression->GenerateEncodeStr(&encodingBuff);
+ *ppOutEncoding = ToNewCString(encodingBuff);
+ }
+
+ delete expression;
+
+ return err;
+}
+
+
+char *nsMsgSearchAdapter::TransformSpacesToStars (const char *spaceString, msg_TransformType transformType)
+{
+ char *starString;
+
+ if (transformType == kOverwrite)
+ {
+ if ((starString = strdup(spaceString)) != nullptr)
+ {
+ char *star = starString;
+ while ((star = PL_strchr(star, ' ')) != nullptr)
+ *star = '*';
+ }
+ }
+ else
+ {
+ int i, count;
+
+ for (i = 0, count = 0; spaceString[i]; )
+ {
+ if (spaceString[i++] == ' ')
+ {
+ count++;
+ while (spaceString[i] && spaceString[i] == ' ') i++;
+ }
+ }
+
+ if (transformType == kSurround)
+ count *= 2;
+
+ if (count > 0)
+ {
+ if ((starString = (char *)PR_Malloc(i + count + 1)) != nullptr)
+ {
+ int j;
+
+ for (i = 0, j = 0; spaceString[i]; )
+ {
+ if (spaceString[i] == ' ')
+ {
+ starString[j++] = '*';
+ starString[j++] = ' ';
+ if (transformType == kSurround)
+ starString[j++] = '*';
+
+ i++;
+ while (spaceString[i] && spaceString[i] == ' ')
+ i++;
+ }
+ else
+ starString[j++] = spaceString[i++];
+ }
+ starString[j] = 0;
+ }
+ }
+ else
+ starString = strdup(spaceString);
+ }
+
+ return starString;
+}
+
+//-----------------------------------------------------------------------------
+//------------------- Validity checking for menu items etc. -------------------
+//-----------------------------------------------------------------------------
+
+nsMsgSearchValidityTable::nsMsgSearchValidityTable ()
+{
+ // Set everything to be unavailable and disabled
+ for (int i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++)
+ for (int j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++)
+ {
+ SetAvailable (i, j, false);
+ SetEnabled (i, j, false);
+ SetValidButNotShown (i,j, false);
+ }
+ m_numAvailAttribs = 0; // # of attributes marked with at least one available operator
+ // assume default is Subject, which it is for mail and news search
+ // it's not for LDAP, so we'll call SetDefaultAttrib()
+ m_defaultAttrib = nsMsgSearchAttrib::Subject;
+}
+
+NS_IMPL_ISUPPORTS(nsMsgSearchValidityTable, nsIMsgSearchValidityTable)
+
+
+nsresult
+nsMsgSearchValidityTable::GetNumAvailAttribs(int32_t *aResult)
+{
+ m_numAvailAttribs = 0;
+ for (int i = 0; i < nsMsgSearchAttrib::kNumMsgSearchAttributes; i++)
+ for (int j = 0; j < nsMsgSearchOp::kNumMsgSearchOperators; j++) {
+ bool available;
+ GetAvailable(i, j, &available);
+ if (available)
+ {
+ m_numAvailAttribs++;
+ break;
+ }
+ }
+ *aResult = m_numAvailAttribs;
+ return NS_OK;
+}
+
+nsresult
+nsMsgSearchValidityTable::ValidateTerms (nsISupportsArray *searchTerms)
+{
+ nsresult err = NS_OK;
+ uint32_t count;
+
+ NS_ENSURE_ARG(searchTerms);
+
+ searchTerms->Count(&count);
+ for (uint32_t i = 0; i < count; i++)
+ {
+ nsCOMPtr<nsIMsgSearchTerm> pTerm;
+ searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
+ (void **)getter_AddRefs(pTerm));
+
+ nsIMsgSearchTerm *iTerm = pTerm;
+ nsMsgSearchTerm *term = static_cast<nsMsgSearchTerm *>(iTerm);
+// XP_ASSERT(term->IsValid());
+ bool enabled;
+ bool available;
+ GetEnabled(term->m_attribute, term->m_operator, &enabled);
+ GetAvailable(term->m_attribute, term->m_operator, &available);
+ if (!enabled || !available)
+ {
+ bool validNotShown;
+ GetValidButNotShown(term->m_attribute, term->m_operator,
+ &validNotShown);
+ if (!validNotShown)
+ err = NS_MSG_ERROR_INVALID_SEARCH_SCOPE;
+ }
+ }
+
+ return err;
+}
+
+nsresult
+nsMsgSearchValidityTable::GetAvailableAttributes(uint32_t *length,
+ nsMsgSearchAttribValue **aResult)
+{
+ NS_ENSURE_ARG_POINTER(length);
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ // count first
+ uint32_t totalAttributes=0;
+ int32_t i, j;
+ for (i = 0; i< nsMsgSearchAttrib::kNumMsgSearchAttributes; i++) {
+ for (j=0; j< nsMsgSearchOp::kNumMsgSearchOperators; j++) {
+ if (m_table[i][j].bitAvailable) {
+ totalAttributes++;
+ break;
+ }
+ }
+ }
+
+ nsMsgSearchAttribValue *array = (nsMsgSearchAttribValue*)
+ moz_xmalloc(sizeof(nsMsgSearchAttribValue) * totalAttributes);
+ NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
+
+ uint32_t numStored=0;
+ for (i = 0; i< nsMsgSearchAttrib::kNumMsgSearchAttributes; i++) {
+ for (j=0; j< nsMsgSearchOp::kNumMsgSearchOperators; j++) {
+ if (m_table[i][j].bitAvailable) {
+ array[numStored++] = i;
+ break;
+ }
+ }
+ }
+
+ NS_ASSERTION(totalAttributes == numStored, "Search Attributes not lining up");
+ *length = totalAttributes;
+ *aResult = array;
+
+ return NS_OK;
+}
+
+nsresult
+nsMsgSearchValidityTable::GetAvailableOperators(nsMsgSearchAttribValue aAttribute,
+ uint32_t *aLength,
+ nsMsgSearchOpValue **aResult)
+{
+ NS_ENSURE_ARG_POINTER(aLength);
+ NS_ENSURE_ARG_POINTER(aResult);
+
+ nsMsgSearchAttribValue attr;
+ if (aAttribute == nsMsgSearchAttrib::Default)
+ attr = m_defaultAttrib;
+ else
+ attr = std::min(aAttribute,
+ (nsMsgSearchAttribValue)nsMsgSearchAttrib::OtherHeader);
+
+ uint32_t totalOperators=0;
+ int32_t i;
+ for (i=0; i<nsMsgSearchOp::kNumMsgSearchOperators; i++) {
+ if (m_table[attr][i].bitAvailable)
+ totalOperators++;
+ }
+
+ nsMsgSearchOpValue *array = (nsMsgSearchOpValue*)
+ moz_xmalloc(sizeof(nsMsgSearchOpValue) * totalOperators);
+ NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
+
+ uint32_t numStored = 0;
+ for (i=0; i<nsMsgSearchOp::kNumMsgSearchOperators;i++) {
+ if (m_table[attr][i].bitAvailable)
+ array[numStored++] = i;
+ }
+
+ NS_ASSERTION(totalOperators == numStored, "Search Operators not lining up");
+ *aLength = totalOperators;
+ *aResult = array;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMsgSearchValidityTable::SetDefaultAttrib(nsMsgSearchAttribValue aAttribute)
+{
+ m_defaultAttrib = aAttribute;
+ return NS_OK;
+}
+
+
+nsMsgSearchValidityManager::nsMsgSearchValidityManager ()
+{
+}
+
+
+nsMsgSearchValidityManager::~nsMsgSearchValidityManager ()
+{
+ // tables released by nsCOMPtr
+}
+
+NS_IMPL_ISUPPORTS(nsMsgSearchValidityManager, nsIMsgSearchValidityManager)
+
+//-----------------------------------------------------------------------------
+// Bottleneck accesses to the objects so we can allocate and initialize them
+// lazily. This way, there's no heap overhead for the validity tables until the
+// user actually searches that scope.
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP nsMsgSearchValidityManager::GetTable (int whichTable, nsIMsgSearchValidityTable **ppOutTable)
+{
+ NS_ENSURE_ARG_POINTER(ppOutTable);
+
+ nsresult rv;
+ *ppOutTable = nullptr;
+
+ nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ nsCString customHeaders;
+ if (NS_SUCCEEDED(rv))
+ pref->GetCharPref(PREF_CUSTOM_HEADERS, getter_Copies(customHeaders));
+
+ switch (whichTable)
+ {
+ case nsMsgSearchScope::offlineMail:
+ if (!m_offlineMailTable)
+ rv = InitOfflineMailTable ();
+ if (m_offlineMailTable)
+ rv = SetOtherHeadersInTable(m_offlineMailTable, customHeaders.get());
+ *ppOutTable = m_offlineMailTable;
+ break;
+ case nsMsgSearchScope::offlineMailFilter:
+ if (!m_offlineMailFilterTable)
+ rv = InitOfflineMailFilterTable ();
+ if (m_offlineMailFilterTable)
+ rv = SetOtherHeadersInTable(m_offlineMailFilterTable, customHeaders.get());
+ *ppOutTable = m_offlineMailFilterTable;
+ break;
+ case nsMsgSearchScope::onlineMail:
+ if (!m_onlineMailTable)
+ rv = InitOnlineMailTable ();
+ if (m_onlineMailTable)
+ rv = SetOtherHeadersInTable(m_onlineMailTable, customHeaders.get());
+ *ppOutTable = m_onlineMailTable;
+ break;
+ case nsMsgSearchScope::onlineMailFilter:
+ if (!m_onlineMailFilterTable)
+ rv = InitOnlineMailFilterTable ();
+ if (m_onlineMailFilterTable)
+ rv = SetOtherHeadersInTable(m_onlineMailFilterTable, customHeaders.get());
+ *ppOutTable = m_onlineMailFilterTable;
+ break;
+ case nsMsgSearchScope::news:
+ if (!m_newsTable)
+ rv = InitNewsTable();
+ if (m_newsTable)
+ rv = SetOtherHeadersInTable(m_newsTable, customHeaders.get());
+ *ppOutTable = m_newsTable;
+ break;
+ case nsMsgSearchScope::newsFilter:
+ if (!m_newsFilterTable)
+ rv = InitNewsFilterTable();
+ if (m_newsFilterTable)
+ rv = SetOtherHeadersInTable(m_newsFilterTable, customHeaders.get());
+ *ppOutTable = m_newsFilterTable;
+ break;
+ case nsMsgSearchScope::localNews:
+ if (!m_localNewsTable)
+ rv = InitLocalNewsTable();
+ if (m_localNewsTable)
+ rv = SetOtherHeadersInTable(m_localNewsTable, customHeaders.get());
+ *ppOutTable = m_localNewsTable;
+ break;
+ case nsMsgSearchScope::localNewsJunk:
+ if (!m_localNewsJunkTable)
+ rv = InitLocalNewsJunkTable();
+ if (m_localNewsJunkTable)
+ rv = SetOtherHeadersInTable(m_localNewsJunkTable, customHeaders.get());
+ *ppOutTable = m_localNewsJunkTable;
+ break;
+ case nsMsgSearchScope::localNewsBody:
+ if (!m_localNewsBodyTable)
+ rv = InitLocalNewsBodyTable();
+ if (m_localNewsBodyTable)
+ rv = SetOtherHeadersInTable(m_localNewsBodyTable, customHeaders.get());
+ *ppOutTable = m_localNewsBodyTable;
+ break;
+ case nsMsgSearchScope::localNewsJunkBody:
+ if (!m_localNewsJunkBodyTable)
+ rv = InitLocalNewsJunkBodyTable();
+ if (m_localNewsJunkBodyTable)
+ rv = SetOtherHeadersInTable(m_localNewsJunkBodyTable, customHeaders.get());
+ *ppOutTable = m_localNewsJunkBodyTable;
+ break;
+
+ case nsMsgSearchScope::onlineManual:
+ if (!m_onlineManualFilterTable)
+ rv = InitOnlineManualFilterTable();
+ if (m_onlineManualFilterTable)
+ rv = SetOtherHeadersInTable(m_onlineManualFilterTable, customHeaders.get());
+ *ppOutTable = m_onlineManualFilterTable;
+ break;
+ case nsMsgSearchScope::LDAP:
+ if (!m_ldapTable)
+ rv = InitLdapTable ();
+ *ppOutTable = m_ldapTable;
+ break;
+ case nsMsgSearchScope::LDAPAnd:
+ if (!m_ldapAndTable)
+ rv = InitLdapAndTable ();
+ *ppOutTable = m_ldapAndTable;
+ break;
+ case nsMsgSearchScope::LocalAB:
+ if (!m_localABTable)
+ rv = InitLocalABTable ();
+ *ppOutTable = m_localABTable;
+ break;
+ case nsMsgSearchScope::LocalABAnd:
+ if (!m_localABAndTable)
+ rv = InitLocalABAndTable ();
+ *ppOutTable = m_localABAndTable;
+ break;
+ default:
+ NS_ASSERTION(false, "invalid table type");
+ rv = NS_MSG_ERROR_INVALID_SEARCH_TERM;
+ }
+
+ NS_IF_ADDREF(*ppOutTable);
+ return rv;
+}
+
+// mapping between ordered attribute values, and property strings
+// see search-attributes.properties
+static struct
+{
+ nsMsgSearchAttribValue id;
+ const char* property;
+}
+nsMsgSearchAttribMap[] =
+{
+ {nsMsgSearchAttrib::Subject, "Subject"},
+ {nsMsgSearchAttrib::Sender, "From"},
+ {nsMsgSearchAttrib::Body, "Body"},
+ {nsMsgSearchAttrib::Date, "Date"},
+ {nsMsgSearchAttrib::Priority, "Priority"},
+ {nsMsgSearchAttrib::MsgStatus, "Status"},
+ {nsMsgSearchAttrib::To, "To"},
+ {nsMsgSearchAttrib::CC, "Cc"},
+ {nsMsgSearchAttrib::ToOrCC, "ToOrCc"},
+ {nsMsgSearchAttrib::AgeInDays, "AgeInDays"},
+ {nsMsgSearchAttrib::Size, "SizeKB"},
+ {nsMsgSearchAttrib::Keywords, "Tags"},
+ {nsMsgSearchAttrib::Name, "AnyName"},
+ {nsMsgSearchAttrib::DisplayName, "DisplayName"},
+ {nsMsgSearchAttrib::Nickname, "Nickname"},
+ {nsMsgSearchAttrib::ScreenName, "ScreenName"},
+ {nsMsgSearchAttrib::Email, "Email"},
+ {nsMsgSearchAttrib::AdditionalEmail, "AdditionalEmail"},
+ {nsMsgSearchAttrib::PhoneNumber, "AnyNumber"},
+ {nsMsgSearchAttrib::WorkPhone, "WorkPhone"},
+ {nsMsgSearchAttrib::HomePhone, "HomePhone"},
+ {nsMsgSearchAttrib::Fax, "Fax"},
+ {nsMsgSearchAttrib::Pager, "Pager"},
+ {nsMsgSearchAttrib::Mobile, "Mobile"},
+ {nsMsgSearchAttrib::City, "City"},
+ {nsMsgSearchAttrib::Street, "Street"},
+ {nsMsgSearchAttrib::Title, "Title"},
+ {nsMsgSearchAttrib::Organization, "Organization"},
+ {nsMsgSearchAttrib::Department, "Department"},
+ {nsMsgSearchAttrib::AllAddresses, "FromToCcOrBcc"},
+ {nsMsgSearchAttrib::JunkScoreOrigin, "JunkScoreOrigin"},
+ {nsMsgSearchAttrib::JunkPercent, "JunkPercent"},
+ {nsMsgSearchAttrib::HasAttachmentStatus, "AttachmentStatus"},
+ {nsMsgSearchAttrib::JunkStatus, "JunkStatus"},
+ {nsMsgSearchAttrib::Label, "Label"},
+ {nsMsgSearchAttrib::OtherHeader, "Customize"},
+ // the last id is -1 to denote end of table
+ {-1, ""}
+};
+
+NS_IMETHODIMP
+nsMsgSearchValidityManager::GetAttributeProperty(nsMsgSearchAttribValue aSearchAttribute,
+ nsAString& aProperty)
+{
+ for (int32_t i = 0; nsMsgSearchAttribMap[i].id >= 0; ++i)
+ {
+ if (nsMsgSearchAttribMap[i].id == aSearchAttribute)
+ {
+ aProperty.Assign(NS_ConvertUTF8toUTF16(nsMsgSearchAttribMap[i].property));
+ return NS_OK;
+ }
+ }
+ return NS_ERROR_FAILURE;
+}
+
+nsresult
+nsMsgSearchValidityManager::NewTable(nsIMsgSearchValidityTable **aTable)
+{
+ NS_ENSURE_ARG_POINTER(aTable);
+ *aTable = new nsMsgSearchValidityTable;
+ if (!*aTable)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(*aTable);
+ return NS_OK;
+}
+
+nsresult
+nsMsgSearchValidityManager::SetOtherHeadersInTable (nsIMsgSearchValidityTable *aTable, const char *customHeaders)
+{
+ uint32_t customHeadersLength = strlen(customHeaders);
+ uint32_t numHeaders=0;
+ if (customHeadersLength)
+ {
+ nsAutoCString hdrStr(customHeaders);
+ hdrStr.StripWhitespace(); //remove whitespace before parsing
+ char *newStr = hdrStr.BeginWriting();
+ char *token = NS_strtok(":", &newStr);
+ while(token)
+ {
+ numHeaders++;
+ token = NS_strtok(":", &newStr);
+ }
+ }
+
+ NS_ASSERTION(nsMsgSearchAttrib::OtherHeader + numHeaders < nsMsgSearchAttrib::kNumMsgSearchAttributes, "more headers than the table can hold");
+
+ uint32_t maxHdrs = std::min(nsMsgSearchAttrib::OtherHeader + numHeaders + 1,
+ (uint32_t)nsMsgSearchAttrib::kNumMsgSearchAttributes);
+ for (uint32_t i=nsMsgSearchAttrib::OtherHeader+1;i< maxHdrs;i++)
+ {
+ aTable->SetAvailable (i, nsMsgSearchOp::Contains, 1); // added for arbitrary headers
+ aTable->SetEnabled (i, nsMsgSearchOp::Contains, 1);
+ aTable->SetAvailable (i, nsMsgSearchOp::DoesntContain, 1);
+ aTable->SetEnabled (i, nsMsgSearchOp::DoesntContain, 1);
+ aTable->SetAvailable (i, nsMsgSearchOp::Is, 1);
+ aTable->SetEnabled (i, nsMsgSearchOp::Is, 1);
+ aTable->SetAvailable (i, nsMsgSearchOp::Isnt, 1);
+ aTable->SetEnabled (i, nsMsgSearchOp::Isnt, 1);
+ }
+ //because custom headers can change; so reset the table for those which are no longer used.
+ for (uint32_t j=maxHdrs; j < nsMsgSearchAttrib::kNumMsgSearchAttributes; j++)
+ {
+ for (uint32_t k=0; k < nsMsgSearchOp::kNumMsgSearchOperators; k++)
+ {
+ aTable->SetAvailable(j,k,0);
+ aTable->SetEnabled(j,k,0);
+ }
+ }
+ return NS_OK;
+}
+
+nsresult nsMsgSearchValidityManager::EnableDirectoryAttribute(nsIMsgSearchValidityTable *table, nsMsgSearchAttribValue aSearchAttrib)
+{
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::Contains, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::Contains, 1);
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::DoesntContain, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::DoesntContain, 1);
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::Is, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::Is, 1);
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::Isnt, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::Isnt, 1);
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::BeginsWith, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::BeginsWith, 1);
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::EndsWith, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::EndsWith, 1);
+ table->SetAvailable (aSearchAttrib, nsMsgSearchOp::SoundsLike, 1);
+ table->SetEnabled (aSearchAttrib, nsMsgSearchOp::SoundsLike, 1);
+ return NS_OK;
+}
+
+nsresult nsMsgSearchValidityManager::InitLdapTable()
+{
+ NS_ASSERTION(!m_ldapTable,"don't call this twice!");
+
+ nsresult rv = NewTable(getter_AddRefs(m_ldapTable));
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = SetUpABTable(m_ldapTable, true);
+ NS_ENSURE_SUCCESS(rv,rv);
+ return rv;
+}
+
+nsresult nsMsgSearchValidityManager::InitLdapAndTable()
+{
+ NS_ASSERTION(!m_ldapAndTable,"don't call this twice!");
+
+ nsresult rv = NewTable(getter_AddRefs(m_ldapAndTable));
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = SetUpABTable(m_ldapAndTable, false);
+ NS_ENSURE_SUCCESS(rv,rv);
+ return rv;
+}
+
+nsresult nsMsgSearchValidityManager::InitLocalABTable()
+{
+ NS_ASSERTION(!m_localABTable,"don't call this twice!");
+
+ nsresult rv = NewTable(getter_AddRefs(m_localABTable));
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = SetUpABTable(m_localABTable, true);
+ NS_ENSURE_SUCCESS(rv,rv);
+ return rv;
+}
+
+nsresult nsMsgSearchValidityManager::InitLocalABAndTable()
+{
+ NS_ASSERTION(!m_localABAndTable,"don't call this twice!");
+
+ nsresult rv = NewTable(getter_AddRefs(m_localABAndTable));
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = SetUpABTable(m_localABAndTable, false);
+ NS_ENSURE_SUCCESS(rv,rv);
+ return rv;
+}
+
+nsresult
+nsMsgSearchValidityManager::SetUpABTable(nsIMsgSearchValidityTable *aTable, bool isOrTable)
+{
+ nsresult rv = aTable->SetDefaultAttrib(isOrTable ? nsMsgSearchAttrib::Name : nsMsgSearchAttrib::DisplayName);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ if (isOrTable) {
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Name);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::PhoneNumber);
+ NS_ENSURE_SUCCESS(rv,rv);
+ }
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::DisplayName);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Email);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::AdditionalEmail);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::ScreenName);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Street);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::City);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Title);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Organization);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Department);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Nickname);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::WorkPhone);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::HomePhone);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Fax);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Pager);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ rv = EnableDirectoryAttribute(aTable, nsMsgSearchAttrib::Mobile);
+ NS_ENSURE_SUCCESS(rv,rv);
+
+ return rv;
+}