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