From 11558b490b5229aa7c993e3e2a2bd5364c0acd17 Mon Sep 17 00:00:00 2001 From: "taka%netscape.com" Date: Fri, 26 Jan 2001 13:50:44 +0000 Subject: [PATCH] fix for #43221, #64781, and #53644. take folder charset and apply appropriate charset conversion before comparison. r=nhotta, a=bienvenu --- .../base/search/public/nsMsgSearchAdapter.h | 3 - mailnews/base/search/src/nsMsgFilter.cpp | 4 + mailnews/base/search/src/nsMsgLocalSearch.cpp | 24 ++++-- mailnews/base/search/src/nsMsgLocalSearch.h | 5 +- .../base/search/src/nsMsgSearchAdapter.cpp | 75 ++---------------- mailnews/base/search/src/nsMsgSearchTerm.cpp | 76 ++++++++----------- 6 files changed, 61 insertions(+), 126 deletions(-) diff --git a/mailnews/base/search/public/nsMsgSearchAdapter.h b/mailnews/base/search/public/nsMsgSearchAdapter.h index 711aa08f882d..3a0286f8f24b 100644 --- a/mailnews/base/search/public/nsMsgSearchAdapter.h +++ b/mailnews/base/search/public/nsMsgSearchAdapter.h @@ -72,9 +72,6 @@ public: static nsresult EncodeImapValue(char *encoding, const char *value, PRBool useQuotes, PRBool reallyDredd); - static char *TryToConvertCharset(const PRUnichar *sourceStr, - const PRUnichar *destCharset, - PRBool useMIME2Style); static char *GetImapCharsetParam(const PRUnichar *destCharset); void GetSearchCharsets(nsString &srcCharset, nsString &destCharset); static PRUnichar *EscapeSearchUrl (const PRUnichar *nntpCommand); diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index 00f705593fcd..3184ca1b6daf 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -330,7 +330,11 @@ NS_IMETHODIMP nsMsgFilter::MatchHdr(nsIMsgDBHdr *msgHdr, nsIMsgFolder *folder, n nsMsgSearchScopeTerm* scope = new nsMsgSearchScopeTerm(nsnull, nsMsgSearchScope::MailFolder, folder); nsCOMPtr scopeInterface = scope; + nsXPIDLString folderCharset; + folder->GetCharset(getter_Copies(folderCharset)); + const char *charset = NS_ConvertUCS2toUTF8(folderCharset); return nsMsgSearchOfflineMail::MatchTermsForFilter(msgHdr, m_termList, + charset, scope, db, headers, diff --git a/mailnews/base/search/src/nsMsgLocalSearch.cpp b/mailnews/base/search/src/nsMsgLocalSearch.cpp index edd2ae39dd09..f3c6ae5200a6 100644 --- a/mailnews/base/search/src/nsMsgLocalSearch.cpp +++ b/mailnews/base/search/src/nsMsgLocalSearch.cpp @@ -478,28 +478,31 @@ nsresult nsMsgSearchOfflineMail::SummaryFileError () nsresult nsMsgSearchOfflineMail::MatchTermsForFilter(nsIMsgDBHdr *msgToMatch, nsISupportsArray *termList, + const char *defaultCharset, nsIMsgSearchScopeTerm * scope, nsIMsgDatabase * db, const char * headers, PRUint32 headerSize, PRBool *pResult) { - return MatchTerms(msgToMatch, termList, scope, db, headers, headerSize, PR_TRUE, pResult); + return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, headers, headerSize, PR_TRUE, pResult); } // static method which matches a header against a list of search terms. nsresult nsMsgSearchOfflineMail::MatchTermsForSearch(nsIMsgDBHdr *msgToMatch, nsISupportsArray* termList, + const char *defaultCharset, nsIMsgSearchScopeTerm *scope, nsIMsgDatabase *db, PRBool *pResult) { - return MatchTerms(msgToMatch, termList, scope, db, nsnull, 0, PR_FALSE, pResult); + return MatchTerms(msgToMatch, termList, defaultCharset, scope, db, nsnull, 0, PR_FALSE, pResult); } nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch, nsISupportsArray * termList, + const char *defaultCharset, nsIMsgSearchScopeTerm * scope, nsIMsgDatabase * db, const char * headers, @@ -511,9 +514,10 @@ nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch, nsXPIDLCString recipients; nsXPIDLCString ccList; nsXPIDLCString matchString; - PRUint32 msgFlags; - - PRBool result; + nsXPIDLCString msgCharset; + const char *charset; + PRUint32 msgFlags; + PRBool result; if (!pResult) return NS_ERROR_NULL_POINTER; @@ -527,8 +531,6 @@ nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch, // Loop over all terms, and match them all to this message. - const char *charset = nsnull; // scope->m_folder->GetFolderCSID() & ~CS_AUTO; - nsMsgSearchBoolExpression * expression = new nsMsgSearchBoolExpression(); // create our expression if (!expression) return NS_ERROR_OUT_OF_MEMORY; @@ -544,6 +546,8 @@ nsresult nsMsgSearchOfflineMail::MatchTerms(nsIMsgDBHdr *msgToMatch, nsMsgSearchAttribValue attrib; pTerm->GetAttrib(&attrib); + msgToMatch->GetCharset(getter_Copies(msgCharset)); + charset = *(const char *)msgCharset ? msgCharset : defaultCharset; switch (attrib) { case nsMsgSearchAttrib::Sender: @@ -658,6 +662,7 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone) err = OpenSummaryFile (); if (!m_db) // must be reparsing. return err; + // Reparsing is unnecessary or completed if (NS_SUCCEEDED(err)) { @@ -678,8 +683,11 @@ nsresult nsMsgSearchOfflineMail::Search (PRBool *aDone) else { PRBool match = PR_FALSE; + nsAutoString nullCharset, folderCharset; + GetSearchCharsets(nullCharset, folderCharset); + const char *charset = NS_ConvertUCS2toUTF8(folderCharset); // Is this message a hit? - err = MatchTermsForSearch (msgDBHdr, m_searchTerms, m_scope, m_db, &match); + err = MatchTermsForSearch (msgDBHdr, m_searchTerms, charset, m_scope, m_db, &match); // Add search hits to the results list if (NS_SUCCEEDED(err) && match) diff --git a/mailnews/base/search/src/nsMsgLocalSearch.h b/mailnews/base/search/src/nsMsgLocalSearch.h index 89a16af7fc0c..29cbcef1ff4a 100644 --- a/mailnews/base/search/src/nsMsgLocalSearch.h +++ b/mailnews/base/search/src/nsMsgLocalSearch.h @@ -52,6 +52,7 @@ public: static nsresult MatchTermsForFilter(nsIMsgDBHdr * msgToMatch, nsISupportsArray *termList, + const char *defaultCharset, nsIMsgSearchScopeTerm *scope, nsIMsgDatabase * db, const char * headers, @@ -60,6 +61,7 @@ public: static nsresult MatchTermsForSearch(nsIMsgDBHdr * msgTomatch, nsISupportsArray * termList, + const char *defaultCharset, nsIMsgSearchScopeTerm *scope, nsIMsgDatabase *db, PRBool *pResult); @@ -67,11 +69,10 @@ public: virtual nsresult OpenSummaryFile (); nsresult SummaryFileError(); - - protected: static nsresult MatchTerms(nsIMsgDBHdr *msgToMatch, nsISupportsArray *termList, + const char *defaultCharset, nsIMsgSearchScopeTerm *scope, nsIMsgDatabase * db, const char * headers, diff --git a/mailnews/base/search/src/nsMsgSearchAdapter.cpp b/mailnews/base/search/src/nsMsgSearchAdapter.cpp index 7cbfc4ef4d36..55dc25a0ff34 100644 --- a/mailnews/base/search/src/nsMsgSearchAdapter.cpp +++ b/mailnews/base/search/src/nsMsgSearchAdapter.cpp @@ -136,73 +136,6 @@ NS_IMETHODIMP nsMsgSearchAdapter::AddHit(nsMsgKey key) } -char * -nsMsgSearchAdapter::TryToConvertCharset(const PRUnichar *sourceStr, - const PRUnichar * destCharset, - PRBool useMime2) -{ - char *result = nsnull; - - if (sourceStr == nsnull) - return nsnull; - - // Convert from unicode to a destination charset. - if (NS_FAILED(ConvertFromUnicode(nsAutoString(destCharset), nsAutoString(sourceStr), &result))) { - PR_FREEIF(result); - result = nsnull; - } - -#ifdef DO_I18N // I have no idea what we should do here. - if ((src_csid != dest_csid) || (useMime2)) - { - // Need to convert. See if we can. - - // ### mwelch Much of this code is lifted from - // lib/libi18n/mime2fun.c (in particular, - // intl_EncodeMimePartIIStr). - CCCDataObject obj = nsnull; - CCCFunc cvtfunc = nsnull; - int srcLen = XP_STRLEN(sourceStr); - - obj = INTL_CreateCharCodeConverter(); - if (obj == nsnull) - return 0; - - /* setup converter from src_csid --> dest_csid */ - INTL_GetCharCodeConverter(src_csid, dest_csid, obj) ; - cvtfunc = INTL_GetCCCCvtfunc(obj); - - if (cvtfunc) - { - // We can convert, so do it. - if (useMime2) - // Force MIME-2 encoding so that the charset (if necessary) gets - // passed to the Dredd server inline - result = INTL_EncodeMimePartIIStr(sourceStr, src_csid, TRUE); - else - { - // Copy the source string before using it for conversion. - // You just don't know where those bits have been. - char *temp = XP_STRDUP(sourceStr); - if (temp) - { - // (result) will differ from (temp) iff a larger string - // were needed to contain the converted chars. - // (or so I understand) - result = (char *) cvtfunc(obj, - (unsigned char*)temp, - srcLen); - if (result != temp) - XP_FREE(temp); - } - } - } - XP_FREEIF(obj); - } -#endif - return result; -} - char * nsMsgSearchAdapter::GetImapCharsetParam(const PRUnichar *destCharset) { @@ -370,8 +303,10 @@ void nsMsgSearchAdapter::GetSearchCharsets(nsString &srcCharset, nsString& dstCharset) { nsresult rv; -// char *defaultCharset = nsMsgI18NGetDefaultMailCharset(); - nsAutoString defaultCharset; defaultCharset.AssignWithConversion(nsMsgI18NGetDefaultMailCharset()); + nsAutoString defaultCharset; + char *search_charset = nsMsgI18NGetDefaultMailCharset(); + defaultCharset.AssignWithConversion(search_charset); + PR_Free((void *)search_charset); srcCharset = defaultCharset; dstCharset = defaultCharset; @@ -646,7 +581,7 @@ nsresult nsMsgSearchAdapter::EncodeImapTerm (nsIMsgSearchTerm *term, PRBool real useQuotes = !reallyDredd || (nsAutoString(convertedValue).FindChar((PRUnichar)' ') != -1); // now convert to char* and escape quoted_specials - value = TryToConvertCharset(convertedValue, destCharset, reallyDredd); + ConvertFromUnicode(nsAutoString(convertedValue), nsAutoString(destCharset), &value); if (value) { char *oldValue = value; diff --git a/mailnews/base/search/src/nsMsgSearchTerm.cpp b/mailnews/base/search/src/nsMsgSearchTerm.cpp index 583d7e484d9e..77ad9c23d9cf 100644 --- a/mailnews/base/search/src/nsMsgSearchTerm.cpp +++ b/mailnews/base/search/src/nsMsgSearchTerm.cpp @@ -701,14 +701,6 @@ nsresult nsMsgSearchTerm::MatchBody (nsIMsgSearchScopeTerm *scope, PRUint32 offs PRBool endOfFile = PR_FALSE; // if retValue == 0, we've hit the end of the file uint32 lines = 0; - PRBool getConverter = PR_FALSE; -#ifdef DO_I18N - CCCDataObject conv = INTL_CreateCharCodeConverter(); - PRInt16 win_csid = INTL_DocToWinCharSetID(foldcsid); - PRInt16 mail_csid = INTL_DefaultMailCharSetID(win_csid); // to default mail_csid (e.g. JIS for Japanese) - if ((nsnull != conv) && INTL_GetCharCodeConverter(mail_csid, win_csid, conv)) - getConverter = PR_TRUE; -#endif // DO_I18N // Change the sense of the loop so we don't bail out prematurely // on negative terms. i.e. opDoesntContain must look at all lines PRBool boolContinueLoop; @@ -733,27 +725,13 @@ nsresult nsMsgSearchTerm::MatchBody (nsIMsgSearchScopeTerm *scope, PRUint32 offs // Do in-place decoding of quoted printable if (isQuotedPrintable) StripQuotedPrintable ((unsigned char*)buf); - - nsCString compare(buf); - if (getConverter) - { -#ifdef DO_I18N - // In here we do I18N conversion if we get the converter - char *newBody = nsnull; - newBody = (char *)INTL_CallCharCodeConverter(conv, (unsigned char *) buf, (int32) PL_strlen(buf)); - if (newBody && (newBody != buf)) - { - // CharCodeConverter return the char* to the orginal string - // we don't want to free body in that case - compare = newBody; - } -#endif - } + nsCString compare(buf); +// ConvertToUnicode(charset, buf, compare); if (compare.Length() > 0) { char startChar = (char) compare.CharAt(0); if (startChar != CR && startChar != LF) { - err = MatchString (compare, nsnull, &result); + err = MatchString (compare, folderCharset, &result); lines++; } } @@ -793,6 +771,7 @@ nsresult nsMsgSearchTerm::MatchRfc2047String (const char *rfc2047string, if (NS_SUCCEEDED(res)) { stringToMatch = decodedString.ToNewUTF8String(); mimedecode = PR_TRUE; + charset = nsnull; } else stringToMatch = rfc2047string; // Try to match anyway @@ -816,75 +795,83 @@ nsresult nsMsgSearchTerm::MatchString (const char *stringToMatch, nsresult err = NS_OK; nsCAutoString n_str; - const char* n_header = nsnull; + const char *utf8 = stringToMatch; if(nsMsgSearchOp::IsEmpty != m_operator) // Save some performance for opIsEmpty { - n_header = stringToMatch; n_str = m_value.string; + if (charset != nsnull) + { + nsAutoString srcCharset; + srcCharset.AssignWithConversion(charset); + nsString out; + ConvertToUnicode(srcCharset, stringToMatch ? stringToMatch : "", out); + utf8 = out.ToNewUTF8String(); + } } + switch (m_operator) { case nsMsgSearchOp::Contains: - if ((nsnull != n_header) && ((n_str.GetBuffer())[0]) && /* INTL_StrContains(csid, n_header, n_str) */ - PL_strcasestr(stringToMatch, n_str)) + if ((nsnull != utf8) && ((n_str.GetBuffer())[0]) && /* INTL_StrContains(csid, n_header, n_str) */ + PL_strcasestr(utf8, n_str)) result = PR_TRUE; break; case nsMsgSearchOp::DoesntContain: - if ((nsnull != n_header) && ((n_str.GetBuffer())[0]) && /* !INTL_StrContains(csid, n_header, n_str) */ - !PL_strcasestr(stringToMatch, n_str)) + if ((nsnull != utf8) && ((n_str.GetBuffer())[0]) && /* !INTL_StrContains(csid, n_header, n_str) */ + !PL_strcasestr(utf8, n_str)) result = PR_TRUE; break; case nsMsgSearchOp::Is: - if(n_header) + if(utf8) { if ((n_str.GetBuffer())[0]) { - if (n_str.EqualsWithConversion(stringToMatch, PR_TRUE /*ignore case*/) /* INTL_StrIs(csid, n_header, n_str)*/ ) + if (n_str.EqualsWithConversion(utf8, PR_TRUE /*ignore case*/) /* INTL_StrIs(csid, n_header, n_str)*/ ) result = PR_TRUE; } - else if (n_header[0] == '\0') // Special case for "is " + else if (utf8[0] == '\0') // Special case for "is " result = PR_TRUE; } break; case nsMsgSearchOp::Isnt: - if(n_header) + if(utf8) { if ((n_str.GetBuffer())[0]) { - if (!n_str.EqualsWithConversion(stringToMatch, PR_TRUE)/* INTL_StrIs(csid, n_header, n_str)*/ ) + if (!n_str.EqualsWithConversion(utf8, PR_TRUE)/* INTL_StrIs(csid, n_header, n_str)*/ ) result = PR_TRUE; } - else if (n_header[0] != '\0') // Special case for "isn't " + else if (utf8[0] != '\0') // Special case for "isn't " result = PR_TRUE; } break; case nsMsgSearchOp::IsEmpty: - if (!PL_strlen(stringToMatch)) + if (!PL_strlen(utf8)) result = PR_TRUE; break; case nsMsgSearchOp::BeginsWith: #ifdef DO_I18N_YET - if((nsnull != n_str) && (nsnull != n_header) && INTL_StrBeginWith(csid, n_header, n_str)) + if((nsnull != n_str) && (nsnull != utf8) && INTL_StrBeginWith(csid, utf8, n_str)) result = PR_TRUE; #else // ### DMB - not the most efficient way to do this. - if (PL_strncmp(stringToMatch, n_str, PL_strlen(n_str)) == 0) + if (PL_strncmp(utf8, n_str, PL_strlen(n_str)) == 0) result = PR_TRUE; #endif break; case nsMsgSearchOp::EndsWith: { - PRUint32 searchStrLen = (PRUint32) PL_strlen(stringToMatch); + PRUint32 searchStrLen = (PRUint32) PL_strlen(utf8); if (n_str.Length() <= searchStrLen) { PRInt32 sourceStrOffset = searchStrLen - n_str.Length(); - if (PL_strcmp(stringToMatch + sourceStrOffset, n_str) == 0) + if (PL_strcmp(utf8 + sourceStrOffset, n_str) == 0) result = PR_TRUE; } } #ifdef DO_I18N_YET { - if((nsnull != n_str) && (nsnull != n_header) && INTL_StrEndWith(csid, n_header, n_str)) + if((nsnull != n_str) && (nsnull != utf8) && INTL_StrEndWith(csid, utf8, n_str)) result = PR_TRUE; } #else @@ -895,6 +882,9 @@ nsresult nsMsgSearchTerm::MatchString (const char *stringToMatch, NS_ASSERTION(PR_FALSE, "invalid operator matching search results"); } + if (utf8 != nsnull && utf8 != stringToMatch) + free((void *)utf8); + *pResult = result; return err; }