kmail

headerstyle.cpp

00001 /*  -*- c++ -*-
00002     headerstyle.cpp
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (c) 2003 Marc Mutz <mutz@kde.org>
00006 
00007     KMail is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU General Public License, version 2, as
00009     published by the Free Software Foundation.
00010 
00011     KMail is distributed in the hope that it will be useful, but
00012     WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020     In addition, as a special exception, the copyright holders give
00021     permission to link the code of this program with any edition of
00022     the Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), and distribute linked
00024     combinations including the two.  You must obey the GNU General
00025     Public License in all respects for all of the code used other than
00026     Qt.  If you modify this file, you may extend this exception to
00027     your version of the file, but you are not obligated to do so.  If
00028     you do not wish to do so, delete this exception statement from
00029     your version.
00030 */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035 
00036 #include "headerstyle.h"
00037 
00038 #include "headerstrategy.h"
00039 #include "kmkernel.h"
00040 #include "linklocator.h"
00041 #include "kmmessage.h"
00042 #include "spamheaderanalyzer.h"
00043 #include "globalsettings.h"
00044 
00045 #include <libemailfunctions/email.h>
00046 #include <libkdepim/kxface.h>
00047 using namespace KPIM;
00048 
00049 #include <mimelib/string.h>
00050 #include <mimelib/field.h>
00051 #include <mimelib/headers.h>
00052 
00053 #include <kdebug.h>
00054 #include <klocale.h>
00055 #include <kglobal.h>
00056 #include <kimproxy.h>
00057 #include <kabc/stdaddressbook.h>
00058 #include <kabc/addresseelist.h>
00059 #include <kmdcodec.h>
00060 #include <qdatetime.h>
00061 #include <qbuffer.h>
00062 #include <qbitmap.h>
00063 #include <qimage.h>
00064 #include <qapplication.h>
00065 #include <qregexp.h>
00066 
00067 namespace KMail {
00068 
00069   //
00070   // Convenience functions:
00071   //
00072   static inline QString directionOf( const QString & str ) {
00073     return str.isRightToLeft() ? "rtl" : "ltr" ;
00074   }
00075 
00076 #if 0
00077   // Converts to html. Changes URLs into href's, escapes HTML special
00078   // chars and inserts the result into an <div> or <span> tag with
00079   // "dir" set to "rtl" or "ltr" depending on the direction of @p str.
00080   static QString convertToHtmlBlock( const QString & str, bool useSpan=false ) {
00081     QString dir = directionOf( str );
00082     QString format = "<%1 dir=\"%3\">%4</%2>";
00083     return format.arg( useSpan ? "span" : "div" )
00084                  .arg( useSpan ? "span" : "div" )
00085                  .arg( dir )
00086                  .arg( LinkLocator::convertToHtml( str ) );
00087   }
00088 #endif
00089 
00090   // ### tmp wrapper to make kmreaderwin code working:
00091   static QString strToHtml( const QString & str,
00092                             int flags = LinkLocator::PreserveSpaces ) {
00093     return LinkLocator::convertToHtml( str, flags );
00094   }
00095 
00096   //
00097   // BriefHeaderStyle
00098   //   Show everything in a single line, don't show header field names.
00099   //
00100 
00101   class BriefHeaderStyle : public HeaderStyle {
00102     friend class ::KMail::HeaderStyle;
00103   protected:
00104     BriefHeaderStyle() : HeaderStyle() {}
00105     virtual ~BriefHeaderStyle() {}
00106 
00107   public:
00108     const char * name() const { return "brief"; }
00109     const HeaderStyle * next() const { return plain(); }
00110     const HeaderStyle * prev() const { return fancy(); }
00111 
00112     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00113                     const QString & vCardName, bool printing ) const;
00114   };
00115 
00116   QString BriefHeaderStyle::format( const KMMessage * message,
00117                                     const HeaderStrategy * strategy,
00118                                     const QString & vCardName, bool printing ) const {
00119     if ( !message ) return QString::null;
00120     if ( !strategy )
00121       strategy = HeaderStrategy::brief();
00122 
00123     // The direction of the header is determined according to the direction
00124     // of the application layout.
00125 
00126     QString dir = QApplication::reverseLayout() ? "rtl" : "ltr" ;
00127 
00128     // However, the direction of the message subject within the header is
00129     // determined according to the contents of the subject itself. Since
00130     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00131     // considered left-to-right, they are ignored when determining its
00132     // direction.
00133 
00134     QString subjectDir;
00135     if (!message->subject().isEmpty())
00136       subjectDir = directionOf( message->cleanSubject() );
00137     else
00138       subjectDir = directionOf( i18n("No Subject") );
00139 
00140     // Prepare the date string (when printing always use the localized date)
00141     QString dateString;
00142     if( printing ) {
00143       QDateTime dateTime;
00144       KLocale * locale = KGlobal::locale();
00145       dateTime.setTime_t( message->date() );
00146       dateString = locale->formatDateTime( dateTime );
00147     } else {
00148       dateString = message->dateStr();
00149     }
00150 
00151     QString headerStr = "<div class=\"header\" dir=\"" + dir + "\">\n";
00152 
00153     if ( strategy->showHeader( "subject" ) )
00154       headerStr += "<div dir=\"" + subjectDir + "\">\n"
00155                    "<b style=\"font-size:130%\">" +
00156                            strToHtml( message->subject() ) +
00157                            "</b></div>\n";
00158 
00159     QStringList headerParts;
00160 
00161     if ( strategy->showHeader( "from" ) ) {
00162       QString fromStr = message->from();
00163       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00164         fromStr = message->fromStrip(); // let's use that
00165       QString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true );
00166       if ( !vCardName.isEmpty() )
00167         fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\">" + i18n("[vCard]") + "</a>";
00168       headerParts << fromPart;
00169     }
00170 
00171     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00172       headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true );
00173 
00174     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00175       headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true );
00176 
00177     if ( strategy->showHeader( "date" ) )
00178       headerParts << strToHtml(message->dateShortStr());
00179 
00180     // remove all empty (modulo whitespace) entries and joins them via ", \n"
00181     headerStr += " (" + headerParts.grep( QRegExp( "\\S" ) ).join( ",\n" ) + ')';
00182 
00183     headerStr += "</div>\n";
00184 
00185     // ### iterate over the rest of strategy->headerToDisplay() (or
00186     // ### all headers if DefaultPolicy == Display) (elsewhere, too)
00187     return headerStr;
00188   }
00189 
00190   //
00191   // PlainHeaderStyle:
00192   //   show every header field on a line by itself,
00193   //   show subject larger
00194   //
00195 
00196   class PlainHeaderStyle : public HeaderStyle {
00197     friend class ::KMail::HeaderStyle;
00198   protected:
00199     PlainHeaderStyle() : HeaderStyle() {}
00200     virtual ~PlainHeaderStyle() {}
00201 
00202   public:
00203     const char * name() const { return "plain"; }
00204     const HeaderStyle * next() const { return fancy(); }
00205     const HeaderStyle * prev() const { return brief(); }
00206 
00207     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00208                     const QString & vCardName, bool printing ) const;
00209 
00210   private:
00211     QString formatAllMessageHeaders( const KMMessage * message ) const;
00212   };
00213 
00214   QString PlainHeaderStyle::format( const KMMessage * message,
00215                                     const HeaderStrategy * strategy,
00216                                     const QString & vCardName, bool printing ) const {
00217     if ( !message ) return QString::null;
00218     if ( !strategy )
00219       strategy = HeaderStrategy::rich();
00220 
00221     // The direction of the header is determined according to the direction
00222     // of the application layout.
00223 
00224     QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00225 
00226     // However, the direction of the message subject within the header is
00227     // determined according to the contents of the subject itself. Since
00228     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00229     // considered left-to-right, they are ignored when determining its
00230     // direction.
00231 
00232     QString subjectDir;
00233     if (!message->subject().isEmpty())
00234       subjectDir = directionOf( message->cleanSubject() );
00235     else
00236       subjectDir = directionOf( i18n("No Subject") );
00237 
00238     // Prepare the date string (when printing always use the localized date)
00239     QString dateString;
00240     if( printing ) {
00241       QDateTime dateTime;
00242       KLocale* locale = KGlobal::locale();
00243       dateTime.setTime_t( message->date() );
00244       dateString = locale->formatDateTime( dateTime );
00245     }
00246     else {
00247       dateString = message->dateStr();
00248     }
00249 
00250     QString headerStr = QString("<div class=\"header\" dir=\"%1\">").arg(dir);
00251 
00252     if ( strategy->headersToDisplay().isEmpty()
00253          && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00254       // crude way to emulate "all" headers:
00255       headerStr += formatAllMessageHeaders( message );
00256       return headerStr + "</div>";
00257     }
00258 
00259     //case HdrLong:
00260     if ( strategy->showHeader( "subject" ) )
00261       headerStr += QString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
00262                            strToHtml(message->subject()) + "</b></div>\n")
00263                         .arg(subjectDir);
00264 
00265     if ( strategy->showHeader( "date" ) )
00266       headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
00267 
00268 #if 0
00269     // Get Instant Messaging presence
00270     QString presence;
00271     QString kabcUid;
00272     if ( strategy->showHeader( "status" ) )
00273     {
00274       KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00275       KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00276       ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00277       kabcUid = addresses[0].uid();
00278       presence = imProxy->presenceString( kabcUid );
00279     }
00280 #endif
00281 
00282     if ( strategy->showHeader( "from" ) ) {
00283       QString fromStr = message->from();
00284       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00285         fromStr = message->fromStrip(); // let's use that
00286       headerStr.append(i18n("From: ") +
00287           KMMessage::emailAddrAsAnchor( fromStr, false) );
00288       if ( !vCardName.isEmpty() )
00289         headerStr.append("&nbsp;&nbsp;<a href=\"" + vCardName +
00290               "\">" + i18n("[vCard]") + "</a>" );
00291 #if 0
00292       if ( !presence.isEmpty() && strategy->showHeader( "status" ) )
00293         headerStr.append("&nbsp;&nbsp;(<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)" );
00294 #endif
00295 
00296       if ( strategy->showHeader( "organization" )
00297           && !message->headerField("Organization").isEmpty())
00298         headerStr.append("&nbsp;&nbsp;(" +
00299               strToHtml(message->headerField("Organization")) + ")");
00300       headerStr.append("<br>\n");
00301     }
00302 
00303     if ( strategy->showHeader( "to" ) )
00304       headerStr.append(i18n("To: ")+
00305                        KMMessage::emailAddrAsAnchor(message->to(),FALSE) + "<br>\n");
00306 
00307     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00308       headerStr.append(i18n("CC: ")+
00309                        KMMessage::emailAddrAsAnchor(message->cc(),FALSE) + "<br>\n");
00310 
00311     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00312       headerStr.append(i18n("BCC: ")+
00313                        KMMessage::emailAddrAsAnchor(message->bcc(),FALSE) + "<br>\n");
00314 
00315     if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
00316       headerStr.append(i18n("Reply to: ")+
00317                      KMMessage::emailAddrAsAnchor(message->replyTo(),FALSE) + "<br>\n");
00318 
00319     headerStr += "</div>\n";
00320 
00321     return headerStr;
00322   }
00323 
00324   QString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
00325     const DwHeaders & headers = message->headers();
00326     QString result;
00327 
00328     for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00329       result += ( field->FieldNameStr() + ": " ).c_str();
00330       result += strToHtml( field->FieldBodyStr().c_str() );
00331       result += "<br>\n";
00332     }
00333 
00334     return result;
00335   }
00336 
00337   //
00338   // FancyHeaderStyle:
00339   //   Like PlainHeaderStyle, but with slick frames and background colours.
00340   //
00341 
00342   class FancyHeaderStyle : public HeaderStyle {
00343     friend class ::KMail::HeaderStyle;
00344   protected:
00345     FancyHeaderStyle() : HeaderStyle() {}
00346     virtual ~FancyHeaderStyle() {}
00347 
00348   public:
00349     const char * name() const { return "fancy"; }
00350     const HeaderStyle * next() const { return brief(); }
00351     const HeaderStyle * prev() const { return plain(); }
00352 
00353     QString format( const KMMessage * message, const HeaderStrategy * strategy,
00354                     const QString & vCardName, bool printing ) const;
00355     static QString imgToDataUrl( const QImage & image,
00356                                  const char *fmt = "PNG" );
00357 
00358   private:
00359     static QString drawSpamMeter( double percent, const QString & filterHeader );
00360 
00361   };
00362 
00363   QString FancyHeaderStyle::drawSpamMeter( double percent,
00364                                            const QString & filterHeader )
00365   {
00366     QImage meterBar( 20, 1, 8, 24 );
00367     const unsigned short gradient[20][3] = {
00368       {   0, 255,   0 },
00369       {  27, 254,   0 },
00370       {  54, 252,   0 },
00371       {  80, 250,   0 },
00372       { 107, 249,   0 },
00373       { 135, 247,   0 },
00374       { 161, 246,   0 },
00375       { 187, 244,   0 },
00376       { 214, 242,   0 },
00377       { 241, 241,   0 },
00378       { 255, 228,   0 },
00379       { 255, 202,   0 },
00380       { 255, 177,   0 },
00381       { 255, 151,   0 },
00382       { 255, 126,   0 },
00383       { 255, 101,   0 },
00384       { 255,  76,   0 },
00385       { 255,  51,   0 },
00386       { 255,  25,   0 },
00387       { 255,   0,   0 }
00388     };
00389     meterBar.setColor( 21, qRgb( 255, 255, 255 ) );
00390     meterBar.setColor( 22, qRgb( 170, 170, 170 ) );
00391     if ( percent < 0 ) // grey is for errors
00392       meterBar.fill( 22 );
00393     else {
00394       meterBar.fill( 21 );
00395       int max = QMIN( 20, static_cast<int>( percent ) / 5 );
00396       for ( int i = 0; i < max; ++i ) {
00397         meterBar.setColor( i+1, qRgb( gradient[i][0], gradient[i][1],
00398                                       gradient[i][2] ) );
00399         meterBar.setPixel( i, 0, i+1 );
00400       }
00401     }
00402     QString titleText = i18n("%1% probability of being spam.\n\nFull report:\n%2")
00403                      .arg( QString::number( percent ), filterHeader );
00404     return QString("<img src=\"%1\" width=\"%2\" height=\"%3\" style=\"border: 1px solid black;\" title=\"%4\"> &nbsp;")
00405       .arg( imgToDataUrl( meterBar, "PPM" ), QString::number( 20 ),
00406             QString::number( 5 ), titleText );
00407   }
00408 
00409 
00410   QString FancyHeaderStyle::format( const KMMessage * message,
00411                                     const HeaderStrategy * strategy,
00412                                     const QString & vCardName, bool printing ) const {
00413     if ( !message ) return QString::null;
00414     if ( !strategy )
00415       strategy = HeaderStrategy::rich();
00416 
00417     KConfigGroup configReader( KMKernel::config(), "Reader" );
00418 
00419     // ### from kmreaderwin begin
00420     // The direction of the header is determined according to the direction
00421     // of the application layout.
00422 
00423     QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00424     QString headerStr = QString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00425 
00426     // However, the direction of the message subject within the header is
00427     // determined according to the contents of the subject itself. Since
00428     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00429     // considered left-to-right, they are ignored when determining its
00430     // direction.
00431 
00432     QString subjectDir;
00433     if ( !message->subject().isEmpty() )
00434       subjectDir = directionOf( message->cleanSubject() );
00435     else
00436       subjectDir = directionOf( i18n("No Subject") );
00437 
00438     // Prepare the date string (when printing always use the localized date)
00439     QString dateString;
00440     if( printing ) {
00441       QDateTime dateTime;
00442       KLocale* locale = KGlobal::locale();
00443       dateTime.setTime_t( message->date() );
00444       dateString = locale->formatDateTime( dateTime );
00445     }
00446     else {
00447       dateString = message->dateStr();
00448     }
00449 
00450     // Spam header display.
00451     // If the spamSpamStatus config value is true then we look for headers
00452     // from a few spam filters and try to create visually meaningful graphics
00453     // out of the spam scores.
00454 
00455     QString spamHTML;
00456 
00457     if ( configReader.readBoolEntry( "showSpamStatus", true ) ) {
00458       SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message );
00459       for ( SpamScoresIterator it = scores.begin(); it != scores.end(); ++it )
00460         spamHTML += (*it).agent() + " " +
00461                     drawSpamMeter( (*it).score(), (*it).spamHeader() );
00462     }
00463 
00464     QString userHTML;
00465     QString presence;
00466 
00467     // IM presence and kabc photo
00468 
00469     ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00470     QString kabcUid;
00471     KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00472     KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00473 
00474     QString photoURL;
00475     int photoWidth = 60;
00476     int photoHeight = 60;
00477     if( addresses.count() == 1 )
00478     {
00479       // kabcUid is embedded in im: URIs to indicate which IM contact to message
00480       kabcUid = addresses[0].uid();
00481 
00482       if ( imProxy->initialize() ) {
00483           // im status
00484           presence = imProxy->presenceString( kabcUid );
00485           if ( !presence.isEmpty() )
00486           {
00487             QString presenceIcon = QString::fromLatin1( " <img src=\"%1\"/>" )
00488                 .arg( imgToDataUrl( imProxy->presenceIcon( kabcUid ).convertToImage() ) );
00489             presence += presenceIcon;
00490           }
00491       }
00492       // picture
00493       if ( addresses[0].photo().isIntern() )
00494       {
00495         // get photo data and convert to data: url
00496         //kdDebug( 5006 ) << "INTERNAL photo found" << endl;
00497         QImage photo = addresses[0].photo().data();
00498         if ( !photo.isNull() )
00499         {
00500           photoWidth = photo.width();
00501           photoHeight = photo.height();
00502           // scale below 60, otherwise it can get way too large
00503           if ( photoHeight > 60 ) {
00504             double ratio = ( double )photoHeight / ( double )photoWidth;
00505             photoHeight = 60;
00506             photoWidth = (int)( 60 / ratio );
00507             photo = photo.smoothScale( photoWidth, photoHeight );
00508           }
00509           photoURL = imgToDataUrl( photo );
00510         }
00511       }
00512       else
00513       {
00514         //kdDebug( 5006 ) << "URL found" << endl;
00515         photoURL = addresses[0].photo().url();
00516         if ( photoURL.startsWith("/") )
00517           photoURL.prepend( "file:" );
00518       }
00519     }
00520     else // TODO: find a usable one
00521     {
00522       kdDebug( 5006 ) << "Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
00523       userHTML = "&nbsp;";
00524     }
00525 
00526     if( photoURL.isEmpty() )
00527     {
00528       // no photo, look for a X-Face header
00529       QString xfaceURL;
00530       QString xfhead = message->headerField( "X-Face" );
00531       if ( !xfhead.isEmpty() )
00532       {
00533         KXFace xf;
00534         photoURL = imgToDataUrl( xf.toImage( xfhead ) );
00535         photoWidth = 48;
00536         photoHeight = 48;
00537 
00538       }
00539     }
00540 
00541     if( !photoURL.isEmpty() )
00542     {
00543         //kdDebug( 5006 ) << "Got a photo: " << photoURL << endl;
00544       userHTML = QString("<img src=\"%1\" width=\"%2\" height=\"%3\">")
00545           .arg( photoURL ).arg( photoWidth ).arg( photoHeight );
00546       if ( presence.isEmpty() ) {
00547         userHTML = QString("<div class=\"senderpic\">") + userHTML + "</div>";
00548       } else {
00549         userHTML = QString( "<div class=\"senderpic\">"
00550             "<a href=\"im:%1\">%2<div class=\"senderstatus\">"
00551             "<span name=\"presence-%3\">%4</span></div></a>"
00552             "</div>" ).arg( kabcUid )
00553             .arg( userHTML )
00554              .arg( kabcUid )
00555             .arg( presence );
00556       }
00557     } else {
00558        // we don't have a photo, just show presence, if we have it
00559       if ( !presence.isEmpty() )
00560         userHTML = QString( "<a href=\"im:%1\"><div class=\"senderstatus\">"
00561             "<span name=\"presence-%2\">%3</span></div></a>" )
00562             .arg( kabcUid )
00563             .arg( kabcUid )
00564             .arg( presence );
00565     }
00566 #if 0
00567     // Disabled 'Launch IM' link in headers - Will
00568     if ( imProxy->imAppsAvailable() )
00569       presence = "<a name=\"launchim\" href=\"kmail:startIMApp\">" + i18n("Launch IM") + "</a></span>";
00570     // do nothing - no im apps available, leave presence empty
00571     //presence = i18n( "DCOP/InstantMessenger not installed" );
00572     kdDebug( 5006 ) << "final presence: '" << presence << "'" << endl;
00573 #endif
00574 
00575 
00576     //case HdrFancy:
00577     // the subject line and box below for details
00578     if ( strategy->showHeader( "subject" ) ) {
00579       const int flags = LinkLocator::PreserveSpaces |
00580                         ( GlobalSettings::self()->showEmoticons() ?
00581                           LinkLocator::ReplaceSmileys : 0 );
00582       headerStr += QString("<div dir=\"%1\">%2</div>\n")
00583                         .arg(subjectDir)
00584                         .arg(message->subject().isEmpty()?
00585                              i18n("No Subject") :
00586                              strToHtml( message->subject(), flags ));
00587     }
00588     headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00589     //headerStr += "<table>\n";
00590     // from line
00591     // the mailto: URLs can contain %3 etc., therefore usage of multiple
00592     // QString::arg is not possible
00593     if ( strategy->showHeader( "from" ) ) {
00594       QString fromStr = message->from();
00595       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00596         fromStr = message->fromStrip(); // let's use that
00597       headerStr += QString("<tr><th>%1</th>\n"
00598                            "<td>")
00599                            .arg(i18n("From: "))
00600                  + KMMessage::emailAddrAsAnchor( fromStr, false )
00601                  + ( !message->headerField( "Resent-From" ).isEmpty() ? "&nbsp;"
00602                                 + i18n("(resent from %1)")
00603                                   .arg( KMMessage::emailAddrAsAnchor(
00604                                     message->headerField( "Resent-From" ),FALSE) )
00605                               : QString("") )
00606                  + ( !vCardName.isEmpty() ? "&nbsp;&nbsp;<a href=\"" + vCardName + "\">"
00607                                 + i18n("[vCard]") + "</a>"
00608                               : QString("") )
00609 #if 0
00610                  + ( ( !presence.isEmpty() )
00611                               ? "&nbsp;&nbsp;(<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)"
00612                               : QString("") )
00613 #endif
00614                  + ( message->headerField("Organization").isEmpty()
00615                               ? QString("")
00616                               : "&nbsp;&nbsp;("
00617                                 + strToHtml(message->headerField("Organization"))
00618                                 + ")")
00619                  + "</td></tr>\n";
00620     }
00621     // to line
00622     if ( strategy->showHeader( "to" ) )
00623       headerStr.append(QString("<tr><th>%1</th>\n"
00624                    "<td>%2</td></tr>\n")
00625                             .arg(i18n("To: "))
00626                             .arg(KMMessage::emailAddrAsAnchor(message->to(),FALSE)));
00627 
00628     // cc line, if any
00629     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00630       headerStr.append(QString("<tr><th>%1</th>\n"
00631                    "<td>%2</td></tr>\n")
00632                               .arg(i18n("CC: "))
00633                               .arg(KMMessage::emailAddrAsAnchor(message->cc(),FALSE)));
00634 
00635     // Bcc line, if any
00636     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00637       headerStr.append(QString("<tr><th>%1</th>\n"
00638                    "<td>%2</td></tr>\n")
00639                               .arg(i18n("BCC: "))
00640                               .arg(KMMessage::emailAddrAsAnchor(message->bcc(),FALSE)));
00641 
00642     if ( strategy->showHeader( "date" ) )
00643       headerStr.append(QString("<tr><th>%1</th>\n"
00644                    "<td dir=\"%2\">%3</td></tr>\n")
00645                             .arg(i18n("Date: "))
00646                     .arg( directionOf( message->dateStr() ) )
00647                             .arg(strToHtml(dateString)));
00648 
00649     // FIXME: Show status in synthetic header style field.  Decide whether this or current in brackets style is best and remove one.
00650     /*    if( strategy->showHeader( "status" ) )
00651       headerStr.append( QString( "<tr><th>%1</th>\n"
00652                                  "<td dir=\"%2\">%3</td></tr>\n")
00653                                     .arg(i18n("Sender status: "))
00654                                     .arg( directionOf( onlineStatus ) )
00655                                     .arg(onlineStatus));
00656     */
00657     headerStr.append(
00658           QString( "</table></td><td align=\"center\">%1</td></tr></table>\n" ).arg(userHTML) );
00659 
00660     if ( !spamHTML.isEmpty() )
00661       headerStr.append( QString( "<div class=\"spamheader\" dir=\"%1\"><b>%2</b>&nbsp;<span style=\"padding-left: 20px;\">%3</span></div>\n")
00662                         .arg( subjectDir, i18n("Spam Status:"), spamHTML ) );
00663 
00664     headerStr += "</div>\n\n";
00665     return headerStr;
00666   }
00667 
00668   QString FancyHeaderStyle::imgToDataUrl( const QImage &image, const char* fmt  )
00669   {
00670     QByteArray ba;
00671     QBuffer buffer( ba );
00672     buffer.open( IO_WriteOnly );
00673     image.save( &buffer, fmt );
00674     return QString::fromLatin1("data:image/%1;base64,%2")
00675            .arg( fmt, KCodecs::base64Encode( ba ) );
00676   }
00677 
00678   //
00679   // HeaderStyle abstract base:
00680   //
00681 
00682   HeaderStyle::HeaderStyle() {
00683 
00684   }
00685 
00686   HeaderStyle::~HeaderStyle() {
00687 
00688   }
00689 
00690   const HeaderStyle * HeaderStyle::create( Type type ) {
00691     switch ( type ) {
00692     case Brief:  return brief();
00693     case Plain:  return plain();
00694     case Fancy:   return fancy();
00695     }
00696     kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
00697                     << (int)type << " ) requested!" << endl;
00698     return 0; // make compiler happy
00699   }
00700 
00701   const HeaderStyle * HeaderStyle::create( const QString & type ) {
00702     QString lowerType = type.lower();
00703     if ( lowerType == "brief" ) return brief();
00704     if ( lowerType == "plain" )  return plain();
00705     //if ( lowerType == "fancy" ) return fancy(); // not needed, see below
00706     // don't kdFatal here, b/c the strings are user-provided
00707     // (KConfig), so fail gracefully to the default:
00708     return fancy();
00709   }
00710 
00711   static const HeaderStyle * briefStyle = 0;
00712   static const HeaderStyle * plainStyle = 0;
00713   static const HeaderStyle * fancyStyle = 0;
00714 
00715   const HeaderStyle * HeaderStyle::brief() {
00716     if ( !briefStyle )
00717       briefStyle = new BriefHeaderStyle();
00718     return briefStyle;
00719   }
00720 
00721   const HeaderStyle * HeaderStyle::plain() {
00722     if ( !plainStyle )
00723       plainStyle = new PlainHeaderStyle();
00724     return plainStyle;
00725   }
00726 
00727   const HeaderStyle * HeaderStyle::fancy() {
00728     if ( !fancyStyle )
00729       fancyStyle = new FancyHeaderStyle();
00730     return fancyStyle;
00731   }
00732 
00733 } // namespace KMail
KDE Home | KDE Accessibility Home | Description of Access Keys