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 <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 <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       KLocale * locale = KGlobal::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       KLocale* locale = KGlobal::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 kabcUid;
00280     if ( strategy->showHeader( "status" ) )
00281     {
00282       KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00283       KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
00284       ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00285       kabcUid = addresses[0].uid();
00286       presence = imProxy->presenceString( kabcUid );
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-" + kabcUid + "\">" + 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     KConfigGroup 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       KLocale* locale = KGlobal::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 kabc photo
00477 
00478     ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00479     TQString kabcUid;
00480     KABC::AddressBook *addressBook = KABC::StdAddressBook::self( true );
00481     KABC::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       // kabcUid is embedded in im: URIs to indicate which IM contact to message
00489       kabcUid = addresses[0].uid();
00490 
00491       if ( imProxy->initialize() ) {
00492           // im status
00493           presence = imProxy->presenceString( kabcUid );
00494           if ( !presence.isEmpty() )
00495           {
00496             TQString presenceIcon = TQString::fromLatin1( " <img src=\"%1\"/>" )
00497                 .arg( imgToDataUrl( imProxy->presenceIcon( kabcUid ).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( kabcUid )
00596             .arg( userHTML )
00597              .arg( kabcUid )
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( kabcUid )
00606             .arg( kabcUid )
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 fro 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         int lzone = (int) (t_local - t_utc) / 60;
00646                 
00647                 // kdDebug() << "FancyHeaderStyle::format() local zone offset (in minutes): " << lzone << endl;
00648                 
00649                 TQTime currTime = TQTime::currentTime( Qt::UTC );
00650                 
00651                 // kdDebug() << "FancyHeaderStyle::format() current time: " << currTime << endl;
00652                 
00653                 // now currTime contain message sender local time
00654                 currTime = currTime.addSecs( zone * 60 );
00655                 
00656                 TQString timeofday;
00657                 TQString color;
00658                 TQString bg_color;
00659                 TQString bg_image;
00660                 if ( currTime > TQTime( 0, 0, 0 ) && currTime <= TQTime( 6, 0, 0 ) ) {
00661                   timeofday = i18n( "Night" );
00662                   color = "white";
00663                   bg_color = "#000B6B";
00664                   bg_image = "url(data:image/png;base64,"
00665                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAIAAAASmSbdAAAAS0lEQVQI11WOsRGAQAzDOG/LHoz9"
00666                     "kikIcF+kSBxbPs7LoNGVapAI0Zn+O+8NUwldozn6io7G7kdS/5zi7i+BvUM/5uSXlIfzMHx/bmWR"
00667                     "k++yj9rZAAAAAElFTkSuQmCC)";
00668                 }
00669                 else if ( currTime > TQTime( 6, 0, 0 ) && currTime <= TQTime( 12, 0, 0 ) ) {
00670                   timeofday = i18n( "Morning" );
00671                   color = "white";
00672                   bg_color = "#00A6FF";
00673                   bg_image = "url(data:image/png;base64,"
00674                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAWklEQVQI122OQQ7DMAzDaP3/dfuO"
00675                     "pWSHJgva7iZIBk3m/Ew5hexCHVCilewzFHKEbFZqgxJQWyzKhWKl9unqddJj8+L9sl0oR2gUim+o"
00676                     "zu4uSh7kn67/DNv+C4tsZOtjAWEHAAAAAElFTkSuQmCC)";
00677                 }
00678                 else if ( currTime > TQTime( 12, 0, 0 ) && currTime <= TQTime( 18, 0, 0 ) ) {
00679                   timeofday = i18n( "Afternoon" );
00680                   color = "black";
00681                   bg_color = "#00A6FF";
00682                   bg_image = "url(data:image/png;base64,"
00683                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAPUlEQVQI132OwQ0AIAwCSfcfw91c"
00684                     "QsCfRm399HFwoWjdDhMICQhxHSWMQPhkTCoqWRZU2h5i9tr4GZfmV5t3wWUI3h+NugAAAABJRU5E"
00685                     "rkJggg==)";
00686                 }
00687                 else {
00688                   timeofday = i18n( "Evening" );
00689                   color = "white";
00690                   bg_color = "#0014CC";
00691                   bg_image = "url(data:image/png;base64,"
00692                     "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAWklEQVQI11WOyRHAMAgDNQuUlBrS"
00693                     "fyFpAfKwje0PwyEt0vN+hVsJpzS6QML2ziWcFI6mZBZNSVDXYehyUgI1XsLI9eimHDH6kW0ddVIO"
00694                     "xx7JjrtshlbXlLDSD+WhJ+hwqWo8AAAAAElFTkSuQmCC)";
00695                 }
00696                 
00697                 TQString tformat;
00698                 if ( KGlobal::locale()->use12Clock() ) {
00699                   tformat = "h:mm AP";
00700                 }
00701                 else {
00702                   tformat = "h:mm";
00703                 }
00704                 
00705                 // kdDebug() << "FancyHeaderStyle::format() current time: " << currTime << " (" << timeofday << ")" << endl;
00706                 
00707                 timeHTML.append( TQString(
00708                   "<div style=\""
00709                   "border:1px solid %1;"
00710                   "color:%2;"
00711                   "background-image:%3;"
00712                   "background-position:center left;"
00713                   "background-repeat:repeat-x;"
00714                   "text-align:center;"
00715                   "font-size:12px;"
00716                   "padding:2px;"
00717                   "width:50px;"
00718                   "heigth:50px;"
00719                   "margin: 0px 0px 3px 0px;"
00720                   "\" class=\"curtime\">%4<br />%5<br />%6</div>"
00721                   )
00722                   .arg( bg_color )
00723                   .arg( color )
00724                   .arg( bg_image )
00725                   .arg( i18n( "Now:" ) )
00726                   .arg( currTime.toString( tformat ) )
00727                   .arg( timeofday )
00728                   );
00729             }
00730             else {
00731               // kdDebug() << "FancyHeaderStyle::format() no date header to display" << endl;
00732             }
00733     }
00734 
00735     //case HdrFancy:
00736     // the subject line and box below for details
00737     if ( strategy->showHeader( "subject" ) ) {
00738       const int flags = LinkLocator::PreserveSpaces |
00739                         ( GlobalSettings::self()->showEmoticons() ?
00740                           LinkLocator::ReplaceSmileys : 0 );
00741       headerStr += TQString("<div dir=\"%1\">%2</div>\n")
00742                         .arg(subjectDir)
00743                         .arg(message->subject().isEmpty()?
00744                              i18n("No Subject") :
00745                              strToHtml( message->subject(), flags ));
00746     }
00747     headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00748     //headerStr += "<table>\n";
00749     // from line
00750     // the mailto: URLs can contain %3 etc., therefore usage of multiple
00751     // TQString::arg is not possible
00752     if ( strategy->showHeader( "from" ) ) {
00753       TQString fromStr = message->from();
00754       if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00755         fromStr = message->fromStrip(); // let's use that
00756       headerStr += TQString("<tr><th>%1</th>\n"
00757                            "<td>")
00758                            .arg(i18n("From: "))
00759                  + KMMessage::emailAddrAsAnchor( fromStr, false )
00760                  + ( !message->headerField( "Resent-From" ).isEmpty() ? "&nbsp;"
00761                                 + i18n("(resent from %1)")
00762                                   .arg( KMMessage::emailAddrAsAnchor(
00763                                     message->headerField( "Resent-From" ),false) )
00764                               : TQString("") )
00765                  + ( !vCardName.isEmpty() ? "&nbsp;&nbsp;<a href=\"" + vCardName + "\">"
00766                                 + i18n("[vCard]") + "</a>"
00767                               : TQString("") )
00768 #if 0
00769                  + ( ( !presence.isEmpty() )
00770                               ? "&nbsp;&nbsp;(<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)"
00771                               : TQString("") )
00772 #endif
00773                  + ( message->headerField("Organization").isEmpty()
00774                               ? TQString("")
00775                               : "&nbsp;&nbsp;("
00776                                 + strToHtml(message->headerField("Organization"))
00777                                 + ")")
00778                  + "</td></tr>\n";
00779     }
00780     // to line
00781     if ( strategy->showHeader( "to" ) )
00782       headerStr.append(TQString("<tr><th>%1</th>\n"
00783                                "<td>%2</td></tr>\n")
00784                        .arg(i18n("To: "))
00785                        .arg(KMMessage::emailAddrAsAnchor(message->to(),false)));
00786 
00787     // cc line, if any
00788     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
00789       headerStr.append(TQString("<tr><th>%1</th>\n"
00790                                "<td>%2</td></tr>\n")
00791                        .arg(i18n("CC: "))
00792                        .arg(KMMessage::emailAddrAsAnchor(message->cc(),false)));
00793 
00794     // Bcc line, if any
00795     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
00796       headerStr.append(TQString("<tr><th>%1</th>\n"
00797                                "<td>%2</td></tr>\n")
00798                        .arg(i18n("BCC: "))
00799                        .arg(KMMessage::emailAddrAsAnchor(message->bcc(),false)));
00800 
00801     if ( strategy->showHeader( "date" ) )
00802       headerStr.append(TQString("<tr><th>%1</th>\n"
00803                                "<td dir=\"%2\">%3</td></tr>\n")
00804                        .arg(i18n("Date: "))
00805                        .arg( directionOf( message->dateStr() ) )
00806                        .arg(strToHtml(dateString)));
00807 
00808     if ( GlobalSettings::self()->showUserAgent() ) {
00809       if ( strategy->showHeader( "user-agent" ) ) {
00810         if ( !message->headerField("User-Agent").isEmpty() ) {
00811           headerStr.append(TQString("<tr><th>%1</th>\n"
00812                                    "<td>%2</td></tr>\n")
00813                            .arg(i18n("User-Agent: "))
00814                            .arg( strToHtml( message->headerField("User-Agent") ) ) );
00815         }
00816       }
00817 
00818       if ( strategy->showHeader( "x-mailer" ) ) {
00819         if ( !message->headerField("X-Mailer").isEmpty() ) {
00820           headerStr.append(TQString("<tr><th>%1</th>\n"
00821                                    "<td>%2</td></tr>\n")
00822                            .arg(i18n("X-Mailer: "))
00823                            .arg( strToHtml( message->headerField("X-Mailer") ) ) );
00824         }
00825       }
00826     }
00827 
00828     // FIXME: Show status in synthetic header style field.  Decide whether this or current in brackets style is best and remove one.
00829     /*    if( strategy->showHeader( "status" ) )
00830       headerStr.append( TQString( "<tr><th>%1</th>\n"
00831                                  "<td dir=\"%2\">%3</td></tr>\n")
00832                                     .arg(i18n("Sender status: "))
00833                                     .arg( directionOf( onlineStatus ) )
00834                                     .arg(onlineStatus));
00835     */
00836     headerStr.append( TQString("<tr><td colspan=\"2\"><div id=\"attachmentInjectionPoint\"></div></td></tr>" ) );
00837     headerStr.append(
00838           TQString( "</table></td><td align=\"center\" valign=\"top\">%1%2</td></tr></table>\n" )
00839           .arg(timeHTML)
00840           .arg(userHTML) );
00841 
00842     if ( !spamHTML.isEmpty() )
00843       headerStr.append( TQString( "<div class=\"spamheader\" dir=\"%1\"><b>%2</b>&nbsp;<span style=\"padding-left: 20px;\">%3</span></div>\n")
00844                         .arg( subjectDir, i18n("Spam Status:"), spamHTML ) );
00845 
00846     headerStr += "</div>\n\n";
00847     return headerStr;
00848   }
00849 
00850   TQString FancyHeaderStyle::imgToDataUrl( const TQImage &image, const char* fmt  )
00851   {
00852     TQByteArray ba;
00853     TQBuffer buffer( ba );
00854     buffer.open( IO_WriteOnly );
00855     image.save( &buffer, fmt );
00856     return TQString::fromLatin1("data:image/%1;base64,%2")
00857            .arg( fmt, KCodecs::base64Encode( ba ).data() );
00858   }
00859 
00860 // #####################
00861 
00862   class EnterpriseHeaderStyle : public HeaderStyle {
00863     friend class ::KMail::HeaderStyle;
00864   protected:
00865     EnterpriseHeaderStyle() : HeaderStyle() {}
00866     virtual ~EnterpriseHeaderStyle() {}
00867 
00868   public:
00869     const char * name() const { return "enterprise"; }
00870     const HeaderStyle * next() const { return brief(); }
00871     const HeaderStyle * prev() const { return fancy(); }
00872 
00873     TQString format( const KMMessage * message, const HeaderStrategy * strategy,
00874                     const TQString & vCardName, bool printing, bool topLevel ) const;
00875   };
00876 
00877     TQString EnterpriseHeaderStyle::format( const KMMessage * message,
00878                                     const HeaderStrategy * strategy,
00879                                     const TQString & vCardName, bool printing, bool topLevel ) const {
00880     if ( !message ) return TQString();
00881     if ( !strategy )
00882         strategy = HeaderStrategy::brief();
00883 
00884     // The direction of the header is determined according to the direction
00885     // of the application layout.
00886 
00887     TQString dir = TQApplication::reverseLayout() ? "rtl" : "ltr" ;
00888 
00889     // However, the direction of the message subject within the header is
00890     // determined according to the contents of the subject itself. Since
00891     // the "Re:" and "Fwd:" prefixes would always cause the subject to be
00892     // considered left-to-right, they are ignored when determining its
00893     // direction.
00894 
00895     TQString subjectDir;
00896     if (!message->subject().isEmpty())
00897         subjectDir = directionOf( message->cleanSubject() );
00898     else
00899         subjectDir = directionOf( i18n("No Subject") );
00900 
00901     // colors depend on if its encapsulated or not
00902         TQColor fontColor(TQt::white);
00903     TQString linkColor = "class =\"white\"";
00904     const TQColor activeColor = tqApp->palette().active().highlight();
00905     TQColor activeColorDark = activeColor.dark(130);
00906         // reverse colors for encapsulated
00907         if( !topLevel ){
00908             activeColorDark = activeColor.dark(50);
00909             fontColor = TQColor(TQt::black);
00910         linkColor = "class =\"black\"";
00911         }
00912 
00913     // Prepare the date string (when printing always use the localized date)
00914     TQString dateString;
00915     if( printing ) {
00916         TQDateTime dateTime;
00917         KLocale * locale = KGlobal::locale();
00918         dateTime.setTime_t( message->date() );
00919         dateString = locale->formatDateTime( dateTime );
00920     } else {
00921         dateString = message->dateStr();
00922     }
00923 
00924     TQString imgpath(locate("data","kmail/pics/"));
00925     imgpath.append("enterprise_");
00926     const TQString borderSettings(" padding-top: 0px; padding-bottom: 0px; border-width: 0px ");
00927     TQString headerStr ("");
00928 
00929     // 3D borders
00930     if(topLevel)
00931         headerStr +=
00932         "<div style=\"position: fixed; top: 0px; left: 0px; background-color: #606060; "
00933         "width: 10px; min-height: 100%;\">&nbsp;</div>"
00934         "<div style=\"position: fixed; top: 0px; right: 0px;  background-color: #606060; "
00935         "width: 10px; min-height: 100%;\">&nbsp;</div>";
00936 
00937     headerStr += ""
00938         "<div style=\"margin-left: 10px; top: 0px;\"><span style=\"font-size: 10px; font-weight: bold;\">"+dateString+"</span></div>"
00939         // #0057ae
00940         "<table style=\"background: "+activeColorDark.name()+"; border-collapse:collapse; top: 14px; min-width: 200px; \" cellpadding=0> \n"
00941         "  <tr> \n"
00942         "   <td style=\"min-width: 6px; background-image: url("+imgpath+"top_left.png); \"></td> \n"
00943         "   <td style=\"height: 6px; width: 100%; background: url("+imgpath+"top.png); \"></td> \n"
00944         "   <td style=\"min-width: 6px; background: url("+imgpath+"top_right.png); \"></td> </tr> \n"
00945         "   <tr> \n"
00946         "   <td style=\"min-width: 6px; max-width: 6px; background: url("+imgpath+"left.png); \"></td> \n"
00947         "   <td style=\"\"> \n";
00948 
00949   headerStr +=
00950     "     <div class=\"noprint\" style=\"z-index: 1; float:right; position: relative; top: -35px; right: 20px ;\">\n"
00951     "       <img src=\""+imgpath+"icon.png\">\n"
00952     "     </div>\n";
00953 
00954   headerStr +=
00955     "     <table style=\"color: "+fontColor.name()+" ! important; margin: 1px; border-spacing: 0px;\" cellpadding=0> \n";
00956 
00957     // subject
00958     //strToHtml( message->subject() )
00959     if ( strategy->showHeader( "subject" ) ){
00960         headerStr +=
00961         "     <tr> \n"
00962         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; "+borderSettings+"\"></td> \n"
00963         "      <td style=\"font-weight: bolder; font-size: 120%; padding-right: 91px; "+borderSettings+"\">"+message->subject()+"</td> \n"
00964         "     </tr> \n";
00965     }
00966 
00967     // from
00968     if ( strategy->showHeader( "from" ) ){
00969         TQString fromStr = message->from();
00970         if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
00971         fromStr = message->fromStrip(); // let's use that
00972             // TODO vcard
00973         TQString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true, linkColor );
00974         if ( !vCardName.isEmpty() )
00975         fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\" "+linkColor+">" + i18n("[vCard]") + "</a>";
00976         //TODO strategy date
00977         //if ( strategy->showHeader( "date" ) )
00978         headerStr +=
00979         "     <tr> \n"
00980         "      <td style=\"font-size: 6px; padding-left: 5px; padding-right: 24px; text-align: right; "+borderSettings+"\">"+i18n("From: ")+"</td> \n"
00981         "      <td style=\""+borderSettings+"\">"+ fromPart +"</td> "
00982         "     </tr> ";
00983     }
00984 
00985     // to line
00986     if( strategy->showHeader( "to" ) )
00987           headerStr +=
00988         "     <tr> "
00989         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("To: ") + "</td> "
00990         "      <td style=\"" + borderSettings + "\">" +
00991         KMMessage::emailAddrAsAnchor( message->to(), false, linkColor ) +
00992         "      </td> "
00993         "     </tr>\n";
00994 
00995         // cc line, if any
00996     if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
00997           headerStr +=
00998         "     <tr> "
00999         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("CC: ") + "</td> "
01000         "      <td style=\"" + borderSettings + "\">" +
01001         KMMessage::emailAddrAsAnchor( message->cc(), false, linkColor ) +
01002         "      </td> "
01003         "     </tr>\n";
01004 
01005         // bcc line, if any
01006     if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
01007           headerStr +=
01008         "     <tr> "
01009         "      <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("BCC: ") + "</td> "
01010         "      <td style=\"" + borderSettings + "\">" +
01011         KMMessage::emailAddrAsAnchor( message->bcc(), false, linkColor ) +
01012         "      </td> "
01013         "     </tr>\n";
01014 
01015     // header-bottom
01016     headerStr +=
01017         "    </table> \n"
01018         "   </td> \n"
01019         "   <td style=\"min-width: 6px; max-height: 15px; background: url("+imgpath+"right.png); \"></td> \n"
01020         "  </tr> \n"
01021         "  <tr> \n"
01022         "   <td style=\"min-width: 6px; background: url("+imgpath+"s_left.png); \"></td> \n"
01023         "   <td style=\"height: 35px; width: 80%; background: url("+imgpath+"sbar.png);\"> \n"
01024         "    <img src=\""+imgpath+"sw.png\" style=\"margin: 0px; height: 30px; overflow:hidden; \"> \n"
01025         "    <img src=\""+imgpath+"sp_right.png\" style=\"float: right; \"> </td> \n"
01026         "   <td style=\"min-width: 6px; background: url("+imgpath+"s_right.png); \"></td> \n"
01027         "  </tr> \n"
01028         " </table> \n";
01029 
01030     // kmail icon
01031     if(topLevel) {
01032 
01033         // attachments
01034         headerStr +=
01035         "<div class=\"noprint\" style=\"position: absolute; top: 60px; right: 20px; width: 91px; height: 200px;\">"
01036         "<div id=\"attachmentInjectionPoint\"></div>"
01037         "</div>\n";
01038     }
01039 
01040     if ( printing ) {
01041       //provide a bit more left padding when printing
01042       //kolab/issue3254 (printed mail cut at the left side)
01043       headerStr += "<div style=\"padding: 6px; padding-left: 10px;\">";
01044     } else {
01045       headerStr += "<div style=\"padding: 6px;\">";
01046     }
01047 
01048     // TODO
01049     // spam status
01050     // ### iterate over the rest of strategy->headerToDisplay() (or
01051     // ### all headers if DefaultPolicy == Display) (elsewhere, too)
01052     return headerStr;
01053   }
01054 
01055 // #####################
01056 
01057   //
01058   // HeaderStyle abstract base:
01059   //
01060 
01061   HeaderStyle::HeaderStyle() {
01062 
01063   }
01064 
01065   HeaderStyle::~HeaderStyle() {
01066 
01067   }
01068 
01069   const HeaderStyle * HeaderStyle::create( Type type ) {
01070     switch ( type ) {
01071     case Brief:  return brief();
01072     case Plain:  return plain();
01073     case Fancy:   return fancy();
01074     case Enterprise: return enterprise();
01075     }
01076     kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
01077                     << (int)type << " ) requested!" << endl;
01078     return 0; // make compiler happy
01079   }
01080 
01081   const HeaderStyle * HeaderStyle::create( const TQString & type ) {
01082     TQString lowerType = type.lower();
01083     if ( lowerType == "brief" ) return brief();
01084     if ( lowerType == "plain" )  return plain();
01085     if ( lowerType == "enterprise" )  return enterprise();
01086     //if ( lowerType == "fancy" ) return fancy(); // not needed, see below
01087     // don't kdFatal here, b/c the strings are user-provided
01088     // (KConfig), so fail gracefully to the default:
01089     return fancy();
01090   }
01091 
01092   static const HeaderStyle * briefStyle = 0;
01093   static const HeaderStyle * plainStyle = 0;
01094   static const HeaderStyle * fancyStyle = 0;
01095   static const HeaderStyle * enterpriseStyle = 0;
01096 
01097   const HeaderStyle * HeaderStyle::brief() {
01098     if ( !briefStyle )
01099       briefStyle = new BriefHeaderStyle();
01100     return briefStyle;
01101   }
01102 
01103   const HeaderStyle * HeaderStyle::plain() {
01104     if ( !plainStyle )
01105       plainStyle = new PlainHeaderStyle();
01106     return plainStyle;
01107   }
01108 
01109   const HeaderStyle * HeaderStyle::fancy() {
01110     if ( !fancyStyle )
01111       fancyStyle = new FancyHeaderStyle();
01112     return fancyStyle;
01113   }
01114 
01115   const HeaderStyle * HeaderStyle::enterprise() {
01116     if ( !enterpriseStyle )
01117       enterpriseStyle = new EnterpriseHeaderStyle();
01118     return enterpriseStyle;
01119   }
01120 
01121 } // namespace KMail