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 TQt library by Trolltech AS, Norway (or with modified versions
00023     of TQt that use the same license as TQt), 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     TQt.  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 <libtdepim/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 <tdelocale.h>
00055 #include <tdeglobal.h>
00056 #include <tdeimproxy.h>
00057 #include <tdeabc/stdaddressbook.h>
00058 #include <tdeabc/addresseelist.h>
00059 #include <kmdcodec.h>
00060 #include <tqdatetime.h>
00061 #include <tqbuffer.h>
00062 #include <tqbitmap.h>
00063 #include <tqimage.h>
00064 #include <tqapplication.h>
00065 #include <tqregexp.h>
00066 
00067 #include <kstandarddirs.h>
00068 
00069 namespace KMail {
00070 
00071   //
00072   // Convenience functions:
00073   //
00074   static inline TQString directionOf( const TQString & str ) {
00075     return str.isRightToLeft() ? "rtl" : "ltr" ;
00076   }
00077 
00078 #if 0
00079   // Converts to html. Changes URLs into href's, escapes HTML special
00080   // chars and inserts the result into an <div> or <span> tag with
00081   // "dir" set to "rtl" or "ltr" depending on the direction of @p str.
00082   static TQString convertToHtmlBlock( const TQString & str, bool useSpan=false ) {
00083     TQString dir = directionOf( str );
00084     TQString format = "<%1 dir=\"%3\">%4</%2>";
00085     return format.arg( useSpan ? "span" : "div" )
00086                  .arg( useSpan ? "span" : "div" )
00087                  .arg( dir )
00088                  .arg( LinkLocator::convertToHtml( str ) );
00089   }
00090 #endif
00091 
00092   // ### tmp wrapper to make kmreaderwin code working:
00093   static TQString strToHtml( const TQString & str,
00094                             int flags = LinkLocator::PreserveSpaces ) {
00095     return LinkLocator::convertToHtml( str, flags );
00096   }
00097 
00098   //
00099   // BriefHeaderStyle
00100   //   Show everything in a single line, don't show header field names.
00101   //
00102 
00103   class BriefHeaderStyle : public HeaderStyle {
00104     friend class ::KMail::HeaderStyle;
00105   protected:
00106     BriefHeaderStyle() : HeaderStyle() {}
00107     virtual ~BriefHeaderStyle() {}
00108 
00109   public:
00110     const char * name() const { return "brief"; }
00111     const HeaderStyle * next() const { return plain(); }
00112     const HeaderStyle * prev() const { return fancy(); }
00113 
00114     TQString format( const KMMessage * message, const HeaderStrategy * strategy,
00115                     const TQString & vCardName, bool printing, bool topLevel ) const;
00116   };
00117 
00118   TQString BriefHeaderStyle::format( const KMMessage * message,
00119                                     const HeaderStrategy * strategy,
00120                                     const TQString & vCardName, bool printing, bool topLevel ) const {
00121     Q_UNUSED( topLevel );
00122     if ( !message ) return TQString();
00123     if ( !strategy )
00124       strategy = HeaderStrategy::brief();
00125 
00126     // The direction of the header is determined according to the direction
00127     // of the application layout.
00128 
00129     TQString dir = TQApplication::reverseLayout() ? "rtl" : "ltr" ;
00130 
00131     // However, the direction of the message subject within the header is
00132     // determined according to the contents of the subject itself. Since
00133     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00134     // considered left-to-right, they are ignored when determining its
00135     // direction.
00136 
00137     TQString subjectDir;
00138     if (!message->subject().isEmpty())
00139       subjectDir = directionOf( message->cleanSubject() );
00140     else
00141       subjectDir = directionOf( i18n("No Subject") );
00142 
00143     // Prepare the date string (when printing always use the localized date)
00144     TQString dateString;
00145     if( printing ) {
00146       TQDateTime dateTime;
00147       TDELocale * locale = TDEGlobal::locale();
00148       dateTime.setTime_t( message->date() );
00149       dateString = locale->formatDateTime( dateTime );
00150     } else {
00151       dateString = message->dateStr();
00152     }
00153 
00154     TQString headerStr = "<div class=\"header\" dir=\"" + dir + "\">\n";
00155 
00156     if ( strategy->showHeader( "subject" ) )
00157       headerStr += "<div dir=\"" + subjectDir + "\">\n"
00158                    "<b style=\"font-size:130%\">" +
00159                            strToHtml( message->subject() ) +
00160                            "</b></div>\n";
00161 
00162     TQStringList headerParts;
00163 
00164     if ( strategy->showHeader( "from" ) ) {
00165       TQString fromStr = message->from();
00166       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00167         fromStr = message->fromStrip(); // let's use that
00168       TQString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true );
00169       if ( !vCardName.isEmpty() )
00170         fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\">" + i18n("[vCard]") + "</a>";
00171       headerParts << fromPart;
00172     }
00173 
00174     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00175       headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true );
00176 
00177     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00178       headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true );
00179 
00180     if ( strategy->showHeader( "date" ) )
00181       headerParts << strToHtml(message->dateShortStr());
00182 
00183     // remove all empty (modulo whitespace) entries and joins them via ", \n"
00184     headerStr += " (" + headerParts.grep( TQRegExp( "\\S" ) ).join( ",\n" ) + ')';
00185 
00186     headerStr += "</div>\n";
00187 
00188     // ### iterate over the rest of strategy->headerToDisplay() (or
00189     // ### all headers if DefaultPolicy == Display) (elsewhere, too)
00190     return headerStr;
00191   }
00192 
00193   //
00194   // PlainHeaderStyle:
00195   //   show every header field on a line by itself,
00196   //   show subject larger
00197   //
00198 
00199   class PlainHeaderStyle : public HeaderStyle {
00200     friend class ::KMail::HeaderStyle;
00201   protected:
00202     PlainHeaderStyle() : HeaderStyle() {}
00203     virtual ~PlainHeaderStyle() {}
00204 
00205   public:
00206     const char * name() const { return "plain"; }
00207     const HeaderStyle * next() const { return fancy(); }
00208     const HeaderStyle * prev() const { return brief(); }
00209 
00210     TQString format( const KMMessage * message, const HeaderStrategy * strategy,
00211                     const TQString & vCardName, bool printing, bool topLevel ) const;
00212 
00213   private:
00214     TQString formatAllMessageHeaders( const KMMessage * message ) const;
00215   };
00216 
00217   TQString PlainHeaderStyle::format( const KMMessage * message,
00218                                     const HeaderStrategy * strategy,
00219                                     const TQString & vCardName, bool printing, bool topLevel ) const {
00220     Q_UNUSED( topLevel );
00221     if ( !message ) return TQString();
00222     if ( !strategy )
00223       strategy = HeaderStrategy::rich();
00224 
00225     // The direction of the header is determined according to the direction
00226     // of the application layout.
00227 
00228     TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
00229 
00230     // However, the direction of the message subject within the header is
00231     // determined according to the contents of the subject itself. Since
00232     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00233     // considered left-to-right, they are ignored when determining its
00234     // direction.
00235 
00236     TQString subjectDir;
00237     if (!message->subject().isEmpty())
00238       subjectDir = directionOf( message->cleanSubject() );
00239     else
00240       subjectDir = directionOf( i18n("No Subject") );
00241 
00242     // Prepare the date string (when printing always use the localized date)
00243     TQString dateString;
00244     if( printing ) {
00245       TQDateTime dateTime;
00246       TDELocale* locale = TDEGlobal::locale();
00247       dateTime.setTime_t( message->date() );
00248       dateString = locale->formatDateTime( dateTime );
00249     }
00250     else {
00251       dateString = message->dateStr();
00252     }
00253 
00254     TQString headerStr;
00255 
00256     if ( strategy->headersToDisplay().isEmpty()
00257          && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00258       // crude way to emulate "all" headers - Note: no strings have
00259       // i18n(), so direction should always be ltr.
00260       headerStr= TQString("<div class=\"header\" dir=\"ltr\">");
00261       headerStr += formatAllMessageHeaders( message );
00262       return headerStr + "</div>";
00263     }
00264 
00265     headerStr = TQString("<div class=\"header\" dir=\"%1\">").arg(dir);
00266 
00267     //case HdrLong:
00268     if ( strategy->showHeader( "subject" ) )
00269       headerStr += TQString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
00270                            strToHtml(message->subject()) + "</b></div>\n")
00271                         .arg(subjectDir);
00272 
00273     if ( strategy->showHeader( "date" ) )
00274       headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
00275 
00276 #if 0
00277     // Get Instant Messaging presence
00278     TQString presence;
00279     TQString tdeabcUid;
00280     if ( strategy->showHeader( "status" ) )
00281     {
00282       TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
00283       TDEABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00284       ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00285       tdeabcUid = addresses[0].uid();
00286       presence = imProxy->presenceString( tdeabcUid );
00287     }
00288 #endif
00289 
00290     if ( strategy->showHeader( "from" ) ) {
00291       TQString fromStr = message->from();
00292       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00293         fromStr = message->fromStrip(); // let's use that
00294       headerStr.append(i18n("From: ") +
00295           KMMessage::emailAddrAsAnchor( fromStr, false, "", true ) );
00296       if ( !vCardName.isEmpty() )
00297         headerStr.append("&nbsp;&nbsp;<a href=\"" + vCardName +
00298               "\">" + i18n("[vCard]") + "</a>" );
00299 #if 0
00300       if ( !presence.isEmpty() && strategy->showHeader( "status" ) )
00301         headerStr.append("&nbsp;&nbsp;(<span name=\"presence-" + tdeabcUid + "\">" + presence + "</span>)" );
00302 #endif
00303 
00304       if ( strategy->showHeader( "organization" )
00305           && !message->headerField("Organization").isEmpty())
00306         headerStr.append("&nbsp;&nbsp;(" +
00307               strToHtml(message->headerField("Organization")) + ")");
00308       headerStr.append("<br>\n");
00309     }
00310 
00311     if ( strategy->showHeader( "to" ) )
00312       headerStr.append(i18n("To: ")+
00313                        KMMessage::emailAddrAsAnchor(message->to(),false) + "<br>\n");
00314 
00315     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00316       headerStr.append(i18n("CC: ")+
00317                        KMMessage::emailAddrAsAnchor(message->cc(),false) + "<br>\n");
00318 
00319     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
00320       headerStr.append(i18n("BCC: ")+
00321                        KMMessage::emailAddrAsAnchor(message->bcc(),false) + "<br>\n");
00322 
00323     if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
00324       headerStr.append(i18n("Reply to: ")+
00325                      KMMessage::emailAddrAsAnchor(message->replyTo(),false) + "<br>\n");
00326 
00327     headerStr += "</div>\n";
00328 
00329     return headerStr;
00330   }
00331 
00332   TQString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
00333     const DwHeaders & headers = message->headers();
00334     TQString result;
00335 
00336     for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00337       result += ( field->FieldNameStr() + ": " ).c_str();
00338       result += strToHtml( field->FieldBodyStr().c_str() );
00339       result += "<br>\n";
00340     }
00341 
00342     return result;
00343   }
00344 
00345   //
00346   // FancyHeaderStyle:
00347   //   Like PlainHeaderStyle, but with slick frames and background colours.
00348   //
00349 
00350   class FancyHeaderStyle : public HeaderStyle {
00351     friend class ::KMail::HeaderStyle;
00352   protected:
00353     FancyHeaderStyle() : HeaderStyle() {}
00354     virtual ~FancyHeaderStyle() {}
00355 
00356   public:
00357     const char * name() const { return "fancy"; }
00358     const HeaderStyle * next() const { return enterprise(); }
00359     const HeaderStyle * prev() const { return plain(); }
00360 
00361     TQString format( const KMMessage * message, const HeaderStrategy * strategy,
00362                     const TQString & vCardName, bool printing, bool topLevel ) const;
00363     static TQString imgToDataUrl( const TQImage & image,
00364                                  const char *fmt = "PNG" );
00365 
00366   private:
00367     static TQString drawSpamMeter( double percent, const TQString & filterHeader );
00368 
00369   };
00370 
00371   TQString FancyHeaderStyle::drawSpamMeter( double percent,
00372                                            const TQString & filterHeader )
00373   {
00374     TQImage meterBar( 20, 1, 8, 24 );
00375     const unsigned short gradient[20][3] = {
00376       {   0, 255,   0 },
00377       {  27, 254,   0 },
00378       {  54, 252,   0 },
00379       {  80, 250,   0 },
00380       { 107, 249,   0 },
00381       { 135, 247,   0 },
00382       { 161, 246,   0 },
00383       { 187, 244,   0 },
00384       { 214, 242,   0 },
00385       { 241, 241,   0 },
00386       { 255, 228,   0 },
00387       { 255, 202,   0 },
00388       { 255, 177,   0 },
00389       { 255, 151,   0 },
00390       { 255, 126,   0 },
00391       { 255, 101,   0 },
00392       { 255,  76,   0 },
00393       { 255,  51,   0 },
00394       { 255,  25,   0 },
00395       { 255,   0,   0 }
00396     };
00397     meterBar.setColor( 21, tqRgb( 255, 255, 255 ) );
00398     meterBar.setColor( 22, tqRgb( 170, 170, 170 ) );
00399     if ( percent < 0 ) // grey is for errors
00400       meterBar.fill( 22 );
00401     else {
00402       meterBar.fill( 21 );
00403       int max = TQMIN( 20, static_cast<int>( percent ) / 5 );
00404       for ( int i = 0; i < max; ++i ) {
00405         meterBar.setColor( i+1, tqRgb( gradient[i][0], gradient[i][1],
00406                                       gradient[i][2] ) );
00407         meterBar.setPixel( i, 0, i+1 );
00408       }
00409     }
00410     TQString titleText = i18n("%1% probability of being spam.\n\nFull report:\n%2")
00411                      .arg( TQString::number( percent ), filterHeader );
00412     return TQString("<img src=\"%1\" width=\"%2\" height=\"%3\" style=\"border: 1px solid black;\" title=\"%4\"> &nbsp;")
00413       .arg( imgToDataUrl( meterBar, "PPM" ), TQString::number( 20 ),
00414             TQString::number( 5 ), titleText );
00415   }
00416 
00417 
00418   TQString FancyHeaderStyle::format( const KMMessage * message,
00419                                     const HeaderStrategy * strategy,
00420                                     const TQString & vCardName, bool printing, bool topLevel ) const {
00421     Q_UNUSED( topLevel );
00422     if ( !message ) return TQString();
00423     if ( !strategy )
00424       strategy = HeaderStrategy::rich();
00425 
00426     TDEConfigGroup configReader( KMKernel::config(), "Reader" );
00427 
00428     // ### from kmreaderwin begin
00429     // The direction of the header is determined according to the direction
00430     // of the application layout.
00431 
00432     TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
00433     TQString headerStr = TQString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00434 
00435     // However, the direction of the message subject within the header is
00436     // determined according to the contents of the subject itself. Since
00437     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00438     // considered left-to-right, they are ignored when determining its
00439     // direction.
00440 
00441     TQString subjectDir;
00442     if ( !message->subject().isEmpty() )
00443       subjectDir = directionOf( message->cleanSubject() );
00444     else
00445       subjectDir = directionOf( i18n("No Subject") );
00446 
00447     // Prepare the date string (when printing always use the localized date)
00448     TQString dateString;
00449     if( printing ) {
00450       TQDateTime dateTime;
00451       TDELocale* locale = TDEGlobal::locale();
00452       dateTime.setTime_t( message->date() );
00453       dateString = locale->formatDateTime( dateTime );
00454     }
00455     else {
00456       dateString = message->dateStr();
00457     }
00458 
00459     // Spam header display.
00460     // If the spamSpamStatus config value is true then we look for headers
00461     // from a few spam filters and try to create visually meaningful graphics
00462     // out of the spam scores.
00463 
00464     TQString spamHTML;
00465 
00466     if ( configReader.readBoolEntry( "showSpamStatus", true ) ) {
00467       SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message );
00468       for ( SpamScoresIterator it = scores.begin(); it != scores.end(); ++it )
00469         spamHTML += (*it).agent() + " " +
00470                     drawSpamMeter( (*it).score(), (*it).spamHeader() );
00471     }
00472 
00473     TQString userHTML;
00474     TQString presence;
00475 
00476     // IM presence and tdeabc photo
00477 
00478     ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00479     TQString tdeabcUid;
00480     TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
00481     TDEABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00482 
00483     TQString photoURL;
00484     int photoWidth = 60;
00485     int photoHeight = 60;
00486     if( addresses.count() == 1 )
00487     {
00488       // tdeabcUid is embedded in im: URIs to indicate which IM contact to message
00489       tdeabcUid = addresses[0].uid();
00490 
00491       if ( imProxy->initialize() ) {
00492           // im status
00493           presence = imProxy->presenceString( tdeabcUid );
00494           if ( !presence.isEmpty() )
00495           {
00496             TQString presenceIcon = TQString::fromLatin1( " <img src=\"%1\"/>" )
00497                 .arg( imgToDataUrl( imProxy->presenceIcon( tdeabcUid ).convertToImage() ) );
00498             presence += presenceIcon;
00499           }
00500       }
00501       // picture
00502       if ( addresses[0].photo().isIntern() )
00503       {
00504         // get photo data and convert to data: url
00505         //kdDebug( 5006 ) << "INTERNAL photo found" << endl;
00506         TQImage photo = addresses[0].photo().data();
00507         if ( !photo.isNull() )
00508         {
00509           photoWidth = photo.width();
00510           photoHeight = photo.height();
00511           // scale below 60, otherwise it can get way too large
00512           if ( photoHeight > 60 ) {
00513             double ratio = ( double )photoHeight / ( double )photoWidth;
00514             photoHeight = 60;
00515             photoWidth = (int)( 60 / ratio );
00516             photo = photo.smoothScale( photoWidth, photoHeight );
00517           }
00518           photoURL = imgToDataUrl( photo );
00519         }
00520       }
00521       else
00522       {
00523         //kdDebug( 5006 ) << "URL found" << endl;
00524         photoURL = addresses[0].photo().url();
00525         if ( photoURL.startsWith("/") )
00526           photoURL.prepend( "file:" );
00527       }
00528     }
00529     else // TODO: find a usable one
00530     {
00531       kdDebug( 5006 ) << "Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
00532       userHTML = "&nbsp;";
00533     }
00534 
00535     if( photoURL.isEmpty() ) {
00536       // no photo, look for a Face header
00537       TQString faceheader = message->headerField( "Face" );
00538       if ( !faceheader.isEmpty() ) {
00539         TQImage faceimage;
00540 
00541         kdDebug( 5006 ) << "Found Face: header" << endl;
00542 
00543         TQCString facestring = faceheader.utf8();
00544         // Spec says header should be less than 998 bytes
00545         // Face: is 5 characters
00546         if ( facestring.length() < 993 ) {
00547           TQByteArray facearray;
00548           KCodecs::base64Decode(facestring, facearray);
00549 
00550           TQImage faceimage;
00551           if ( faceimage.loadFromData( facearray, "png" ) ) {
00552             // Spec says image must be 48x48 pixels
00553             if ( (48 == faceimage.width()) && (48 == faceimage.height()) ) {
00554               photoURL = imgToDataUrl( faceimage );
00555               photoWidth = 48;
00556               photoHeight = 48;
00557             } else {
00558               kdDebug( 5006 ) << "Face: header image is" << faceimage.width() << "by" << faceimage.height() <<"not 48x48 Pixels" << endl;
00559             }
00560           } else {
00561             kdDebug( 5006 ) << "Failed to load decoded png from Face: header" << endl;
00562           }
00563         } else {
00564           kdDebug( 5006 ) << "Face: header too long at " << facestring.length() << endl;
00565         }
00566       }
00567     }
00568 
00569     if( photoURL.isEmpty() )
00570     {
00571       // no photo, look for a X-Face header
00572       TQString xfaceURL;
00573       TQString xfhead = message->headerField( "X-Face" );
00574       if ( !xfhead.isEmpty() )
00575       {
00576         KXFace xf;
00577         photoURL = imgToDataUrl( xf.toImage( xfhead ) );
00578         photoWidth = 48;
00579         photoHeight = 48;
00580 
00581       }
00582     }
00583 
00584     if( !photoURL.isEmpty() )
00585     {
00586         //kdDebug( 5006 ) << "Got a photo: " << photoURL << endl;
00587       userHTML = TQString("<img src=\"%1\" width=\"%2\" height=\"%3\">")
00588           .arg( photoURL ).arg( photoWidth ).arg( photoHeight );
00589       if ( presence.isEmpty() ) {
00590         userHTML = TQString("<div class=\"senderpic\">") + userHTML + "</div>";
00591       } else {
00592         userHTML = TQString( "<div class=\"senderpic\">"
00593             "<a href=\"im:%1\">%2<div class=\"senderstatus\">"
00594             "<span name=\"presence-%3\">%4</span></div></a>"
00595             "</div>" ).arg( tdeabcUid )
00596             .arg( userHTML )
00597              .arg( tdeabcUid )
00598             .arg( presence );
00599       }
00600     } else {
00601        // we don't have a photo, just show presence, if we have it
00602       if ( !presence.isEmpty() )
00603         userHTML = TQString( "<a href=\"im:%1\"><div class=\"senderstatus\">"
00604             "<span name=\"presence-%2\">%3</span></div></a>" )
00605             .arg( tdeabcUid )
00606             .arg( tdeabcUid )
00607             .arg( presence );
00608     }
00609 #if 0
00610     // Disabled 'Launch IM' link in headers - Will
00611     if ( imProxy->imAppsAvailable() )
00612       presence = "<a name=\"launchim\" href=\"kmail:startIMApp\">" + i18n("Launch IM") + "</a></span>";
00613     // do nothing - no im apps available, leave presence empty
00614     //presence = i18n( "DCOP/InstantMessenger not installed" );
00615     kdDebug( 5006 ) << "final presence: '" << presence << "'" << endl;
00616 #endif
00617 
00618     TQString timeHTML;
00619     if ( GlobalSettings::self()->showCurrentTime() && strategy->showHeader( "date" ) ) {
00620       DwHeaders& header = message->headers();
00621       if ( header.HasDate() ) {
00622                 DwDateTime& origDate = header.Date();
00623                 int zone = origDate.Zone();
00624                 // kdDebug() << "FancyHeaderStyle::format() zone offset (in minutes): " << zone << endl;
00625                 
00626                 // copyed from mimelib -- code to determine local timezone
00627         time_t t_now = time((time_t*) 0);
00628 #if defined(HAVE_GMTIME_R)
00629         struct tm utc;
00630         gmtime_r(&t_now, &utc);
00631         struct tm local;
00632         localtime_r(&t_now, &local);
00633 #else
00634         struct tm utc = *gmtime(&t_now);
00635         struct tm local = *localtime(&t_now);
00636 #endif
00637         DwUint32 t_local = 0;
00638         t_local = 24 * t_local + local.tm_hour;
00639         t_local = 60 * t_local + local.tm_min;
00640         t_local = 60 * t_local + local.tm_sec;
00641         DwUint32 t_utc = 0;
00642         t_utc = 24 * t_utc + utc.tm_hour;
00643         t_utc = 60 * t_utc + utc.tm_min;
00644         t_utc = 60 * t_utc + utc.tm_sec;
00645                 
00646                 // kdDebug() << "FancyHeaderStyle::format() local zone offset (in minutes): " << lzone << endl;
00647                 
00648                 TQTime currTime = TQTime::currentTime( Qt::UTC );
00649                 
00650                 // kdDebug() << "FancyHeaderStyle::format() current time: " << currTime << endl;
00651                 
00652                 // now currTime contain message sender local time
00653                 currTime = currTime.addSecs( zone * 60 );
00654                 
00655                 TQString timeofday;
00656                 TQString color;
00657                 TQString bg_color;
00658                 TQString bg_image;
00659                 if ( currTime > TQTime( 0, 0, 0 ) && currTime <= TQTime( 6, 0, 0 ) ) {
00660                   timeofday = i18n( "Night" );
00661                   color = "white";
00662                   bg_color = "#000B6B";
00663                   bg_image = "url(data:image/png;base64,"
00664                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAIAAAASmSbdAAAAS0lEQVQI11WOsRGAQAzDOG/LHoz9"
00665                     "kikIcF+kSBxbPs7LoNGVapAI0Zn+O+8NUwldozn6io7G7kdS/5zi7i+BvUM/5uSXlIfzMHx/bmWR"
00666                     "k++yj9rZAAAAAElFTkSuQmCC)";
00667                 }
00668                 else if ( currTime > TQTime( 6, 0, 0 ) && currTime <= TQTime( 12, 0, 0 ) ) {
00669                   timeofday = i18n( "Morning" );
00670                   color = "black";
00671                   bg_color = "#00A6FF";
00672                   bg_image = "url(data:image/png;base64,"
00673                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAWklEQVQI122OQQ7DMAzDaP3/dfuO"
00674                     "pWSHJgva7iZIBk3m/Ew5hexCHVCilewzFHKEbFZqgxJQWyzKhWKl9unqddJj8+L9sl0oR2gUim+o"
00675                     "zu4uSh7kn67/DNv+C4tsZOtjAWEHAAAAAElFTkSuQmCC)";
00676                 }
00677                 else if ( currTime > TQTime( 12, 0, 0 ) && currTime <= TQTime( 18, 0, 0 ) ) {
00678                   timeofday = i18n( "Afternoon" );
00679                   color = "black";
00680                   bg_color = "#00A6FF";
00681                   bg_image = "url(data:image/png;base64,"
00682                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAPUlEQVQI132OwQ0AIAwCSfcfw91c"
00683                     "QsCfRm399HFwoWjdDhMICQhxHSWMQPhkTCoqWRZU2h5i9tr4GZfmV5t3wWUI3h+NugAAAABJRU5E"
00684                     "rkJggg==)";
00685                 }
00686                 else {
00687                   timeofday = i18n( "Evening" );
00688                   color = "white";
00689                   bg_color = "#0014CC";
00690                   bg_image = "url(data:image/png;base64,"
00691                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAWklEQVQI11WOyRHAMAgDNQuUlBrS"
00692                     "fyFpAfKwje0PwyEt0vN+hVsJpzS6QML2ziWcFI6mZBZNSVDXYehyUgI1XsLI9eimHDH6kW0ddVIO"
00693                     "xx7JjrtshlbXlLDSD+WhJ+hwqWo8AAAAAElFTkSuQmCC)";
00694                 }
00695                 
00696                 TQString tformat;
00697                 if ( TDEGlobal::locale()->use12Clock() ) {
00698                   tformat = "h:mm AP";
00699                 }
00700                 else {
00701                   tformat = "h:mm";
00702                 }
00703                 
00704                 // kdDebug() << "FancyHeaderStyle::format() current time: " << currTime << " (" << timeofday << ")" << endl;
00705                 
00706                 timeHTML.append( TQString(
00707                   "<div id=\"sendersCurrentTime\" style=\""
00708                   "border:1px solid %1;"
00709                   "color:%2;"
00710                   "background-image:%3;"
00711                   "background-position:center left;"
00712                   "background-repeat:repeat-x;"
00713                   "text-align:center;"
00714                   "font-size:12px;"
00715                   "padding:2px;"
00716                   "width:150px;"
00717                   "height:45px;"
00718                   "margin: 0px 0px 3px 0px;"
00719                   "\" class=\"curtime\">%4<br />%5<br />%6</div>"
00720                   )
00721                   .arg( bg_color )
00722                   .arg( color )
00723                   .arg( bg_image )
00724                   .arg( i18n( "Sender's Current Time:" ) )
00725                   .arg( currTime.toString( tformat ) )
00726                   .arg( timeofday )
00727                   );
00728             }
00729             else {
00730               // kdDebug() << "FancyHeaderStyle::format() no date header to display" << endl;
00731             }
00732     }
00733 
00734     //case HdrFancy:
00735     // the subject line and box below for details
00736     if ( strategy->showHeader( "subject" ) ) {
00737       const int flags = LinkLocator::PreserveSpaces |
00738                         ( GlobalSettings::self()->showEmoticons() ?
00739                           LinkLocator::ReplaceSmileys : 0 );
00740       headerStr += TQString("<div dir=\"%1\">%2</div>\n")
00741                         .arg(subjectDir)
00742                         .arg(message->subject().isEmpty()?
00743                              i18n("No Subject") :
00744                              strToHtml( message->subject(), flags ));
00745     }
00746     headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00747     //headerStr += "<table>\n";
00748     // from line
00749     // the mailto: URLs can contain %3 etc., therefore usage of multiple
00750     // TQString::arg is not possible
00751     if ( strategy->showHeader( "from" ) ) {
00752       TQString fromStr = message->from();
00753       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00754         fromStr = message->fromStrip(); // let's use that
00755       headerStr += TQString("<tr><th>%1</th>\n"
00756                            "<td>")
00757                            .arg(i18n("From: "))
00758                  + KMMessage::emailAddrAsAnchor( fromStr, false )
00759                  + ( !message->headerField( "Resent-From" ).isEmpty() ? "&nbsp;"
00760                                 + i18n("(resent from %1)")
00761                                   .arg( KMMessage::emailAddrAsAnchor(
00762                                     message->headerField( "Resent-From" ),false) )
00763                               : TQString("") )
00764                  + ( !vCardName.isEmpty() ? "&nbsp;&nbsp;<a href=\"" + vCardName + "\">"
00765                                 + i18n("[vCard]") + "</a>"
00766                               : TQString("") )
00767 #if 0
00768                  + ( ( !presence.isEmpty() )
00769                               ? "&nbsp;&nbsp;(<span name=\"presence-" + tdeabcUid + "\">" + presence + "</span>)"
00770                               : TQString("") )
00771 #endif
00772                  + ( message->headerField("Organization").isEmpty()
00773                               ? TQString("")
00774                               : "&nbsp;&nbsp;("
00775                                 + strToHtml(message->headerField("Organization"))
00776                                 + ")")
00777                  + "</td></tr>\n";
00778     }
00779     // to line
00780     if ( strategy->showHeader( "to" ) )
00781       headerStr.append(TQString("<tr><th>%1</th>\n"
00782                                "<td>%2</td></tr>\n")
00783                        .arg(i18n("To: "))
00784                        .arg(KMMessage::emailAddrAsAnchor(message->to(),false)));
00785 
00786     // cc line, if any
00787     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00788       headerStr.append(TQString("<tr><th>%1</th>\n"
00789                                "<td>%2</td></tr>\n")
00790                        .arg(i18n("CC: "))
00791                        .arg(KMMessage::emailAddrAsAnchor(message->cc(),false)));
00792 
00793     // Bcc line, if any
00794     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00795       headerStr.append(TQString("<tr><th>%1</th>\n"
00796                                "<td>%2</td></tr>\n")
00797                        .arg(i18n("BCC: "))
00798                        .arg(KMMessage::emailAddrAsAnchor(message->bcc(),false)));
00799 
00800     if ( strategy->showHeader( "date" ) )
00801       headerStr.append(TQString("<tr><th>%1</th>\n"
00802                                "<td dir=\"%2\">%3</td></tr>\n")
00803                        .arg(i18n("Date: "))
00804                        .arg( directionOf( message->dateStr() ) )
00805                        .arg(strToHtml(dateString)));
00806 
00807     if ( GlobalSettings::self()->showUserAgent() ) {
00808       if ( strategy->showHeader( "user-agent" ) ) {
00809         if ( !message->headerField("User-Agent").isEmpty() ) {
00810           headerStr.append(TQString("<tr><th>%1</th>\n"
00811                                    "<td>%2</td></tr>\n")
00812                            .arg(i18n("User-Agent: "))
00813                            .arg( strToHtml( message->headerField("User-Agent") ) ) );
00814         }
00815       }
00816 
00817       if ( strategy->showHeader( "x-mailer" ) ) {
00818         if ( !message->headerField("X-Mailer").isEmpty() ) {
00819           headerStr.append(TQString("<tr><th>%1</th>\n"
00820                                    "<td>%2</td></tr>\n")
00821                            .arg(i18n("X-Mailer: "))
00822                            .arg( strToHtml( message->headerField("X-Mailer") ) ) );
00823         }
00824       }
00825     }
00826 
00827     // FIXME: Show status in synthetic header style field.  Decide whether this or current in brackets style is best and remove one.
00828     /*    if( strategy->showHeader( "status" ) )
00829       headerStr.append( TQString( "<tr><th>%1</th>\n"
00830                                  "<td dir=\"%2\">%3</td></tr>\n")
00831                                     .arg(i18n("Sender status: "))
00832                                     .arg( directionOf( onlineStatus ) )
00833                                     .arg(onlineStatus));
00834     */
00835     headerStr.append( TQString("<tr><td colspan=\"2\"><div id=\"attachmentInjectionPoint\"></div></td></tr>" ) );
00836     headerStr.append(
00837           TQString( "</table></td><td align=\"center\" valign=\"top\">%1%2</td></tr></table>\n" )
00838           .arg(timeHTML)
00839           .arg(userHTML) );
00840 
00841     if ( !spamHTML.isEmpty() )
00842       headerStr.append( TQString( "<div class=\"spamheader\" dir=\"%1\"><b>%2</b>&nbsp;<span style=\"padding-left: 20px;\">%3</span></div>\n")
00843                         .arg( subjectDir, i18n("Spam Status:"), spamHTML ) );
00844 
00845     headerStr += "</div>\n\n";
00846     return headerStr;
00847   }
00848 
00849   TQString FancyHeaderStyle::imgToDataUrl( const TQImage &image, const char* fmt  )
00850   {
00851     TQByteArray ba;
00852     TQBuffer buffer( ba );
00853     buffer.open( IO_WriteOnly );
00854     image.save( &buffer, fmt );
00855     return TQString::fromLatin1("data:image/%1;base64,%2")
00856            .arg( fmt, KCodecs::base64Encode( ba ).data() );
00857   }
00858 
00859 // #####################
00860 
00861   class EnterpriseHeaderStyle : public HeaderStyle {
00862     friend class ::KMail::HeaderStyle;
00863   protected:
00864     EnterpriseHeaderStyle() : HeaderStyle() {}
00865     virtual ~EnterpriseHeaderStyle() {}
00866 
00867   public:
00868     const char * name() const { return "enterprise"; }
00869     const HeaderStyle * next() const { return brief(); }
00870     const HeaderStyle * prev() const { return fancy(); }
00871 
00872     TQString format( const KMMessage * message, const HeaderStrategy * strategy,
00873                     const TQString & vCardName, bool printing, bool topLevel ) const;
00874   };
00875 
00876     TQString EnterpriseHeaderStyle::format( const KMMessage * message,
00877                                     const HeaderStrategy * strategy,
00878                                     const TQString & vCardName, bool printing, bool topLevel ) const {
00879     if ( !message ) return TQString();
00880     if ( !strategy )
00881         strategy = HeaderStrategy::brief();
00882 
00883     // The direction of the header is determined according to the direction
00884     // of the application layout.
00885 
00886     TQString dir = TQApplication::reverseLayout() ? "rtl" : "ltr" ;
00887 
00888     // However, the direction of the message subject within the header is
00889     // determined according to the contents of the subject itself. Since
00890     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00891     // considered left-to-right, they are ignored when determining its
00892     // direction.
00893 
00894     TQString subjectDir;
00895     if (!message->subject().isEmpty())
00896         subjectDir = directionOf( message->cleanSubject() );
00897     else
00898         subjectDir = directionOf( i18n("No Subject") );
00899 
00900     // colors depend on if its encapsulated or not
00901         TQColor fontColor(TQt::white);
00902     TQString linkColor = "class =\"white\"";
00903     const TQColor activeColor = tqApp->palette().active().highlight();
00904     TQColor activeColorDark = activeColor.dark(130);
00905         // reverse colors for encapsulated
00906         if( !topLevel ){
00907             activeColorDark = activeColor.dark(50);
00908             fontColor = TQColor(TQt::black);
00909         linkColor = "class =\"black\"";
00910         }
00911 
00912     // Prepare the date string (when printing always use the localized date)
00913     TQString dateString;
00914     if( printing ) {
00915         TQDateTime dateTime;
00916         TDELocale * locale = TDEGlobal::locale();
00917         dateTime.setTime_t( message->date() );
00918         dateString = locale->formatDateTime( dateTime );
00919     } else {
00920         dateString = message->dateStr();
00921     }
00922 
00923     TQString imgpath(locate("data","kmail/pics/"));
00924     imgpath.append("enterprise_");
00925     const TQString borderSettings(" padding-top: 0px; padding-bottom: 0px; border-width: 0px ");
00926     TQString headerStr ("");
00927 
00928     // 3D borders
00929     if(topLevel)
00930         headerStr +=
00931         "<div style=\"position: fixed; top: 0px; left: 0px; background-color: #606060; "
00932         "width: 10px; min-height: 100%;\">&nbsp;</div>"
00933         "<div style=\"position: fixed; top: 0px; right: 0px;  background-color: #606060; "
00934         "width: 10px; min-height: 100%;\">&nbsp;</div>";
00935 
00936     headerStr += ""
00937         "<div style=\"margin-left: 10px; top: 0px;\"><span style=\"font-size: 10px; font-weight: bold;\">"+dateString+"</span></div>"
00938         // #0057ae
00939         "<table style=\"background: "+activeColorDark.name()+"; border-collapse:collapse; top: 14px; min-width: 200px; \" cellpadding=0> \n"
00940         "  <tr> \n"
00941         "   <td style=\"min-width: 6px; background-image: url("+imgpath+"top_left.png); \"></td> \n"
00942         "   <td style=\"height: 6px; width: 100%; background: url("+imgpath+"top.png); \"></td> \n"
00943         "   <td style=\"min-width: 6px; background: url("+imgpath+"top_right.png); \"></td> </tr> \n"
00944         "   <tr> \n"
00945         "   <td style=\"min-width: 6px; max-width: 6px; background: url("+imgpath+"left.png); \"></td> \n"
00946         "   <td style=\"\"> \n";
00947 
00948   headerStr +=
00949     "     <div class=\"noprint\" style=\"z-index: 1; float:right; position: relative; top: -35px; right: 20px ;\">\n"
00950     "       <img src=\""+imgpath+"icon.png\">\n"
00951     "     </div>\n";
00952 
00953   headerStr +=
00954     "     <table style=\"color: "+fontColor.name()+" ! important; margin: 1px; border-spacing: 0px;\" cellpadding=0> \n";
00955 
00956     // subject
00957     //strToHtml( message->subject() )
00958     if ( strategy->showHeader( "subject" ) ){
00959         headerStr +=
00960         "     <tr> \n"
00961         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; "+borderSettings+"\"></td> \n"
00962         "      <td style=\"font-weight: bolder; font-size: 120%; padding-right: 91px; "+borderSettings+"\">"+message->subject()+"</td> \n"
00963         "     </tr> \n";
00964     }
00965 
00966     // from
00967     if ( strategy->showHeader( "from" ) ){
00968         TQString fromStr = message->from();
00969         if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00970         fromStr = message->fromStrip(); // let's use that
00971             // TODO vcard
00972         TQString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true, linkColor );
00973         if ( !vCardName.isEmpty() )
00974         fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\" "+linkColor+">" + i18n("[vCard]") + "</a>";
00975         //TODO strategy date
00976         //if ( strategy->showHeader( "date" ) )
00977         headerStr +=
00978         "     <tr> \n"
00979         "      <td style=\"font-size: 6px; padding-left: 5px; padding-right: 24px; text-align: right; "+borderSettings+"\">"+i18n("From: ")+"</td> \n"
00980         "      <td style=\""+borderSettings+"\">"+ fromPart +"</td> "
00981         "     </tr> ";
00982     }
00983 
00984     // to line
00985     if( strategy->showHeader( "to" ) )
00986           headerStr +=
00987         "     <tr> "
00988         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("To: ") + "</td> "
00989         "      <td style=\"" + borderSettings + "\">" +
00990         KMMessage::emailAddrAsAnchor( message->to(), false, linkColor ) +
00991         "      </td> "
00992         "     </tr>\n";
00993 
00994         // cc line, if any
00995     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00996           headerStr +=
00997         "     <tr> "
00998         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("CC: ") + "</td> "
00999         "      <td style=\"" + borderSettings + "\">" +
01000         KMMessage::emailAddrAsAnchor( message->cc(), false, linkColor ) +
01001         "      </td> "
01002         "     </tr>\n";
01003 
01004         // bcc line, if any
01005     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
01006           headerStr +=
01007         "     <tr> "
01008         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("BCC: ") + "</td> "
01009         "      <td style=\"" + borderSettings + "\">" +
01010         KMMessage::emailAddrAsAnchor( message->bcc(), false, linkColor ) +
01011         "      </td> "
01012         "     </tr>\n";
01013 
01014     // header-bottom
01015     headerStr +=
01016         "    </table> \n"
01017         "   </td> \n"
01018         "   <td style=\"min-width: 6px; max-height: 15px; background: url("+imgpath+"right.png); \"></td> \n"
01019         "  </tr> \n"
01020         "  <tr> \n"
01021         "   <td style=\"min-width: 6px; background: url("+imgpath+"s_left.png); \"></td> \n"
01022         "   <td style=\"height: 35px; width: 80%; background: url("+imgpath+"sbar.png);\"> \n"
01023         "    <img src=\""+imgpath+"sw.png\" style=\"margin: 0px; height: 30px; overflow:hidden; \"> \n"
01024         "    <img src=\""+imgpath+"sp_right.png\" style=\"float: right; \"> </td> \n"
01025         "   <td style=\"min-width: 6px; background: url("+imgpath+"s_right.png); \"></td> \n"
01026         "  </tr> \n"
01027         " </table> \n";
01028 
01029     // kmail icon
01030     if(topLevel) {
01031 
01032         // attachments
01033         headerStr +=
01034         "<div class=\"noprint\" style=\"position: absolute; top: 60px; right: 20px; width: 91px; height: 200px;\">"
01035         "<div id=\"attachmentInjectionPoint\"></div>"
01036         "</div>\n";
01037     }
01038 
01039     if ( printing ) {
01040       //provide a bit more left padding when printing
01041       //kolab/issue3254 (printed mail cut at the left side)
01042       headerStr += "<div style=\"padding: 6px; padding-left: 10px;\">";
01043     } else {
01044       headerStr += "<div style=\"padding: 6px;\">";
01045     }
01046 
01047     // TODO
01048     // spam status
01049     // ### iterate over the rest of strategy->headerToDisplay() (or
01050     // ### all headers if DefaultPolicy == Display) (elsewhere, too)
01051     return headerStr;
01052   }
01053 
01054 // #####################
01055 
01056   //
01057   // HeaderStyle abstract base:
01058   //
01059 
01060   HeaderStyle::HeaderStyle() {
01061 
01062   }
01063 
01064   HeaderStyle::~HeaderStyle() {
01065 
01066   }
01067 
01068   const HeaderStyle * HeaderStyle::create( Type type ) {
01069     switch ( type ) {
01070     case Brief:  return brief();
01071     case Plain:  return plain();
01072     case Fancy:   return fancy();
01073     case Enterprise: return enterprise();
01074     }
01075     kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
01076                     << (int)type << " ) requested!" << endl;
01077     return 0; // make compiler happy
01078   }
01079 
01080   const HeaderStyle * HeaderStyle::create( const TQString & type ) {
01081     TQString lowerType = type.lower();
01082     if ( lowerType == "brief" ) return brief();
01083     if ( lowerType == "plain" )  return plain();
01084     if ( lowerType == "enterprise" )  return enterprise();
01085     //if ( lowerType == "fancy" ) return fancy(); // not needed, see below
01086     // don't kdFatal here, b/c the strings are user-provided
01087     // (TDEConfig), so fail gracefully to the default:
01088     return fancy();
01089   }
01090 
01091   static const HeaderStyle * briefStyle = 0;
01092   static const HeaderStyle * plainStyle = 0;
01093   static const HeaderStyle * fancyStyle = 0;
01094   static const HeaderStyle * enterpriseStyle = 0;
01095 
01096   const HeaderStyle * HeaderStyle::brief() {
01097     if ( !briefStyle )
01098       briefStyle = new BriefHeaderStyle();
01099     return briefStyle;
01100   }
01101 
01102   const HeaderStyle * HeaderStyle::plain() {
01103     if ( !plainStyle )
01104       plainStyle = new PlainHeaderStyle();
01105     return plainStyle;
01106   }
01107 
01108   const HeaderStyle * HeaderStyle::fancy() {
01109     if ( !fancyStyle )
01110       fancyStyle = new FancyHeaderStyle();
01111     return fancyStyle;
01112   }
01113 
01114   const HeaderStyle * HeaderStyle::enterprise() {
01115     if ( !enterpriseStyle )
01116       enterpriseStyle = new EnterpriseHeaderStyle();
01117     return enterpriseStyle;
01118   }
01119 
01120 } // namespace KMail