bool nsMsgI18Ncheck_data_in_charset_range(const char *charset, const char16_t* inString, char **fallbackCharset) { if (!charset || !*charset || !inString || !*inString) return true; nsresult res; bool result = true; nsCOMPtr <nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res); if (NS_SUCCEEDED(res)) { nsCOMPtr <nsIUnicodeEncoder> encoder; // get an unicode converter res = ccm->GetUnicodeEncoderRaw(charset, getter_AddRefs(encoder)); if(NS_SUCCEEDED(res)) { const char16_t *originalPtr = inString; int32_t originalLen = NS_strlen(inString); const char16_t *currentSrcPtr = originalPtr; char localBuff[512]; int32_t consumedLen = 0; int32_t srcLen; int32_t dstLength; // convert from unicode while (consumedLen < originalLen) { srcLen = originalLen - consumedLen; dstLength = 512; res = encoder->Convert(currentSrcPtr, &srcLen, localBuff, &dstLength); if (NS_ERROR_UENC_NOMAPPING == res) { result = false; break; } else if (NS_FAILED(res) || (0 == dstLength)) break; currentSrcPtr += srcLen; consumedLen = currentSrcPtr - originalPtr; // src length used so far } } } // if the conversion was not successful then try fallback to other charsets if (!result && fallbackCharset) { nsCString convertedString; res = nsMsgI18NConvertFromUnicode(*fallbackCharset, nsDependentString(inString), convertedString, false, true); result = (NS_SUCCEEDED(res) && NS_ERROR_UENC_NOMAPPING != res); } return result; }
static int MimeInlineTextPlainFlowed_parse_line (const char *aLine, PRInt32 length, MimeObject *obj) { int status; PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above PRBool plainHTML = quoting || (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs); // see above struct MimeInlineTextPlainFlowedExData *exdata; exdata = MimeInlineTextPlainFlowedExDataList; while(exdata && (exdata->ownerobj != obj)) { exdata = exdata->next; } NS_ASSERTION(exdata, "The extra data has disappeared!"); NS_ASSERTION(length > 0, "zero length"); if (length <= 0) return 0; uint32 linequotelevel = 0; nsCAutoString real_line(aLine, length); char *line = real_line.BeginWriting(); const char *linep = real_line.BeginReading(); // Space stuffed? if(' ' == *linep) { linep++; } else { // count '>':s before the first non-'>' while('>' == *linep) { linep++; linequotelevel++; } // Space stuffed? if(' ' == *linep) { linep++; } } // Look if the last character (after stripping ending end // of lines and quoting stuff) is a SPACE. If it is, we are looking at a // flowed line. Normally we assume that the last two chars // are CR and LF as said in RFC822, but that doesn't seem to // be the case always. PRBool flowed = PR_FALSE; PRBool sigSeparator = PR_FALSE; PRInt32 index = length-1; while(index >= 0 && ('\r' == line[index] || '\n' == line[index])) { index--; } if (index > linep - line && ' ' == line[index]) /* Ignore space stuffing, i.e. lines with just (quote marks and) a space count as empty */ { flowed = PR_TRUE; sigSeparator = (index - (linep - line) + 1 == 3) && !strncmp(linep, "-- ", 3); if (((MimeInlineTextPlainFlowed *) obj)->delSp && ! sigSeparator) /* If line is flowed and DelSp=yes, logically delete trailing space. Line consisting of dash dash space ("-- "), commonly used as signature separator, gets special handling (RFC 3676) */ { length--; line[index] = '\0'; } } mozITXTToHTMLConv *conv = GetTextConverter(obj->options); PRBool skipConversion = !conv || (obj->options && obj->options->force_user_charset); nsAutoString lineSource; nsString lineResult; char *mailCharset = NULL; nsresult rv; if (!skipConversion) { // Convert only if the source string is not empty if (length - (linep - line) > 0) { PRBool whattodo = obj->options->whattodo; if (plainHTML) { if (quoting) whattodo = 0; else whattodo = whattodo & ~mozITXTToHTMLConv::kGlyphSubstitution; /* Do recognition for the case, the result is viewed in Mozilla, but not GlyphSubstitution, because other UAs might not be able to display the glyphs. */ } const nsDependentCSubstring& inputStr = Substring(linep, linep + (length - (linep - line))); // For 'SaveAs', |line| is in |mailCharset|. // convert |line| to UTF-16 before 'html'izing (calling ScanTXT()) if (obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs) { // Get the mail charset of this message. MimeInlineText *inlinetext = (MimeInlineText *) obj; if (!inlinetext->initializeCharset) ((MimeInlineTextClass*)&mimeInlineTextClass)->initialize_charset(obj); mailCharset = inlinetext->charset; if (mailCharset && *mailCharset) { rv = nsMsgI18NConvertToUnicode(mailCharset, PromiseFlatCString(inputStr), lineSource); NS_ENSURE_SUCCESS(rv, -1); } else // this probably never happens... CopyUTF8toUTF16(inputStr, lineSource); } else // line is in UTF-8 CopyUTF8toUTF16(inputStr, lineSource); // This is the main TXT to HTML conversion: // escaping (very important), eventually recognizing etc. rv = conv->ScanTXT(lineSource.get(), whattodo, getter_Copies(lineResult)); NS_ENSURE_SUCCESS(rv, -1); } } else { CopyUTF8toUTF16(nsDependentCString(line, length), lineResult); status = NS_OK; } nsCAutoString preface; /* Correct number of blockquotes */ int32 quoteleveldiff=linequotelevel - exdata->quotelevel; if((quoteleveldiff != 0) && flowed && exdata->inflow) { // From RFC 2646 4.5 // The receiver SHOULD handle this error by using the 'quote-depth-wins' rule, // which is to ignore the flowed indicator and treat the line as fixed. That // is, the change in quote depth ends the paragraph. // We get that behaviour by just going on. } while(quoteleveldiff>0) { quoteleveldiff--; preface += "<blockquote type=cite"; // This is to have us observe the user pref settings for citations MimeInlineTextPlainFlowed *tObj = (MimeInlineTextPlainFlowed *) obj; nsCAutoString style; MimeTextBuildPrefixCSS(tObj->mQuotedSizeSetting, tObj->mQuotedStyleSetting, tObj->mCitationColor, style); if (!plainHTML && !style.IsEmpty()) { preface += " style=\""; preface += style; preface += '"'; } preface += '>'; } while(quoteleveldiff<0) { quoteleveldiff++; preface += "</blockquote>"; } exdata->quotelevel = linequotelevel; nsAutoString lineResult2; if(flowed) { // Check RFC 2646 "4.3. Usenet Signature Convention": "-- "+CRLF is // not a flowed line if (sigSeparator) { if (linequotelevel > 0 || exdata->isSig) { preface += "-- <br>"; } else { exdata->isSig = PR_TRUE; preface += "<div class=\"moz-txt-sig\"><span class=\"moz-txt-tag\">" "-- <br></span>"; } } else { Line_convert_whitespace(lineResult, PR_FALSE /* Allow wraps */, lineResult2); } exdata->inflow=PR_TRUE; } else { // Fixed paragraph. Line_convert_whitespace(lineResult, !plainHTML && !obj->options->wrap_long_lines_p /* If wrap, convert all spaces but the last in a row into nbsp, otherwise all. */, lineResult2); lineResult2.AppendLiteral("<br>"); exdata->inflow = PR_FALSE; } // End Fixed line if (!(exdata->isSig && quoting)) { status = MimeObject_write(obj, preface.get(), preface.Length(), PR_TRUE); if (status < 0) return status; nsCAutoString outString; if (obj->options->format_out != nsMimeOutput::nsMimeMessageSaveAs || !mailCharset || !*mailCharset) CopyUTF16toUTF8(lineResult2, outString); else { // convert back to mailCharset before writing. rv = nsMsgI18NConvertFromUnicode(mailCharset, lineResult2, outString); NS_ENSURE_SUCCESS(rv, -1); } status = MimeObject_write(obj, outString.get(), outString.Length(), PR_TRUE); return status; } else return NS_OK; }
static int MimeInlineTextPlain_parse_line (char *line, PRInt32 length, MimeObject *obj) { int status; PRBool quoting = ( obj->options && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting || obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting ) ); // see above PRBool plainHTML = quoting || (obj->options && obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs); // see above PRBool rawPlainText = obj->options && (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach); // this routine gets called for every line of data that comes through the // mime converter. It's important to make sure we are efficient with // how we allocate memory in this routine. be careful if you go to add // more to this routine. NS_ASSERTION(length > 0, "zero length"); if (length <= 0) return 0; mozITXTToHTMLConv *conv = GetTextConverter(obj->options); MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj; PRBool skipConversion = !conv || rawPlainText || (obj->options && obj->options->force_user_charset); char *mailCharset = NULL; nsresult rv; // if this part has a name and it's not a message/rfc822, don't quote if (quoting && obj->headers && MimeHeaders_get_name(obj->headers, obj->options) && PL_strcasecmp(obj->content_type, MESSAGE_RFC822)) return 0; if (!skipConversion) { nsDependentCString inputStr(line, length); nsAutoString lineSourceStr; // For 'SaveAs', |line| is in |mailCharset|. // convert |line| to UTF-16 before 'html'izing (calling ScanTXT()) if (obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs) { // Get the mail charset of this message. MimeInlineText *inlinetext = (MimeInlineText *) obj; if (!inlinetext->initializeCharset) ((MimeInlineTextClass*)&mimeInlineTextClass)->initialize_charset(obj); mailCharset = inlinetext->charset; if (mailCharset && *mailCharset) { rv = nsMsgI18NConvertToUnicode(mailCharset, inputStr, lineSourceStr); NS_ENSURE_SUCCESS(rv, -1); } else // this probably never happens ... CopyUTF8toUTF16(inputStr, lineSourceStr); } else // line is in UTF-8 CopyUTF8toUTF16(inputStr, lineSourceStr); nsCAutoString prefaceResultStr; // Quoting stuff before the real text // Recognize quotes PRUint32 oldCiteLevel = text->mCiteLevel; PRUint32 logicalLineStart = 0; rv = conv->CiteLevelTXT(lineSourceStr.get(), &logicalLineStart, &(text->mCiteLevel)); NS_ENSURE_SUCCESS(rv, -1); // Find out, which recognitions to do PRBool whattodo = obj->options->whattodo; if (plainHTML) { if (quoting) whattodo = 0; // This is done on Send. Don't do it twice. else whattodo = whattodo & ~mozITXTToHTMLConv::kGlyphSubstitution; /* Do recognition for the case, the result is viewed in Mozilla, but not GlyphSubstitution, because other UAs might not be able to display the glyphs. */ if (!text->mBlockquoting) text->mCiteLevel = 0; } // Write blockquote if (text->mCiteLevel > oldCiteLevel) { prefaceResultStr += "</pre>"; for (PRUint32 i = 0; i < text->mCiteLevel - oldCiteLevel; i++) { nsCAutoString style; MimeTextBuildPrefixCSS(text->mQuotedSizeSetting, text->mQuotedStyleSetting, text->mCitationColor, style); if (!plainHTML && !style.IsEmpty()) { prefaceResultStr += "<blockquote type=cite style=\""; prefaceResultStr += style; prefaceResultStr += "\">"; } else prefaceResultStr += "<blockquote type=cite>"; } prefaceResultStr += "<pre wrap>"; } else if (text->mCiteLevel < oldCiteLevel) { prefaceResultStr += "</pre>"; for (PRUint32 i = 0; i < oldCiteLevel - text->mCiteLevel; i++) prefaceResultStr += "</blockquote>"; prefaceResultStr += "<pre wrap>"; if (text->mCiteLevel == 0) prefaceResultStr += "<!---->"; /* Make sure, NGLayout puts out a linebreak */ } // Write plain text quoting tags if (logicalLineStart != 0 && !(plainHTML && text->mBlockquoting)) { if (!plainHTML) prefaceResultStr += "<span class=\"moz-txt-citetags\">"; nsAutoString citeTagsSource; lineSourceStr.Mid(citeTagsSource, 0, logicalLineStart); // Convert to HTML nsXPIDLString citeTagsResultUnichar; rv = conv->ScanTXT(citeTagsSource.get(), 0 /* no recognition */, getter_Copies(citeTagsResultUnichar)); if (NS_FAILED(rv)) return -1; AppendUTF16toUTF8(citeTagsResultUnichar, prefaceResultStr); if (!plainHTML) prefaceResultStr += "</span>"; } // recognize signature if ((lineSourceStr.Length() >= 4) && lineSourceStr.First() == '-' && Substring(lineSourceStr, 0, 3).EqualsLiteral("-- ") && (lineSourceStr[3] == '\r' || lineSourceStr[3] == '\n') ) { text->mIsSig = PR_TRUE; if (!quoting) prefaceResultStr += "<div class=\"moz-txt-sig\">"; } /* This is the main TXT to HTML conversion: escaping (very important), eventually recognizing etc. */ nsXPIDLString lineResultUnichar; rv = conv->ScanTXT(lineSourceStr.get() + logicalLineStart, whattodo, getter_Copies(lineResultUnichar)); NS_ENSURE_SUCCESS(rv, -1); if (!(text->mIsSig && quoting)) { status = MimeObject_write(obj, prefaceResultStr.get(), prefaceResultStr.Length(), PR_TRUE); if (status < 0) return status; nsCAutoString outString; if (obj->options->format_out != nsMimeOutput::nsMimeMessageSaveAs || !mailCharset || !*mailCharset) CopyUTF16toUTF8(lineResultUnichar, outString); else { // convert back to mailCharset before writing. rv = nsMsgI18NConvertFromUnicode(mailCharset, lineResultUnichar, outString); NS_ENSURE_SUCCESS(rv, -1); } status = MimeObject_write(obj, outString.get(), outString.Length(), PR_TRUE); } else { status = NS_OK; } } else { status = MimeObject_write(obj, line, length, PR_TRUE); } return status; }
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 = nsMsgI18NConvertFromUnicode( NS_LossyConvertUTF16toASCII(destCharset), 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(""); 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) free(value); *ppOutTerm = encoding; return err; }
nsresult nsAbManager::ExportDirectoryToDelimitedText(nsIAbDirectory *aDirectory, const char *aDelim, PRUint32 aDelimLen, nsILocalFile *aLocalFile) { nsCOMPtr <nsISimpleEnumerator> cardsEnumerator; nsCOMPtr <nsIAbCard> card; nsresult rv; nsCOMPtr <nsIOutputStream> outputStream; rv = MsgNewBufferedFileOutputStream(getter_AddRefs(outputStream), aLocalFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, 0664); // the desired file may be read only if (NS_FAILED(rv)) return rv; PRUint32 i; PRUint32 writeCount; PRUint32 length; nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIStringBundle> bundle; rv = bundleService->CreateBundle("chrome://messenger/locale/importMsgs.properties", getter_AddRefs(bundle)); NS_ENSURE_SUCCESS(rv, rv); nsCString revisedName; nsString columnName; for (i = 0; i < NS_ARRAY_LENGTH(EXPORT_ATTRIBUTES_TABLE); i++) { if (EXPORT_ATTRIBUTES_TABLE[i].plainTextStringID != 0) { // We don't need to truncate the string here as getter_Copies will // do that for us. if (NS_FAILED(bundle->GetStringFromID(EXPORT_ATTRIBUTES_TABLE[i].plainTextStringID, getter_Copies(columnName)))) columnName.AppendInt(EXPORT_ATTRIBUTES_TABLE[i].plainTextStringID); rv = nsMsgI18NConvertFromUnicode(nsMsgI18NFileSystemCharset(), columnName, revisedName); NS_ENSURE_SUCCESS(rv,rv); rv = outputStream->Write(revisedName.get(), revisedName.Length(), &writeCount); NS_ENSURE_SUCCESS(rv,rv); if (revisedName.Length() != writeCount) return NS_ERROR_FAILURE; if (i < NS_ARRAY_LENGTH(EXPORT_ATTRIBUTES_TABLE) - 1) { rv = outputStream->Write(aDelim, aDelimLen, &writeCount); NS_ENSURE_SUCCESS(rv,rv); if (aDelimLen != writeCount) return NS_ERROR_FAILURE; } } } rv = outputStream->Write(MSG_LINEBREAK, MSG_LINEBREAK_LEN, &writeCount); NS_ENSURE_SUCCESS(rv,rv); if (MSG_LINEBREAK_LEN != writeCount) return NS_ERROR_FAILURE; rv = aDirectory->GetChildCards(getter_AddRefs(cardsEnumerator)); if (NS_SUCCEEDED(rv) && cardsEnumerator) { nsCOMPtr<nsISupports> item; bool more; while (NS_SUCCEEDED(cardsEnumerator->HasMoreElements(&more)) && more) { rv = cardsEnumerator->GetNext(getter_AddRefs(item)); if (NS_SUCCEEDED(rv)) { nsCOMPtr <nsIAbCard> card = do_QueryInterface(item, &rv); NS_ENSURE_SUCCESS(rv,rv); bool isMailList; rv = card->GetIsMailList(&isMailList); NS_ENSURE_SUCCESS(rv,rv); if (isMailList) { // .tab, .txt and .csv aren't able to export mailing lists // use LDIF for that. } else { nsString value; nsCString valueCStr; for (i = 0; i < NS_ARRAY_LENGTH(EXPORT_ATTRIBUTES_TABLE); i++) { if (EXPORT_ATTRIBUTES_TABLE[i].plainTextStringID != 0) { rv = card->GetPropertyAsAString(EXPORT_ATTRIBUTES_TABLE[i].abPropertyName, value); if (NS_FAILED(rv)) value.Truncate(); // If a string contains at least one comma, tab or double quote then // we need to quote the entire string. Also if double quote is part // of the string we need to quote the double quote(s) as well. nsAutoString newValue(value); bool needsQuotes = false; if(newValue.FindChar('"') != -1) { needsQuotes = PR_TRUE; PRInt32 match = 0; PRUint32 offset = 0; nsString oldSubstr = NS_LITERAL_STRING("\""); nsString newSubstr = NS_LITERAL_STRING("\"\""); while (offset < newValue.Length()) { match = newValue.Find(oldSubstr, offset); if (match == -1) break; newValue.Replace(offset + match, oldSubstr.Length(), newSubstr); offset += (match + newSubstr.Length()); } } if (!needsQuotes && (newValue.FindChar(',') != -1 || newValue.FindChar('\x09') != -1)) needsQuotes = PR_TRUE; // Make sure we quote if containing CR/LF. if (newValue.FindChar('\r') != -1 || newValue.FindChar('\n') != -1) needsQuotes = PR_TRUE; if (needsQuotes) { newValue.Insert(NS_LITERAL_STRING("\""), 0); newValue.AppendLiteral("\""); } rv = nsMsgI18NConvertFromUnicode(nsMsgI18NFileSystemCharset(), newValue, valueCStr); NS_ENSURE_SUCCESS(rv,rv); if (NS_FAILED(rv)) { NS_ERROR("failed to convert string to system charset. use LDIF"); valueCStr = "?"; } length = valueCStr.Length(); if (length) { rv = outputStream->Write(valueCStr.get(), length, &writeCount); NS_ENSURE_SUCCESS(rv,rv); if (length != writeCount) return NS_ERROR_FAILURE; } valueCStr = ""; } else { // something we don't support for the current export // for example, .tab doesn't export preferred html format continue; // go to next field } if (i < NS_ARRAY_LENGTH(EXPORT_ATTRIBUTES_TABLE) - 1) { rv = outputStream->Write(aDelim, aDelimLen, &writeCount); NS_ENSURE_SUCCESS(rv,rv); if (aDelimLen != writeCount) return NS_ERROR_FAILURE; } } // write out the linebreak that separates the cards rv = outputStream->Write(MSG_LINEBREAK, MSG_LINEBREAK_LEN, &writeCount); NS_ENSURE_SUCCESS(rv,rv); if (MSG_LINEBREAK_LEN != writeCount) return NS_ERROR_FAILURE; } } } } rv = outputStream->Flush(); NS_ENSURE_SUCCESS(rv,rv); rv = outputStream->Close(); NS_ENSURE_SUCCESS(rv,rv); return NS_OK; }
// Test a message send???? nsresult nsEudoraCompose::SendTheMessage(nsIFile *pMailImportLocation, nsIFile **pMsg) { nsresult rv = CreateComponents(); if (NS_SUCCEEDED( rv)) rv = CreateIdentity(); if (NS_FAILED( rv)) return( rv); // IMPORT_LOG0( "Outlook Compose created necessary components\n"); nsString bodyType; nsString charSet; nsString headerVal; GetHeaderValue( m_pHeaders, m_headerLen, "From:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetFrom( headerVal); GetHeaderValue( m_pHeaders, m_headerLen, "To:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetTo( headerVal); GetHeaderValue( m_pHeaders, m_headerLen, "Subject:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetSubject( headerVal); GetHeaderValue( m_pHeaders, m_headerLen, "Content-type:", headerVal); bodyType = headerVal; ExtractType( bodyType); ExtractCharset( headerVal); // Use platform charset as default if the msg doesn't specify one // (ie, no 'charset' param in the Content-Type: header). As the last // resort we'll use the mail default charset. // (ie, no 'charset' param in the Content-Type: header) or if the // charset parameter fails a length sanity check. // As the last resort we'll use the mail default charset. if ( headerVal.IsEmpty() || (headerVal.Length() > kContentTypeLengthSanityCheck) ) { CopyASCIItoUTF16(nsMsgI18NFileSystemCharset(), headerVal); if (headerVal.IsEmpty()) { // last resort if (m_defCharset.IsEmpty()) { nsString defaultCharset; NS_GetLocalizedUnicharPreferenceWithDefault(nsnull, "mailnews.view_default_charset", NS_LITERAL_STRING("ISO-8859-1"), defaultCharset); m_defCharset = defaultCharset; } headerVal = m_defCharset; } } m_pMsgFields->SetCharacterSet( NS_LossyConvertUTF16toASCII(headerVal).get() ); charSet = headerVal; GetHeaderValue( m_pHeaders, m_headerLen, "CC:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetCc( headerVal); GetHeaderValue( m_pHeaders, m_headerLen, "Message-ID:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetMessageId( NS_LossyConvertUTF16toASCII(headerVal).get() ); GetHeaderValue( m_pHeaders, m_headerLen, "Reply-To:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetReplyTo( headerVal); // what about all of the other headers?!?!?!?!?!?! char *pMimeType; if (!bodyType.IsEmpty()) pMimeType = ToNewCString(bodyType); else pMimeType = ToNewCString(m_bodyType); // IMPORT_LOG0( "Outlook compose calling CreateAndSendMessage\n"); nsMsgAttachedFile *pAttach = GetLocalAttachments(); /* l10n - I have the body of the message in the system charset, I need to "encode" it to be the charset for the message *UNLESS* of course, I don't know what the charset of the message should be? How do I determine what the charset should be if it doesn't exist? */ nsString uniBody; NS_CopyNativeToUnicode( nsDependentCString(m_pBody), uniBody); nsCString body; rv = nsMsgI18NConvertFromUnicode( NS_LossyConvertUTF16toASCII(charSet).get(), uniBody, body); if (NS_FAILED( rv)) { // in this case, if we did not use the default compose // charset, then try that. if (!charSet.Equals( m_defCharset)) { body.Truncate(); rv = nsMsgI18NConvertFromUnicode( NS_LossyConvertUTF16toASCII(charSet).get(), uniBody, body); } } uniBody.Truncate(); // See if it's a draft msg (ie, no From: or no To: AND no Cc: AND no Bcc:). // Eudora saves sent and draft msgs in Out folder (ie, mixed) and it does // store Bcc: header in the msg itself. nsMsgDeliverMode mode = nsIMsgSend::nsMsgDeliverNow; nsAutoString from, to, cc, bcc; rv = m_pMsgFields->GetFrom(from); rv = m_pMsgFields->GetTo(to); rv = m_pMsgFields->GetCc(cc); rv = m_pMsgFields->GetBcc(bcc); if ( from.IsEmpty() || to.IsEmpty() && cc.IsEmpty() && bcc.IsEmpty() ) mode = nsIMsgSend::nsMsgSaveAsDraft; // We only get the editor interface when there's embedded content. // Otherwise pEditor remains NULL. That way we only import with the pseudo // editor when it helps. nsRefPtr<nsEudoraEditor> pEudoraEditor = new nsEudoraEditor(m_pBody, pMailImportLocation); nsCOMPtr<nsIEditor> pEditor; if (pEudoraEditor->HasEmbeddedContent()) // There's embedded content that we need to import, so query for the editor interface pEudoraEditor->QueryInterface( NS_GET_IID(nsIEditor), getter_AddRefs(pEditor) ); if (NS_FAILED( rv)) { rv = m_pSendProxy->CreateAndSendMessage( pEditor.get(), // pseudo editor shell when there's embedded content s_pIdentity, // dummy identity nsnull, // account key m_pMsgFields, // message fields PR_FALSE, // digest = NO PR_TRUE, // dont_deliver = YES, make a file mode, // mode nsnull, // no message to replace pMimeType, // body type m_pBody, // body pointer m_bodyLen, // body length nsnull, // remote attachment data pAttach, // local attachments nsnull, // related part nsnull, // parent window nsnull, // progress listener m_pListener, // listener nsnull, // password EmptyCString(), // originalMsgURI nsnull); // message compose type } else { rv = m_pSendProxy->CreateAndSendMessage( pEditor.get(), // pseudo editor shell when there's embedded content s_pIdentity, // dummy identity nsnull, // account key m_pMsgFields, // message fields PR_FALSE, // digest = NO PR_TRUE, // dont_deliver = YES, make a file mode, // mode nsnull, // no message to replace pMimeType, // body type body.get(), // body pointer body.Length(), // body length nsnull, // remote attachment data pAttach, // local attachments nsnull, // related part nsnull, // parent window nsnull, // progress listener m_pListener, // listener nsnull, // password EmptyCString(), // originalMsgURI nsnull); // message compose type } // IMPORT_LOG0( "Returned from CreateAndSendMessage\n"); if (pAttach) delete [] pAttach; EudoraSendListener *pListen = (EudoraSendListener *)m_pListener; if (NS_FAILED( rv)) { IMPORT_LOG1( "*** Error, CreateAndSendMessage FAILED: 0x%lx\n", rv); // IMPORT_LOG1( "Headers: %80s\n", m_pHeaders); } else { // wait for the listener to get done! PRInt32 abortCnt = 0; PRInt32 cnt = 0; PRInt32 sleepCnt = 1; while (!pListen->m_done && (abortCnt < kHungAbortCount)) { PR_Sleep( sleepCnt); cnt++; if (cnt > kHungCount) { abortCnt++; sleepCnt *= 2; cnt = 0; } } if (abortCnt >= kHungAbortCount) { IMPORT_LOG0( "**** Create and send message hung\n"); IMPORT_LOG1( "Headers: %s\n", m_pHeaders); IMPORT_LOG1( "Body: %s\n", m_pBody); rv = NS_ERROR_FAILURE; } } if (pMimeType) NS_Free( pMimeType); if (pListen->m_location) { pListen->m_location->Clone(pMsg); rv = NS_OK; } else { rv = NS_ERROR_FAILURE; IMPORT_LOG0( "*** Error, Outlook compose unsuccessful\n"); } pListen->Reset(); return( rv); }
// Test a message send???? nsresult nsEudoraCompose::SendTheMessage(nsIFile *pMailImportLocation, nsIFile **pMsg) { nsresult rv = CreateComponents(); if (NS_FAILED(rv)) return rv; // IMPORT_LOG0("Outlook Compose created necessary components\n"); nsString bodyType; nsString charSet; nsString headerVal; GetHeaderValue(m_pHeaders, m_headerLen, "From:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetFrom(headerVal); GetHeaderValue(m_pHeaders, m_headerLen, "To:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetTo(headerVal); GetHeaderValue(m_pHeaders, m_headerLen, "Subject:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetSubject(headerVal); GetHeaderValue(m_pHeaders, m_headerLen, "Content-type:", headerVal); bodyType = headerVal; ExtractType(bodyType); ExtractCharset(headerVal); // Use platform charset as default if the msg doesn't specify one // (ie, no 'charset' param in the Content-Type: header). As the last // resort we'll use the mail default charset. // (ie, no 'charset' param in the Content-Type: header) or if the // charset parameter fails a length sanity check. // As the last resort we'll use the mail default charset. if (headerVal.IsEmpty() || (headerVal.Length() > kContentTypeLengthSanityCheck)) { headerVal.AssignASCII(nsMsgI18NFileSystemCharset()); if (headerVal.IsEmpty()) { // last resort if (m_defCharset.IsEmpty()) { nsString defaultCharset; NS_GetLocalizedUnicharPreferenceWithDefault(nullptr, "mailnews.view_default_charset", NS_LITERAL_STRING("ISO-8859-1"), defaultCharset); m_defCharset = defaultCharset; } headerVal = m_defCharset; } } m_pMsgFields->SetCharacterSet(NS_LossyConvertUTF16toASCII(headerVal).get()); charSet = headerVal; GetHeaderValue(m_pHeaders, m_headerLen, "CC:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetCc(headerVal); GetHeaderValue(m_pHeaders, m_headerLen, "Message-ID:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetMessageId(NS_LossyConvertUTF16toASCII(headerVal).get()); GetHeaderValue(m_pHeaders, m_headerLen, "Reply-To:", headerVal); if (!headerVal.IsEmpty()) m_pMsgFields->SetReplyTo(headerVal); // what about all of the other headers?!?!?!?!?!?! char *pMimeType; if (!bodyType.IsEmpty()) pMimeType = ToNewCString(NS_LossyConvertUTF16toASCII(bodyType)); else pMimeType = ToNewCString(m_bodyType); nsCOMPtr<nsIArray> pAttach; GetLocalAttachments(getter_AddRefs(pAttach)); nsEudoraEditor eudoraEditor(m_pBody, pMailImportLocation); nsCOMPtr<nsIArray> embeddedObjects; if (eudoraEditor.HasEmbeddedContent()) eudoraEditor.GetEmbeddedObjects(getter_AddRefs(embeddedObjects)); nsString uniBody; NS_CopyNativeToUnicode(nsDependentCString(m_pBody), uniBody); /* l10n - I have the body of the message in the system charset, I need to "encode" it to be the charset for the message *UNLESS* of course, I don't know what the charset of the message should be? How do I determine what the charset should be if it doesn't exist? */ nsCString body; rv = nsMsgI18NConvertFromUnicode(NS_LossyConvertUTF16toASCII(charSet).get(), uniBody, body); if (NS_FAILED(rv) && !charSet.Equals(m_defCharset)) { // in this case, if we did not use the default compose // charset, then try that. body.Truncate(); rv = nsMsgI18NConvertFromUnicode(NS_LossyConvertUTF16toASCII(charSet).get(), uniBody, body); } uniBody.Truncate(); // See if it's a draft msg (ie, no From: or no To: AND no Cc: AND no Bcc:). // Eudora saves sent and draft msgs in Out folder (ie, mixed) and it does // store Bcc: header in the msg itself. nsAutoString from, to, cc, bcc; rv = m_pMsgFields->GetFrom(from); rv = m_pMsgFields->GetTo(to); rv = m_pMsgFields->GetCc(cc); rv = m_pMsgFields->GetBcc(bcc); bool createAsDraft = from.IsEmpty() || (to.IsEmpty() && cc.IsEmpty() && bcc.IsEmpty()); nsCOMPtr<nsIImportService> impService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); rv = impService->CreateRFC822Message( s_pIdentity, // dummy identity m_pMsgFields, // message fields pMimeType, // body type body, // body pointer createAsDraft, pAttach, // local attachments embeddedObjects, m_pListener); // listener EudoraSendListener *pListen = (EudoraSendListener *)m_pListener; if (NS_FAILED(rv)) { IMPORT_LOG1("*** Error, CreateAndSendMessage FAILED: 0x%lx\n", rv); // IMPORT_LOG1("Headers: %80s\n", m_pHeaders); } else { // wait for the listener to get done! int32_t abortCnt = 0; int32_t cnt = 0; int32_t sleepCnt = 1; while (!pListen->m_done && (abortCnt < kHungAbortCount)) { PR_Sleep(sleepCnt); cnt++; if (cnt > kHungCount) { abortCnt++; sleepCnt *= 2; cnt = 0; } } if (abortCnt >= kHungAbortCount) { IMPORT_LOG0("**** Create and send message hung\n"); IMPORT_LOG1("Headers: %s\n", m_pHeaders); IMPORT_LOG1("Body: %s\n", m_pBody); rv = NS_ERROR_FAILURE; } } if (pMimeType) NS_Free(pMimeType); if (pListen->m_location) { pListen->m_location->Clone(pMsg); rv = NS_OK; } else { rv = NS_ERROR_FAILURE; IMPORT_LOG0("*** Error, Outlook compose unsuccessful\n"); } pListen->Reset(); return rv; }
void CMapiMessage::GetBody(nsCString& dest) const { nsMsgI18NConvertFromUnicode(m_mimeCharset.get(), m_body, dest); }