kmail

headerstyle.cpp

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