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 += " <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(" <a href=\"" + vCardName + 00298 "\">" + i18n("[vCard]") + "</a>" ); 00299 #if 0 00300 if ( !presence.isEmpty() && strategy->showHeader( "status" ) ) 00301 headerStr.append(" (<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)" ); 00302 #endif 00303 00304 if ( strategy->showHeader( "organization" ) 00305 && !message->headerField("Organization").isEmpty()) 00306 headerStr.append(" (" + 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\"> ") 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 = " "; 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() ? " " 00761 + i18n("(resent from %1)") 00762 .arg( KMMessage::emailAddrAsAnchor( 00763 message->headerField( "Resent-From" ),false) ) 00764 : TQString("") ) 00765 + ( !vCardName.isEmpty() ? " <a href=\"" + vCardName + "\">" 00766 + i18n("[vCard]") + "</a>" 00767 : TQString("") ) 00768 #if 0 00769 + ( ( !presence.isEmpty() ) 00770 ? " (<span name=\"presence-" + kabcUid + "\">" + presence + "</span>)" 00771 : TQString("") ) 00772 #endif 00773 + ( message->headerField("Organization").isEmpty() 00774 ? TQString("") 00775 : " (" 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> <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%;\"> </div>" 00934 "<div style=\"position: fixed; top: 0px; right: 0px; background-color: #606060; " 00935 "width: 10px; min-height: 100%;\"> </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 += " <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