Back to index

lightning-sunbird  0.9+nobinonly
mimetpla.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Ben Bucksch <mozilla@bucksch.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "mimetpla.h"
00040 #include "mimebuf.h"
00041 #include "prmem.h"
00042 #include "plstr.h"
00043 #include "mozITXTToHTMLConv.h"
00044 #include "nsCOMPtr.h"
00045 #include "nsIComponentManager.h"
00046 #include "nsString.h"
00047 #include "nsXPIDLString.h"
00048 #include "nsReadableUtils.h"
00049 #include "nsMimeStringResources.h"
00050 #include "mimemoz2.h"
00051 #include "nsIServiceManager.h"
00052 #include "nsIPrefBranch.h"
00053 #include "prprf.h"
00054 #include "nsMsgI18N.h"
00055 #include "nsMimeTypes.h"
00056 
00057 #define MIME_SUPERCLASS mimeInlineTextClass
00058 MimeDefClass(MimeInlineTextPlain, MimeInlineTextPlainClass,
00059                       mimeInlineTextPlainClass, &MIME_SUPERCLASS);
00060 
00061 static int MimeInlineTextPlain_parse_begin (MimeObject *);
00062 static int MimeInlineTextPlain_parse_line (char *, PRInt32, MimeObject *);
00063 static int MimeInlineTextPlain_parse_eof (MimeObject *, PRBool);
00064 
00065 static int
00066 MimeInlineTextPlainClassInitialize(MimeInlineTextPlainClass *clazz)
00067 {
00068   MimeObjectClass *oclass = (MimeObjectClass *) clazz;
00069   NS_ASSERTION(!oclass->class_initialized, "class not initialized");
00070   oclass->parse_begin = MimeInlineTextPlain_parse_begin;
00071   oclass->parse_line  = MimeInlineTextPlain_parse_line;
00072   oclass->parse_eof   = MimeInlineTextPlain_parse_eof;
00073   return 0;
00074 }
00075 
00076 extern "C"
00077 void 
00078 MimeTextBuildPrefixCSS(PRInt32    quotedSizeSetting,   // mail.quoted_size
00079                        PRInt32    quotedStyleSetting,  // mail.quoted_style
00080                        char       *citationColor,      // mail.citation_color
00081                        nsACString &style)               
00082 {
00083   switch (quotedStyleSetting)
00084   {
00085   case 0:     // regular
00086     break;
00087   case 1:     // bold
00088     style.Append("font-weight: bold; ");
00089     break;
00090   case 2:     // italic
00091     style.Append("font-style: italic; ");
00092     break;
00093   case 3:     // bold-italic
00094     style.Append("font-weight: bold; font-style: italic; ");
00095     break;
00096   }
00097   
00098   switch (quotedSizeSetting)
00099   {
00100   case 0:     // regular
00101     break;
00102   case 1:     // large
00103     style.Append("font-size: large; ");
00104     break;
00105   case 2:     // small
00106     style.Append("font-size: small; ");
00107     break;
00108   }
00109   
00110   if (citationColor && *citationColor)
00111   {
00112     style += "color: ";
00113     style += citationColor;
00114     style += ';';
00115   }
00116 }
00117 
00118 static int
00119 MimeInlineTextPlain_parse_begin (MimeObject *obj)
00120 {
00121   int status = 0;
00122   PRBool quoting = ( obj->options
00123     && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting ||
00124          obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting
00125        )       );  // The output will be inserted in the composer as quotation
00126   PRBool plainHTML = quoting || (obj->options &&
00127        (obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs));
00128        // Just good(tm) HTML. No reliance on CSS.
00129   PRBool rawPlainText = obj->options &&
00130        (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer
00131          || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach);
00132 
00133   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_begin(obj);
00134   if (status < 0) return status;
00135 
00136   if (!obj->output_p) return 0;
00137 
00138   if (obj->options &&
00139          obj->options->write_html_p &&
00140          obj->options->output_fn)
00141        {
00142       MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj;
00143       text->mCiteLevel = 0;
00144 
00145       // Get the prefs
00146 
00147       // Quoting
00148       text->mBlockquoting = PR_TRUE; // mail.quoteasblock
00149 
00150       // Viewing
00151       text->mQuotedSizeSetting = 0;   // mail.quoted_size
00152       text->mQuotedStyleSetting = 0;  // mail.quoted_style
00153       text->mCitationColor = nsnull;  // mail.citation_color
00154       PRBool graphicalQuote = PR_TRUE; // mail.quoted_graphical
00155 
00156       nsIPrefBranch *prefBranch = GetPrefBranch(obj->options);
00157       if (prefBranch)
00158       {
00159         prefBranch->GetIntPref("mail.quoted_size", &(text->mQuotedSizeSetting));
00160         prefBranch->GetIntPref("mail.quoted_style", &(text->mQuotedStyleSetting));
00161         prefBranch->GetCharPref("mail.citation_color", &(text->mCitationColor));
00162         prefBranch->GetBoolPref("mail.quoted_graphical", &graphicalQuote);
00163         prefBranch->GetBoolPref("mail.quoteasblock", &(text->mBlockquoting));
00164       }
00165 
00166       if (!rawPlainText)
00167       {
00168         // Get font
00169         // only used for viewing (!plainHTML)
00170         nsCAutoString fontstyle;
00171         nsCAutoString fontLang;  // langgroup of the font
00172 
00173         // generic font-family name ( -moz-fixed for fixed font and NULL for
00174         // variable font ) is sufficient now that bug 105199 has been fixed.
00175 
00176         if (!obj->options->variable_width_plaintext_p)
00177           fontstyle = "font-family: -moz-fixed";
00178 
00179         if (nsMimeOutput::nsMimeMessageBodyDisplay == obj->options->format_out ||
00180             nsMimeOutput::nsMimeMessagePrintOutput == obj->options->format_out)
00181         {
00182           PRInt32 fontSize;       // default font size
00183           PRInt32 fontSizePercentage;   // size percentage
00184           nsresult rv = GetMailNewsFont(obj,
00185                              !obj->options->variable_width_plaintext_p,
00186                              &fontSize, &fontSizePercentage, fontLang);
00187           if (NS_SUCCEEDED(rv))
00188           {
00189             if ( ! fontstyle.IsEmpty() ) {
00190               fontstyle += "; ";
00191             }
00192             fontstyle += "font-size: ";
00193             fontstyle.AppendInt(fontSize);
00194             fontstyle += "px;";
00195           }
00196         }
00197 
00198         // Opening <div>. We currently have to add formatting here. :-(
00199         nsCAutoString openingDiv;
00200         if (!quoting)
00201              /* 4.x' editor can't break <div>s (e.g. to interleave comments).
00202                 We'll add the class to the <blockquote type=cite> later. */
00203         {
00204           openingDiv = "<div class=\"moz-text-plain\"";
00205           if (!plainHTML)
00206           {
00207             if (obj->options->wrap_long_lines_p)
00208               openingDiv += " wrap=true";
00209             else
00210               openingDiv += " wrap=false";
00211 
00212             if (graphicalQuote)
00213               openingDiv += " graphical-quote=true";
00214             else
00215               openingDiv += " graphical-quote=false";
00216 
00217             if (!fontstyle.IsEmpty())
00218             {
00219               openingDiv += " style=\"";
00220               openingDiv += fontstyle;
00221               openingDiv += '\"';
00222             }
00223             if (!fontLang.IsEmpty())
00224             {
00225               openingDiv += " lang=\"";
00226               openingDiv += fontLang;
00227               openingDiv += '\"';
00228             }
00229           }
00230           openingDiv += "><pre wrap>";
00231         }
00232         else
00233           openingDiv = "<pre wrap>";
00234            status = MimeObject_write(obj, openingDiv.get(), openingDiv.Length(), PR_FALSE);
00235            if (status < 0) return status;
00236 
00237            /* text/plain objects always have separators before and after them.
00238                  Note that this is not the case for text/enriched objects. */
00239            status = MimeObject_write_separator(obj);
00240            if (status < 0) return status;
00241     }
00242        }
00243 
00244   return 0;
00245 }
00246 
00247 static int
00248 MimeInlineTextPlain_parse_eof (MimeObject *obj, PRBool abort_p)
00249 {
00250   int status;
00251 
00252   // Has this method already been called for this object?
00253   // In that case return.
00254   if (obj->closed_p) return 0;
00255 
00256   nsXPIDLCString citationColor;
00257   MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj;
00258   if (text && text->mCitationColor)
00259     citationColor.Adopt(text->mCitationColor);
00260 
00261   PRBool quoting = ( obj->options
00262     && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting ||
00263          obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting
00264        )           );  // see above
00265   
00266   PRBool rawPlainText = obj->options &&
00267        (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer
00268         || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach);
00269 
00270   /* Run parent method first, to flush out any buffered data. */
00271   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p);
00272   if (status < 0) return status;
00273 
00274   // if this part has a name and it's not a message/rfc822, don't quote
00275   if (quoting && obj->headers && MimeHeaders_get_name(obj->headers, obj->options) 
00276       && PL_strcasecmp(obj->content_type, MESSAGE_RFC822))
00277     return 0;
00278 
00279   if (!obj->output_p) return 0;
00280 
00281   if (obj->options &&
00282          obj->options->write_html_p &&
00283          obj->options->output_fn &&
00284          !abort_p && !rawPlainText)
00285        {
00286       MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj;
00287       if (text->mIsSig && !quoting)
00288       {
00289         status = MimeObject_write(obj, "</div>", 6, PR_FALSE);  // .moz-txt-sig
00290         if (status < 0) return status;
00291       }
00292       status = MimeObject_write(obj, "</pre>", 6, PR_FALSE);
00293       if (status < 0) return status;
00294       if (!quoting)
00295       {
00296         status = MimeObject_write(obj, "</div>", 6, PR_FALSE);
00297                                         // .moz-text-plain
00298         if (status < 0) return status;
00299       }
00300 
00301       /* text/plain objects always have separators before and after them.
00302                Note that this is not the case for text/enriched objects.
00303           */
00304          status = MimeObject_write_separator(obj);
00305          if (status < 0) return status;
00306        }
00307 
00308   return 0;
00309 }
00310 
00311 
00312 static int
00313 MimeInlineTextPlain_parse_line (char *line, PRInt32 length, MimeObject *obj)
00314 {
00315   int status;
00316   PRBool quoting = ( obj->options
00317     && ( obj->options->format_out == nsMimeOutput::nsMimeMessageQuoting ||
00318          obj->options->format_out == nsMimeOutput::nsMimeMessageBodyQuoting
00319        )           );  // see above
00320   PRBool plainHTML = quoting || (obj->options &&
00321        obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs);
00322        // see above
00323 
00324   PRBool rawPlainText = obj->options &&
00325        (obj->options->format_out == nsMimeOutput::nsMimeMessageFilterSniffer
00326        || obj->options->format_out == nsMimeOutput::nsMimeMessageAttach);
00327 
00328   // this routine gets called for every line of data that comes through the
00329   // mime converter. It's important to make sure we are efficient with 
00330   // how we allocate memory in this routine. be careful if you go to add
00331   // more to this routine.
00332 
00333   NS_ASSERTION(length > 0, "zero length");
00334   if (length <= 0) return 0;
00335 
00336   mozITXTToHTMLConv *conv = GetTextConverter(obj->options);
00337   MimeInlineTextPlain *text = (MimeInlineTextPlain *) obj;
00338 
00339   PRBool skipConversion = !conv || rawPlainText ||
00340                           (obj->options && obj->options->force_user_charset);
00341 
00342   char *mailCharset = NULL;
00343   nsresult rv;
00344 
00345   // if this part has a name and it's not a message/rfc822, don't quote
00346   if (quoting && obj->headers && MimeHeaders_get_name(obj->headers, obj->options) 
00347       && PL_strcasecmp(obj->content_type, MESSAGE_RFC822))
00348     return 0;
00349 
00350   if (!skipConversion)
00351   {
00352     nsDependentCString inputStr(line, length);
00353     nsAutoString lineSourceStr;
00354 
00355     // For 'SaveAs', |line| is in |mailCharset|.
00356     // convert |line| to UTF-16 before 'html'izing (calling ScanTXT())
00357     if (obj->options->format_out == nsMimeOutput::nsMimeMessageSaveAs)
00358     { // Get the mail charset of this message.
00359       MimeInlineText  *inlinetext = (MimeInlineText *) obj;
00360       if (!inlinetext->initializeCharset)
00361          ((MimeInlineTextClass*)&mimeInlineTextClass)->initialize_charset(obj);
00362       mailCharset = inlinetext->charset;
00363       if (mailCharset && *mailCharset) {
00364         rv = nsMsgI18NConvertToUnicode(mailCharset, inputStr, lineSourceStr);
00365         NS_ENSURE_SUCCESS(rv, -1);
00366       }
00367       else // this probably never happens ...
00368         CopyUTF8toUTF16(inputStr, lineSourceStr);
00369     }
00370     else  // line is in UTF-8
00371       CopyUTF8toUTF16(inputStr, lineSourceStr);
00372 
00373     nsCAutoString prefaceResultStr;  // Quoting stuff before the real text
00374 
00375     // Recognize quotes
00376     PRUint32 oldCiteLevel = text->mCiteLevel;
00377     PRUint32 logicalLineStart = 0;
00378     rv = conv->CiteLevelTXT(lineSourceStr.get(),
00379                             &logicalLineStart, &(text->mCiteLevel));
00380     NS_ENSURE_SUCCESS(rv, -1);
00381 
00382     // Find out, which recognitions to do
00383     PRBool whattodo = obj->options->whattodo;
00384     if (plainHTML)
00385     {
00386       if (quoting)
00387         whattodo = 0;  // This is done on Send. Don't do it twice.
00388       else
00389         whattodo = whattodo & ~mozITXTToHTMLConv::kGlyphSubstitution;
00390                    /* Do recognition for the case, the result is viewed in
00391                       Mozilla, but not GlyphSubstitution, because other UAs
00392                       might not be able to display the glyphs. */
00393       if (!text->mBlockquoting)
00394         text->mCiteLevel = 0;
00395     }
00396 
00397     // Write blockquote
00398     if (text->mCiteLevel > oldCiteLevel)
00399     {
00400       prefaceResultStr += "</pre>";
00401       for (PRUint32 i = 0; i < text->mCiteLevel - oldCiteLevel; i++)
00402       {
00403         nsCAutoString style;
00404         MimeTextBuildPrefixCSS(text->mQuotedSizeSetting, text->mQuotedStyleSetting,
00405                                text->mCitationColor, style);
00406         if (!plainHTML && !style.IsEmpty())
00407         {
00408           prefaceResultStr += "<blockquote type=cite style=\"";
00409           prefaceResultStr += style;
00410           prefaceResultStr += "\">";
00411         }
00412         else
00413           prefaceResultStr += "<blockquote type=cite>";
00414       }
00415       prefaceResultStr += "<pre wrap>";
00416     }
00417     else if (text->mCiteLevel < oldCiteLevel)
00418     {
00419       prefaceResultStr += "</pre>";
00420       for (PRUint32 i = 0; i < oldCiteLevel - text->mCiteLevel; i++)
00421         prefaceResultStr += "</blockquote>";
00422       prefaceResultStr += "<pre wrap>";
00423       if (text->mCiteLevel == 0)
00424         prefaceResultStr += "<!---->";   /* Make sure, NGLayout puts out
00425                                             a linebreak */
00426     }
00427 
00428     // Write plain text quoting tags
00429     if (logicalLineStart != 0 && !(plainHTML && text->mBlockquoting))
00430     {
00431       if (!plainHTML)
00432         prefaceResultStr += "<span class=\"moz-txt-citetags\">";
00433 
00434       nsAutoString citeTagsSource;
00435       lineSourceStr.Mid(citeTagsSource, 0, logicalLineStart);
00436 
00437       // Convert to HTML
00438       nsXPIDLString citeTagsResultUnichar;
00439       rv = conv->ScanTXT(citeTagsSource.get(), 0 /* no recognition */,
00440                          getter_Copies(citeTagsResultUnichar));
00441       if (NS_FAILED(rv)) return -1;
00442 
00443       AppendUTF16toUTF8(citeTagsResultUnichar, prefaceResultStr);
00444       if (!plainHTML)
00445         prefaceResultStr += "</span>";
00446     }
00447 
00448 
00449     // recognize signature
00450     if ((lineSourceStr.Length() >= 4)
00451         && lineSourceStr.First() == '-'
00452         && Substring(lineSourceStr, 0, 3).EqualsLiteral("-- ")
00453         && (lineSourceStr[3] == '\r' || lineSourceStr[3] == '\n') )
00454     {
00455       text->mIsSig = PR_TRUE;
00456       if (!quoting)
00457         prefaceResultStr += "<div class=\"moz-txt-sig\">";
00458     }
00459 
00460 
00461     /* This is the main TXT to HTML conversion:
00462        escaping (very important), eventually recognizing etc. */
00463     nsXPIDLString lineResultUnichar;
00464 
00465     rv = conv->ScanTXT(lineSourceStr.get() + logicalLineStart,
00466                        whattodo, getter_Copies(lineResultUnichar));
00467     NS_ENSURE_SUCCESS(rv, -1);
00468 
00469     if (!(text->mIsSig && quoting))
00470     {
00471       status = MimeObject_write(obj, prefaceResultStr.get(), prefaceResultStr.Length(), PR_TRUE);
00472       if (status < 0) return status;
00473       nsCAutoString outString;
00474       if (obj->options->format_out != nsMimeOutput::nsMimeMessageSaveAs ||
00475           !mailCharset || !*mailCharset)
00476         CopyUTF16toUTF8(lineResultUnichar, outString);
00477       else
00478       { // convert back to mailCharset before writing.       
00479         rv = nsMsgI18NConvertFromUnicode(mailCharset, 
00480                                          lineResultUnichar, outString);
00481         NS_ENSURE_SUCCESS(rv, -1);
00482       }
00483 
00484       status = MimeObject_write(obj, outString.get(), outString.Length(), PR_TRUE);
00485     }
00486     else
00487     {
00488       status = NS_OK;
00489     }
00490   }
00491   else
00492   {
00493     status = MimeObject_write(obj, line, length, PR_TRUE);
00494   }
00495 
00496   return status;
00497 }
00498