зеркало из https://github.com/mozilla/pjs.git
fix searching for non 7bit ascii characters with imap 243625 sr=mscott
This commit is contained in:
Родитель
deb1a2db69
Коммит
d78bb30101
|
@ -111,55 +111,55 @@ nsresult nsMsgSearchOnlineMail::Encode (nsCString& pEncoding,
|
|||
nsISupportsArray *searchTerms,
|
||||
const PRUnichar *destCharset)
|
||||
{
|
||||
nsXPIDLCString imapTerms;
|
||||
|
||||
//check if searchTerms are ascii only
|
||||
PRBool asciiOnly = PR_TRUE;
|
||||
nsXPIDLCString imapTerms;
|
||||
|
||||
//check if searchTerms are ascii only
|
||||
PRBool asciiOnly = PR_TRUE;
|
||||
// ### what's this mean in the NWO?????
|
||||
|
||||
if (PR_TRUE) // !(srcCharset & CODESET_MASK == STATEFUL || srcCharset & CODESET_MASK == WIDECHAR) ) //assume all single/multiple bytes charset has ascii as subset
|
||||
{
|
||||
PRUint32 termCount;
|
||||
|
||||
if (PR_TRUE) // !(srcCharset & CODESET_MASK == STATEFUL || srcCharset & CODESET_MASK == WIDECHAR) ) //assume all single/multiple bytes charset has ascii as subset
|
||||
{
|
||||
PRUint32 termCount;
|
||||
searchTerms->Count(&termCount);
|
||||
PRUint32 i = 0;
|
||||
|
||||
for (i = 0; i < termCount && asciiOnly; i++)
|
||||
{
|
||||
PRUint32 i = 0;
|
||||
|
||||
for (i = 0; i < termCount && asciiOnly; i++)
|
||||
{
|
||||
nsCOMPtr<nsIMsgSearchTerm> pTerm;
|
||||
searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
|
||||
(void **)getter_AddRefs(pTerm));
|
||||
|
||||
(void **)getter_AddRefs(pTerm));
|
||||
|
||||
nsMsgSearchAttribValue attribute;
|
||||
pTerm->GetAttrib(&attribute);
|
||||
if (IsStringAttribute(attribute))
|
||||
{
|
||||
if (IsStringAttribute(attribute))
|
||||
{
|
||||
nsXPIDLString pchar;
|
||||
nsCOMPtr <nsIMsgSearchValue> searchValue;
|
||||
|
||||
|
||||
nsresult rv = pTerm->GetValue(getter_AddRefs(searchValue));
|
||||
if (NS_FAILED(rv) || !searchValue)
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
|
||||
rv = searchValue->GetStr(getter_Copies(pchar));
|
||||
if (NS_FAILED(rv) || !pchar)
|
||||
continue;
|
||||
if (NS_FAILED(rv) || !pchar)
|
||||
continue;
|
||||
asciiOnly = nsCRT::IsAscii(pchar.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
asciiOnly = PR_FALSE;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
asciiOnly = PR_FALSE;
|
||||
|
||||
nsAutoString usAsciiCharSet(NS_LITERAL_STRING("us-ascii"));
|
||||
// Get the optional CHARSET parameter, in case we need it.
|
||||
// Get the optional CHARSET parameter, in case we need it.
|
||||
char *csname = GetImapCharsetParam(asciiOnly ? usAsciiCharSet.get() : destCharset);
|
||||
|
||||
|
||||
// We do not need "srcCharset" since the search term in always unicode.
|
||||
// I just pass destCharset for both src and dest charset instead of removing srcCharst from the arguemnt.
|
||||
nsresult err = nsMsgSearchAdapter::EncodeImap (getter_Copies(imapTerms), searchTerms,
|
||||
asciiOnly ? usAsciiCharSet.get(): destCharset,
|
||||
asciiOnly ? usAsciiCharSet.get(): destCharset, PR_FALSE);
|
||||
asciiOnly ? usAsciiCharSet.get(): destCharset,
|
||||
asciiOnly ? usAsciiCharSet.get(): destCharset, PR_FALSE);
|
||||
if (NS_SUCCEEDED(err))
|
||||
{
|
||||
pEncoding.Append("SEARCH");
|
||||
|
|
|
@ -391,401 +391,412 @@ nsresult nsMsgSearchAdapter::EncodeImapTerm (nsIMsgSearchTerm *term, PRBool real
|
|||
char *arbitraryHeader = nsnull;
|
||||
const char *whichMnemonic = nsnull;
|
||||
const char *orHeaderMnemonic = nsnull;
|
||||
|
||||
|
||||
*ppOutTerm = nsnull;
|
||||
|
||||
|
||||
nsCOMPtr <nsIMsgSearchValue> searchValue;
|
||||
nsresult rv = term->GetValue(getter_AddRefs(searchValue));
|
||||
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
||||
nsMsgSearchOpValue op;
|
||||
term->GetOp(&op);
|
||||
|
||||
if (op == nsMsgSearchOp::DoesntContain || op == nsMsgSearchOp::Isnt)
|
||||
useNot = PR_TRUE;
|
||||
|
||||
|
||||
if (op == nsMsgSearchOp::DoesntContain || op == nsMsgSearchOp::Isnt)
|
||||
useNot = PR_TRUE;
|
||||
|
||||
nsMsgSearchAttribValue attrib;
|
||||
term->GetAttrib(&attrib);
|
||||
|
||||
switch (attrib)
|
||||
{
|
||||
case nsMsgSearchAttrib::ToOrCC:
|
||||
orHeaderMnemonic = m_kImapCC;
|
||||
// fall through to case nsMsgSearchAttrib::To:
|
||||
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;
|
||||
excludeHeader = PR_TRUE;
|
||||
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!
|
||||
switch (op)
|
||||
{
|
||||
case nsMsgSearchOp::IsGreaterThan:
|
||||
whichMnemonic = m_kImapBefore;
|
||||
break;
|
||||
case nsMsgSearchOp::IsLessThan:
|
||||
whichMnemonic = m_kImapSince;
|
||||
break;
|
||||
case nsMsgSearchOp::Is:
|
||||
whichMnemonic = m_kImapSentOn;
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
excludeHeader = PR_TRUE;
|
||||
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(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
excludeHeader = PR_TRUE;
|
||||
break;
|
||||
case nsMsgSearchAttrib::AnyText:
|
||||
whichMnemonic = m_kImapAnyText;
|
||||
excludeHeader = PR_TRUE;
|
||||
break;
|
||||
case nsMsgSearchAttrib::Keywords:
|
||||
whichMnemonic = m_kNntpKeywords;
|
||||
break;
|
||||
case nsMsgSearchAttrib::MsgStatus:
|
||||
useNot = PR_FALSE; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
|
||||
ignoreValue = PR_TRUE; // the mnemonic is all we need
|
||||
excludeHeader = PR_TRUE;
|
||||
PRUint32 status;
|
||||
searchValue->GetStatus(&status);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case MSG_FLAG_READ:
|
||||
whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapSeen : m_kImapNotSeen;
|
||||
break;
|
||||
case MSG_FLAG_REPLIED:
|
||||
whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapAnswered : m_kImapNotAnswered;
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ( attrib > nsMsgSearchAttrib::OtherHeader && attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes)
|
||||
|
||||
switch (attrib)
|
||||
{
|
||||
case nsMsgSearchAttrib::ToOrCC:
|
||||
orHeaderMnemonic = m_kImapCC;
|
||||
// fall through to case nsMsgSearchAttrib::To:
|
||||
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;
|
||||
excludeHeader = PR_TRUE;
|
||||
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!
|
||||
switch (op)
|
||||
{
|
||||
nsXPIDLCString arbitraryHeaderTerm;
|
||||
term->GetArbitraryHeader(getter_Copies(arbitraryHeaderTerm));
|
||||
if (!arbitraryHeaderTerm.IsEmpty())
|
||||
{
|
||||
arbitraryHeader = new char [strlen((const char *)arbitraryHeaderTerm) + 6]; // 6 bytes for SPACE \" .... \" SPACE
|
||||
if (!arbitraryHeader)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
arbitraryHeader[0] = '\0';
|
||||
PL_strcat(arbitraryHeader, " \"");
|
||||
PL_strcat(arbitraryHeader, (const char *)arbitraryHeaderTerm);
|
||||
PL_strcat(arbitraryHeader, "\" ");
|
||||
whichMnemonic = arbitraryHeader;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
case nsMsgSearchOp::IsGreaterThan:
|
||||
whichMnemonic = m_kImapBefore;
|
||||
break;
|
||||
case nsMsgSearchOp::IsLessThan:
|
||||
whichMnemonic = m_kImapSince;
|
||||
break;
|
||||
case nsMsgSearchOp::Is:
|
||||
whichMnemonic = m_kImapSentOn;
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
char *value = "";
|
||||
char dateBuf[100];
|
||||
dateBuf[0] = '\0';
|
||||
|
||||
PRBool valueWasAllocated = PR_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.
|
||||
// ack, is this right? is PRTime seconds or microseconds?
|
||||
PRInt64 microSecondsPerSecond, secondsInDay, microSecondsInDay;
|
||||
|
||||
LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
|
||||
LL_UI2L(secondsInDay, 60 * 60 * 24);
|
||||
LL_MUL(microSecondsInDay, secondsInDay, microSecondsPerSecond);
|
||||
LL_ADD(adjustedDate, adjustedDate, microSecondsInDay); // bump up to the day after this one...
|
||||
}
|
||||
|
||||
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.
|
||||
PRUint32 ageInDays;
|
||||
|
||||
searchValue->GetAge(&ageInDays);
|
||||
|
||||
PRTime now = PR_Now();
|
||||
PRTime matchDay;
|
||||
|
||||
PRInt64 microSecondsPerSecond, secondsInDays, microSecondsInDay;
|
||||
|
||||
LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
|
||||
LL_UI2L(secondsInDays, 60 * 60 * 24 * ageInDays);
|
||||
LL_MUL(microSecondsInDay, secondsInDays, microSecondsPerSecond);
|
||||
|
||||
LL_SUB(matchDay, now, microSecondsInDay); // = now - term->m_value.u.age * 60 * 60 * 24;
|
||||
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 (IsStringAttribute(attrib))
|
||||
{
|
||||
PRUnichar *convertedValue; // = reallyDredd ? MSG_EscapeSearchUrl (term->m_value.u.string) : msg_EscapeImapSearchProtocol(term->m_value.u.string);
|
||||
nsXPIDLString searchTermValue;
|
||||
searchValue->GetStr(getter_Copies(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) :
|
||||
EscapeImapSearchProtocol(searchTermValue);
|
||||
useQuotes = !reallyDredd ||
|
||||
(nsDependentString(convertedValue).FindChar(PRUnichar(' ')) != -1);
|
||||
// now convert to char* and escape quoted_specials
|
||||
nsCAutoString valueStr;
|
||||
nsresult rv = ConvertFromUnicode(NS_LossyConvertUTF16toASCII(destCharset).get(),
|
||||
nsDependentString(convertedValue), valueStr);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
excludeHeader = PR_TRUE;
|
||||
break;
|
||||
case nsMsgSearchAttrib::Date:
|
||||
switch (op)
|
||||
{
|
||||
const char *vptr = valueStr.get();
|
||||
// max escaped length is one extra character for every character in the cmd.
|
||||
nsAutoArrayPtr<char> newValue(new char[2*strlen(vptr) + 1]);
|
||||
if (newValue)
|
||||
{
|
||||
char *p = newValue;
|
||||
while (1)
|
||||
{
|
||||
char ch = *vptr++;
|
||||
if (!ch)
|
||||
break;
|
||||
if ((useQuotes ? ch == '"' : 0) || ch == '\\')
|
||||
*p++ = '\\';
|
||||
*p++ = ch;
|
||||
}
|
||||
*p = '\0';
|
||||
value = nsCRT::strdup(newValue); // realloc down to smaller size
|
||||
}
|
||||
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(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
else
|
||||
value = nsCRT::strdup("");
|
||||
nsCRT::free(convertedValue);
|
||||
valueWasAllocated = PR_TRUE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int len = strlen(whichMnemonic) + strlen(value) + (useNot ? strlen(m_kImapNot) : 0) +
|
||||
(useQuotes ? 2 : 0) + strlen(m_kImapHeader) +
|
||||
(orHeaderMnemonic ? (strlen(m_kImapHeader) + strlen(m_kImapOr) + (useNot ? strlen(m_kImapNot) : 0) +
|
||||
strlen(orHeaderMnemonic) + strlen(value) + 2 /*""*/) : 0) + 1;
|
||||
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 (!excludeHeader)
|
||||
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)
|
||||
PR_Free (value);
|
||||
if (arbitraryHeader)
|
||||
delete arbitraryHeader;
|
||||
|
||||
*ppOutTerm = encoding;
|
||||
|
||||
return err;
|
||||
excludeHeader = PR_TRUE;
|
||||
break;
|
||||
case nsMsgSearchAttrib::AnyText:
|
||||
whichMnemonic = m_kImapAnyText;
|
||||
excludeHeader = PR_TRUE;
|
||||
break;
|
||||
case nsMsgSearchAttrib::Keywords:
|
||||
whichMnemonic = m_kNntpKeywords;
|
||||
break;
|
||||
case nsMsgSearchAttrib::MsgStatus:
|
||||
useNot = PR_FALSE; // bizarrely, NOT SEEN is wrong, but UNSEEN is right.
|
||||
ignoreValue = PR_TRUE; // the mnemonic is all we need
|
||||
excludeHeader = PR_TRUE;
|
||||
PRUint32 status;
|
||||
searchValue->GetStatus(&status);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case MSG_FLAG_READ:
|
||||
whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapSeen : m_kImapNotSeen;
|
||||
break;
|
||||
case MSG_FLAG_REPLIED:
|
||||
whichMnemonic = op == nsMsgSearchOp::Is ? m_kImapAnswered : m_kImapNotAnswered;
|
||||
break;
|
||||
default:
|
||||
NS_ASSERTION(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ( attrib > nsMsgSearchAttrib::OtherHeader && attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes)
|
||||
{
|
||||
nsXPIDLCString arbitraryHeaderTerm;
|
||||
term->GetArbitraryHeader(getter_Copies(arbitraryHeaderTerm));
|
||||
if (!arbitraryHeaderTerm.IsEmpty())
|
||||
{
|
||||
arbitraryHeader = new char [strlen((const char *)arbitraryHeaderTerm) + 6]; // 6 bytes for SPACE \" .... \" SPACE
|
||||
if (!arbitraryHeader)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
arbitraryHeader[0] = '\0';
|
||||
PL_strcat(arbitraryHeader, " \"");
|
||||
PL_strcat(arbitraryHeader, (const char *)arbitraryHeaderTerm);
|
||||
PL_strcat(arbitraryHeader, "\" ");
|
||||
whichMnemonic = arbitraryHeader;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "invalid search operator");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
char *value = "";
|
||||
char dateBuf[100];
|
||||
dateBuf[0] = '\0';
|
||||
|
||||
PRBool valueWasAllocated = PR_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.
|
||||
// ack, is this right? is PRTime seconds or microseconds?
|
||||
PRInt64 microSecondsPerSecond, secondsInDay, microSecondsInDay;
|
||||
|
||||
LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
|
||||
LL_UI2L(secondsInDay, 60 * 60 * 24);
|
||||
LL_MUL(microSecondsInDay, secondsInDay, microSecondsPerSecond);
|
||||
LL_ADD(adjustedDate, adjustedDate, microSecondsInDay); // bump up to the day after this one...
|
||||
}
|
||||
|
||||
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.
|
||||
PRUint32 ageInDays;
|
||||
|
||||
searchValue->GetAge(&ageInDays);
|
||||
|
||||
PRTime now = PR_Now();
|
||||
PRTime matchDay;
|
||||
|
||||
PRInt64 microSecondsPerSecond, secondsInDays, microSecondsInDay;
|
||||
|
||||
LL_I2L(microSecondsPerSecond, PR_USEC_PER_SEC);
|
||||
LL_UI2L(secondsInDays, 60 * 60 * 24 * ageInDays);
|
||||
LL_MUL(microSecondsInDay, secondsInDays, microSecondsPerSecond);
|
||||
|
||||
LL_SUB(matchDay, now, microSecondsInDay); // = now - term->m_value.u.age * 60 * 60 * 24;
|
||||
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 (IsStringAttribute(attrib))
|
||||
{
|
||||
PRUnichar *convertedValue; // = reallyDredd ? MSG_EscapeSearchUrl (term->m_value.u.string) : msg_EscapeImapSearchProtocol(term->m_value.u.string);
|
||||
nsXPIDLString searchTermValue;
|
||||
searchValue->GetStr(getter_Copies(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) :
|
||||
EscapeImapSearchProtocol(searchTermValue);
|
||||
useQuotes = !reallyDredd ||
|
||||
(nsDependentString(convertedValue).FindChar(PRUnichar(' ')) != -1);
|
||||
// now convert to char* and escape quoted_specials
|
||||
nsCAutoString 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.
|
||||
nsAutoArrayPtr<char> newValue(new char[2*strlen(vptr) + 1]);
|
||||
if (newValue)
|
||||
{
|
||||
char *p = newValue;
|
||||
while (1)
|
||||
{
|
||||
char ch = *vptr++;
|
||||
if (!ch)
|
||||
break;
|
||||
if ((useQuotes ? ch == '"' : 0) || ch == '\\')
|
||||
*p++ = '\\';
|
||||
*p++ = ch;
|
||||
}
|
||||
*p = '\0';
|
||||
value = nsCRT::strdup(newValue); // realloc down to smaller size
|
||||
}
|
||||
}
|
||||
else
|
||||
value = nsCRT::strdup("");
|
||||
nsCRT::free(convertedValue);
|
||||
valueWasAllocated = PR_TRUE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// this should be rewritten to use nsCString
|
||||
int len = strlen(whichMnemonic) + strlen(value) + (useNot ? strlen(m_kImapNot) : 0) +
|
||||
(useQuotes ? 2 : 0) + strlen(m_kImapHeader) +
|
||||
(orHeaderMnemonic ? (strlen(m_kImapHeader) + strlen(m_kImapOr) + (useNot ? strlen(m_kImapNot) : 0) +
|
||||
strlen(orHeaderMnemonic) + strlen(value) + 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 (!excludeHeader)
|
||||
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)
|
||||
PR_Free (value);
|
||||
if (arbitraryHeader)
|
||||
delete arbitraryHeader;
|
||||
|
||||
*ppOutTerm = encoding;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
nsresult nsMsgSearchAdapter::EncodeImapValue(char *encoding, const char *value, PRBool useQuotes, PRBool 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 (useQuotes)
|
||||
PL_strcat(encoding, "\"");
|
||||
PL_strcat (encoding, value);
|
||||
if (useQuotes)
|
||||
PL_strcat(encoding, "\"");
|
||||
|
||||
return NS_OK;
|
||||
// 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 (!nsCRT::IsAscii(value))
|
||||
{
|
||||
nsCAutoString lengthStr;
|
||||
PL_strcat(encoding, "{");
|
||||
lengthStr.AppendInt(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 PRUnichar *srcCharset, const PRUnichar *destCharset, PRBool 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 = nsnull;
|
||||
|
||||
PRUint32 termCount;
|
||||
// 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 = nsnull;
|
||||
|
||||
PRUint32 termCount;
|
||||
searchTerms->Count(&termCount);
|
||||
PRUint32 i = 0;
|
||||
int encodingLength = 0;
|
||||
|
||||
// Build up an array of encodings, one per query term
|
||||
char **termEncodings = new char *[termCount];
|
||||
if (!termEncodings)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// create our expression
|
||||
nsMsgSearchBoolExpression * expression = new nsMsgSearchBoolExpression();
|
||||
if (!expression)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (i = 0; i < termCount && NS_SUCCEEDED(err); i++)
|
||||
{
|
||||
PRUint32 i = 0;
|
||||
int encodingLength = 0;
|
||||
|
||||
// Build up an array of encodings, one per query term
|
||||
char **termEncodings = new char *[termCount];
|
||||
if (!termEncodings)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// create our expression
|
||||
nsMsgSearchBoolExpression * expression = new nsMsgSearchBoolExpression();
|
||||
if (!expression)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (i = 0; i < termCount && NS_SUCCEEDED(err); i++)
|
||||
{
|
||||
nsCOMPtr<nsIMsgSearchTerm> pTerm;
|
||||
searchTerms->QueryElementAt(i, NS_GET_IID(nsIMsgSearchTerm),
|
||||
(void **)getter_AddRefs(pTerm));
|
||||
err = EncodeImapTerm (pTerm, reallyDredd, srcCharset, destCharset, &termEncodings[i]);
|
||||
if (NS_SUCCEEDED(err) && nsnull != termEncodings[i])
|
||||
{
|
||||
encodingLength += strlen(termEncodings[i]) + 1;
|
||||
expression = nsMsgSearchBoolExpression::AddSearchTermWithEncoding(expression, pTerm,termEncodings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(err))
|
||||
{
|
||||
// Catenate the intermediate encodings together into a big string
|
||||
char *totalEncoding = new char [encodingLength + (!reallyDredd ? strlen(m_kImapUnDeleted) : 0) + 1];
|
||||
nsCString encodingBuff;
|
||||
|
||||
if (totalEncoding)
|
||||
{
|
||||
totalEncoding[0] = '\0';
|
||||
|
||||
int offset = 0; // offset into starting place for the buffer
|
||||
if (!reallyDredd)
|
||||
PL_strcat(totalEncoding, m_kImapUnDeleted);
|
||||
|
||||
if (!reallyDredd)
|
||||
{
|
||||
encodingBuff.Append(m_kImapUnDeleted);
|
||||
offset = strlen(m_kImapUnDeleted);
|
||||
}
|
||||
|
||||
expression->GenerateEncodeStr(&encodingBuff);
|
||||
|
||||
for (i = 0; i < termCount; i++)
|
||||
{
|
||||
if (termEncodings[i])
|
||||
{
|
||||
PL_strcat (totalEncoding, termEncodings[i]);
|
||||
delete [] termEncodings[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
err = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
delete totalEncoding;
|
||||
delete expression;
|
||||
|
||||
// Set output parameter if we encoded the query successfully
|
||||
if (NS_SUCCEEDED(err))
|
||||
*ppOutEncoding = ToNewCString(encodingBuff);
|
||||
}
|
||||
|
||||
delete [] termEncodings;
|
||||
|
||||
return err;
|
||||
(void **)getter_AddRefs(pTerm));
|
||||
err = EncodeImapTerm (pTerm, reallyDredd, srcCharset, destCharset, &termEncodings[i]);
|
||||
if (NS_SUCCEEDED(err) && nsnull != termEncodings[i])
|
||||
{
|
||||
encodingLength += strlen(termEncodings[i]) + 1;
|
||||
expression = nsMsgSearchBoolExpression::AddSearchTermWithEncoding(expression, pTerm,termEncodings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(err))
|
||||
{
|
||||
// Catenate the intermediate encodings together into a big string
|
||||
char *totalEncoding = new char [encodingLength + (!reallyDredd ? strlen(m_kImapUnDeleted) : 0) + 1];
|
||||
nsCString encodingBuff;
|
||||
|
||||
if (totalEncoding)
|
||||
{
|
||||
totalEncoding[0] = '\0';
|
||||
|
||||
int offset = 0; // offset into starting place for the buffer
|
||||
if (!reallyDredd)
|
||||
PL_strcat(totalEncoding, m_kImapUnDeleted);
|
||||
|
||||
if (!reallyDredd)
|
||||
{
|
||||
encodingBuff.Append(m_kImapUnDeleted);
|
||||
offset = strlen(m_kImapUnDeleted);
|
||||
}
|
||||
|
||||
expression->GenerateEncodeStr(&encodingBuff);
|
||||
|
||||
for (i = 0; i < termCount; i++)
|
||||
{
|
||||
if (termEncodings[i])
|
||||
{
|
||||
PL_strcat (totalEncoding, termEncodings[i]);
|
||||
delete [] termEncodings[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
err = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
delete totalEncoding;
|
||||
delete expression;
|
||||
|
||||
// Set output parameter if we encoded the query successfully
|
||||
if (NS_SUCCEEDED(err))
|
||||
*ppOutEncoding = ToNewCString(encodingBuff);
|
||||
}
|
||||
|
||||
delete [] termEncodings;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -6811,9 +6811,24 @@ void nsImapProtocol::Search(const char * searchCriteria,
|
|||
protocolString.Append(" uid");
|
||||
protocolString.Append(" ");
|
||||
protocolString.Append(searchCriteria);
|
||||
// the search criteria can contain string literals, which means we
|
||||
// need to break up the protocol string by CRLF's, and after sending CRLF,
|
||||
// wait for the server to respond OK before sending more data
|
||||
nsresult rv;
|
||||
PRInt32 crlfIndex;
|
||||
while (crlfIndex = protocolString.Find(CRLF), crlfIndex != kNotFound && !DeathSignalReceived())
|
||||
{
|
||||
nsCAutoString tempProtocolString;
|
||||
protocolString.Left(tempProtocolString, crlfIndex + 2);
|
||||
rv = SendData(tempProtocolString.get());
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
ParseIMAPandCheckForNewMail();
|
||||
protocolString.Cut(0, crlfIndex + 2);
|
||||
}
|
||||
protocolString.Append(CRLF);
|
||||
|
||||
nsresult rv = SendData(protocolString.get());
|
||||
rv = SendData(protocolString.get());
|
||||
if (NS_SUCCEEDED(rv))
|
||||
ParseIMAPandCheckForNewMail();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче