00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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 "linklocator.h"
00040
#include "kmmessage.h"
00041
#include "kmkernel.h"
00042
00043
#include <libkdepim/email.h>
00044
00045
#include <mimelib/string.h>
00046
#include <mimelib/field.h>
00047
#include <mimelib/headers.h>
00048
00049
#include <kdebug.h>
00050
#include <klocale.h>
00051
#include <kglobal.h>
00052
#include "kimproxy.h"
00053
#include <kabc/stdaddressbook.h>
00054
#include <kabc/addresseelist.h>
00055
#include <kmdcodec.h>
00056
#include <qdatetime.h>
00057
#include <qbuffer.h>
00058
#include <qimage.h>
00059
#include <qapplication.h>
00060
#include <qregexp.h>
00061
00062
namespace KMail {
00063
00064
00065
00066
00067
static inline QString directionOf(
const QString & str ) {
00068
return str.isRightToLeft() ?
"rtl" :
"ltr" ;
00069 }
00070
00071
#if 0
00072
00073
00074
00075
static QString convertToHtmlBlock(
const QString & str,
bool useSpan=
false ) {
00076
QString dir = directionOf( str );
00077
QString format =
"<%1 dir=\"%3\">%4</%2>";
00078
return format.arg( useSpan ?
"span" :
"div" )
00079 .arg( useSpan ?
"span" :
"div" )
00080 .arg( dir )
00081 .arg( LinkLocator::convertToHtml( str ) );
00082 }
00083
#endif
00084
00085
00086
static QString strToHtml(
const QString & str,
bool preserveBlanks=
true ) {
00087
return LinkLocator::convertToHtml( str, preserveBlanks );
00088 }
00089
00090
00091
00092
00093
00094
00095
class BriefHeaderStyle :
public HeaderStyle {
00096
friend class HeaderStyle;
00097
protected:
00098 BriefHeaderStyle() : HeaderStyle() {}
00099
virtual ~BriefHeaderStyle() {}
00100
00101
public:
00102
const char * name()
const {
return "brief"; }
00103
const HeaderStyle * next()
const {
return plain(); }
00104
const HeaderStyle * prev()
const {
return fancy(); }
00105
00106
QString format(
const KMMessage * message,
const HeaderStrategy * strategy,
00107
const QString & vCardName,
bool printing )
const;
00108 };
00109
00110
QString BriefHeaderStyle::format(
const KMMessage * message,
00111
const HeaderStrategy * strategy,
00112
const QString & vCardName,
bool printing )
const {
00113
if ( !message )
return QString::null;
00114
if ( !strategy )
00115 strategy = HeaderStrategy::brief();
00116
00117
00118
00119
00120
QString dir = QApplication::reverseLayout() ?
"rtl" :
"ltr" ;
00121
00122
00123
00124
00125
00126
00127
00128
QString subjectDir;
00129
if (!message->subject().isEmpty())
00130 subjectDir = directionOf( message->cleanSubject() );
00131
else
00132 subjectDir = directionOf( i18n(
"No Subject") );
00133
00134
00135
QString dateString;
00136
if( printing ) {
00137
QDateTime dateTime;
00138 KLocale * locale = KGlobal::locale();
00139 dateTime.setTime_t( message->date() );
00140 dateString = locale->formatDateTime( dateTime );
00141 }
else {
00142 dateString = message->dateStr();
00143 }
00144
00145
QString headerStr =
"<div class=\"header\" dir=\"" + dir +
"\">\n";
00146
00147
if ( strategy->showHeader(
"subject" ) )
00148 headerStr +=
"<div dir=\"" + subjectDir +
"\">\n"
00149
"<b style=\"font-size:130%\">" +
00150 strToHtml( message->subject() ) +
00151
"</b></div>\n";
00152
00153
QStringList headerParts;
00154
00155
if ( strategy->showHeader(
"from" ) ) {
00156
QString fromPart = KMMessage::emailAddrAsAnchor( message->from(),
true );
00157
if ( !vCardName.isEmpty() )
00158 fromPart +=
" <a href=\"" + vCardName +
"\">" + i18n(
"[vCard]") +
"</a>";
00159 headerParts << fromPart;
00160 }
00161
00162
if ( strategy->showHeader(
"cc" ) && !message->cc().isEmpty() )
00163 headerParts << i18n(
"CC: ") + KMMessage::emailAddrAsAnchor( message->cc(),
true );
00164
00165
if ( strategy->showHeader(
"bcc" ) && !message->bcc().isEmpty() )
00166 headerParts << i18n(
"BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(),
true );
00167
00168
if ( strategy->showHeader(
"date" ) )
00169 headerParts << strToHtml(message->dateShortStr());
00170
00171
00172 headerStr +=
" (" + headerParts.grep(
QRegExp(
"\\S" ) ).join(
",\n" ) +
')';
00173
00174 headerStr +=
"</div>\n";
00175
00176
00177
00178
return headerStr;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
class PlainHeaderStyle :
public HeaderStyle {
00188
friend class HeaderStyle;
00189
protected:
00190 PlainHeaderStyle() : HeaderStyle() {}
00191
virtual ~PlainHeaderStyle() {}
00192
00193
public:
00194
const char * name()
const {
return "plain"; }
00195
const HeaderStyle * next()
const {
return fancy(); }
00196
const HeaderStyle * prev()
const {
return brief(); }
00197
00198
QString format(
const KMMessage * message,
const HeaderStrategy * strategy,
00199
const QString & vCardName,
bool printing )
const;
00200
00201
private:
00202
QString formatAllMessageHeaders(
const KMMessage * message )
const;
00203 };
00204
00205
QString PlainHeaderStyle::format(
const KMMessage * message,
00206
const HeaderStrategy * strategy,
00207
const QString & vCardName,
bool printing )
const {
00208
if ( !message )
return QString::null;
00209
if ( !strategy )
00210 strategy = HeaderStrategy::rich();
00211
00212
00213
00214
00215
QString dir = ( QApplication::reverseLayout() ?
"rtl" :
"ltr" );
00216
00217
00218
00219
00220
00221
00222
00223
QString subjectDir;
00224
if (!message->subject().isEmpty())
00225 subjectDir = directionOf( message->cleanSubject() );
00226
else
00227 subjectDir = directionOf( i18n(
"No Subject") );
00228
00229
00230
QString dateString;
00231
if( printing ) {
00232
QDateTime dateTime;
00233 KLocale* locale = KGlobal::locale();
00234 dateTime.setTime_t( message->date() );
00235 dateString = locale->formatDateTime( dateTime );
00236 }
00237
else {
00238 dateString = message->dateStr();
00239 }
00240
00241
QString headerStr =
QString(
"<div class=\"header\" dir=\"%1\">").arg(dir);
00242
00243
if ( strategy->headersToDisplay().isEmpty()
00244 && strategy->defaultPolicy() == HeaderStrategy::Display ) {
00245
00246 headerStr += formatAllMessageHeaders( message );
00247
return headerStr +
"</div>";
00248 }
00249
00250
00251
if ( strategy->showHeader(
"subject" ) )
00252 headerStr +=
QString(
"<div dir=\"%1\"><b style=\"font-size:130%\">" +
00253 strToHtml(message->subject()) +
"</b></div>\n")
00254 .arg(subjectDir);
00255
00256
if ( strategy->showHeader(
"date" ) )
00257 headerStr.append(i18n(
"Date: ") + strToHtml(dateString)+
"<br>\n");
00258
00259
00260
QString presence;
00261
QString kabcUid;
00262
if ( strategy->showHeader(
"status" ) )
00263 {
00264 KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00265 KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getEmailAddr( message->from() ) );
00266 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00267 kabcUid = addresses[0].uid();
00268 presence = imProxy->presenceString( kabcUid );
00269 }
00270
00271
if ( strategy->showHeader(
"from" ) ) {
00272 headerStr.append(i18n(
"From: ") +
00273 KMMessage::emailAddrAsAnchor(message->from(),FALSE));
00274
if ( !vCardName.isEmpty() )
00275 headerStr.append(
" <a href=\"" + vCardName +
00276
"\">" + i18n(
"[vCard]") +
"</a>" );
00277
if ( !presence.isEmpty() && strategy->showHeader(
"status" ) )
00278 headerStr.append(
" (<span name=\"presence-" + kabcUid +
"\">" + presence +
"</span>)" );
00279
if ( strategy->showHeader(
"organization" )
00280 && !message->headerField(
"Organization").isEmpty())
00281 headerStr.append(
" (" +
00282 strToHtml(message->headerField(
"Organization")) +
")");
00283 headerStr.append(
"<br>\n");
00284 }
00285
00286
if ( strategy->showHeader(
"to" ) )
00287 headerStr.append(i18n(
"To: ")+
00288 KMMessage::emailAddrAsAnchor(message->to(),FALSE) +
"<br>\n");
00289
00290
if ( strategy->showHeader(
"cc" ) && !message->cc().isEmpty() )
00291 headerStr.append(i18n(
"CC: ")+
00292 KMMessage::emailAddrAsAnchor(message->cc(),FALSE) +
"<br>\n");
00293
00294
if ( strategy->showHeader(
"bcc" ) && !message->bcc().isEmpty() )
00295 headerStr.append(i18n(
"BCC: ")+
00296 KMMessage::emailAddrAsAnchor(message->bcc(),FALSE) +
"<br>\n");
00297
00298
if ( strategy->showHeader(
"reply-to" ) && !message->replyTo().isEmpty())
00299 headerStr.append(i18n(
"Reply to: ")+
00300 KMMessage::emailAddrAsAnchor(message->replyTo(),FALSE) +
"<br>\n");
00301
00302 headerStr +=
"</div>\n";
00303
00304
return headerStr;
00305 }
00306
00307
QString PlainHeaderStyle::formatAllMessageHeaders(
const KMMessage * message )
const {
00308
const DwHeaders & headers = message->headers();
00309
QString result;
00310
00311
for (
const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
00312 result += ( field->FieldNameStr() +
": " ).c_str();
00313 result += strToHtml( field->FieldBodyStr().c_str() );
00314 result +=
"<br>\n";
00315 }
00316
00317
return result;
00318 }
00319
00320
00321
00322
00323
00324
00325
class FancyHeaderStyle :
public HeaderStyle {
00326
friend class HeaderStyle;
00327
protected:
00328 FancyHeaderStyle() : HeaderStyle() {}
00329
virtual ~FancyHeaderStyle() {}
00330
00331
public:
00332
const char * name()
const {
return "fancy"; }
00333
const HeaderStyle * next()
const {
return brief(); }
00334
const HeaderStyle * prev()
const {
return plain(); }
00335
00336
QString format(
const KMMessage * message,
const HeaderStrategy * strategy,
00337
const QString & vCardName,
bool printing )
const;
00338
static QString imgToDataUrl(
const QImage &image );
00339
00340 };
00341
00342
QString FancyHeaderStyle::format(
const KMMessage * message,
00343
const HeaderStrategy * strategy,
00344
const QString & vCardName,
bool printing )
const {
00345
if ( !message )
return QString::null;
00346
if ( !strategy )
00347 strategy = HeaderStrategy::rich();
00348
00349
00350
00351
00352
00353
QString dir = ( QApplication::reverseLayout() ?
"rtl" :
"ltr" );
00354
QString headerStr =
QString(
"<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
00355
00356
00357
00358
00359
00360
00361
00362
QString subjectDir;
00363
if ( !message->subject().isEmpty() )
00364 subjectDir = directionOf( message->cleanSubject() );
00365
else
00366 subjectDir = directionOf( i18n(
"No Subject") );
00367
00368
00369
QString dateString;
00370
if( printing ) {
00371
QDateTime dateTime;
00372 KLocale* locale = KGlobal::locale();
00373 dateTime.setTime_t( message->date() );
00374 dateString = locale->formatDateTime( dateTime );
00375 }
00376
else {
00377 dateString = message->dateStr();
00378 }
00379
00380
QString userHTML;
00381
QString presence;
00382
00383
00384
00385
00386 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
00387
QString kabcUid;
00388
if ( ( strategy->showHeader(
"status" ) || strategy->showHeader(
"statuspic" ) ) )
00389 {
00390
if ( imProxy->initialize() )
00391 {
00392 KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
00393 KABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getEmailAddr( message->from() ) );
00394
00395
if( addresses.count() == 1 )
00396 {
00397
00398 kabcUid = addresses[0].uid();
00399
00400
00401 presence = imProxy->presenceString( kabcUid );
00402
if ( !presence.isEmpty() )
00403 {
00404
QString presenceIcon = QString::fromLatin1(
" <img src=\"%1\"/>" )
00405 .arg( imgToDataUrl( imProxy->presenceIcon( kabcUid ).convertToImage() ) );
00406 presence += presenceIcon;
00407 }
00408
00409
if ( strategy->showHeader(
"statuspic" ) )
00410 {
00411
QString photoURL;
00412
if ( addresses[0].photo().isIntern() )
00413 {
00414
00415
00416
QImage photo = addresses[0].photo().data();
00417
if ( !photo.isNull() )
00418 {
00419 photoURL = imgToDataUrl( photo );
00420 }
00421 }
00422
else
00423 {
00424
00425 photoURL = addresses[0].photo().url();
00426
if ( photoURL.startsWith(
"/") )
00427 photoURL.prepend(
"file:" );
00428 }
00429
if( !photoURL.isEmpty() )
00430 {
00431
00432 userHTML =
QString(
"<img src=\"%1\" width=\"60\" height=\"60\">").arg( photoURL );
00433
if ( presence.isEmpty() )
00434 {
00435 userHTML =
QString(
"<div class=\"senderpic\">") + userHTML +
"</div>";
00436 }
00437
else
00438 userHTML =
QString(
"<div class=\"senderpic\">"
00439
"<a href=\"im:%1\">%2<div class=\"senderstatus\"><span name=\"presence-%2\">%3</span></div></a>"
00440
"</div>" ).arg( kabcUid )
00441 .arg( userHTML )
00442 .arg( presence );
00443 }
00444 }
00445 }
00446
else
00447 {
00448 kdDebug( 5006 ) <<
"Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
00449 userHTML =
" ";
00450 }
00451 }
00452
00453
00454
00455
00456 }
00457
00458
00459 kdDebug( 5006 ) <<
"final presence: '" << presence <<
"'" << endl;
00460
00461
00462
if ( strategy->showHeader(
"subject" ) )
00463 headerStr +=
QString(
"<div dir=\"%1\">%2</div>\n")
00464 .arg(subjectDir)
00465 .arg(message->subject().isEmpty()?
00466 i18n(
"No Subject") :
00467 strToHtml(message->subject()));
00468 headerStr +=
"<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
00469
00470
00471
00472
00473
if ( strategy->showHeader(
"from" ) )
00474 headerStr +=
QString(
"<tr><th>%1</th>\n"
00475
"<td>")
00476 .arg(i18n(
"From: "))
00477 + KMMessage::emailAddrAsAnchor(message->from(),FALSE)
00478 + ( !vCardName.isEmpty() ?
" <a href=\"" + vCardName +
"\">"
00479 + i18n(
"[vCard]") +
"</a>"
00480 :
QString(
"") )
00481 + ( ( !presence.isEmpty() && strategy->showHeader(
"status" ) )
00482 ?
" (<span name=\"presence-" + kabcUid +
"\">" + presence +
"</span>)"
00483 :
QString(
"") )
00484 + ( message->headerField(
"Organization").isEmpty()
00485 ?
QString(
"")
00486 :
" ("
00487 + strToHtml(message->headerField(
"Organization"))
00488 +
")")
00489 +
"</td></tr>\n";
00490
00491
if ( strategy->showHeader(
"to" ) )
00492 headerStr.append(
QString(
"<tr><th>%1</th>\n"
00493
"<td>%2</td></tr>\n")
00494 .arg(i18n(
"To: "))
00495 .arg(KMMessage::emailAddrAsAnchor(message->to(),FALSE)));
00496
00497
00498
if ( strategy->showHeader(
"cc" ) && !message->cc().isEmpty())
00499 headerStr.append(
QString(
"<tr><th>%1</th>\n"
00500
"<td>%2</td></tr>\n")
00501 .arg(i18n(
"CC: "))
00502 .arg(KMMessage::emailAddrAsAnchor(message->cc(),FALSE)));
00503
00504
00505
if ( strategy->showHeader(
"bcc" ) && !message->bcc().isEmpty())
00506 headerStr.append(
QString(
"<tr><th>%1</th>\n"
00507
"<td>%2</td></tr>\n")
00508 .arg(i18n(
"BCC: "))
00509 .arg(KMMessage::emailAddrAsAnchor(message->bcc(),FALSE)));
00510
00511
if ( strategy->showHeader(
"date" ) )
00512 headerStr.append(
QString(
"<tr><th>%1</th>\n"
00513
"<td dir=\"%2\">%3</td></tr>\n")
00514 .arg(i18n(
"Date: "))
00515 .arg( directionOf( message->dateStr() ) )
00516 .arg(strToHtml(dateString)));
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 headerStr.append(
00527
QString(
"</table></td><td align=\"center\">%1</td></tr></table>\n").arg(userHTML)
00528 );
00529
00530 headerStr +=
"</div>\n\n";
00531
return headerStr;
00532 }
00533
00534
QString FancyHeaderStyle::imgToDataUrl(
const QImage &image )
00535 {
00536
QByteArray ba;
00537
QBuffer buffer( ba );
00538 buffer.open( IO_WriteOnly );
00539 image.save( &buffer,
"PNG" );
00540
return QString::fromLatin1(
"data:image/png;base64,%1").arg( KCodecs::base64Encode( ba ) );
00541 }
00542
00543
00544
00545
00546 HeaderStyle::HeaderStyle() {
00547
00548 }
00549
00550 HeaderStyle::~HeaderStyle() {
00551
00552 }
00553
00554
const HeaderStyle * HeaderStyle::create( Type type ) {
00555
switch ( type ) {
00556
case Brief:
return brief();
00557
case Plain:
return plain();
00558
case Fancy:
return fancy();
00559 }
00560 kdFatal( 5006 ) <<
"HeaderStyle::create(): Unknown header style ( type == "
00561 << (
int)type <<
" ) requested!" << endl;
00562
return 0;
00563 }
00564
00565
const HeaderStyle * HeaderStyle::create(
const QString & type ) {
00566
QString lowerType = type.lower();
00567
if ( lowerType ==
"brief" )
return brief();
00568
if ( lowerType ==
"plain" )
return plain();
00569
00570
00571
00572
return fancy();
00573 }
00574
00575
static const HeaderStyle * briefStyle = 0;
00576
static const HeaderStyle * plainStyle = 0;
00577
static const HeaderStyle * fancyStyle = 0;
00578
00579
const HeaderStyle * HeaderStyle::brief() {
00580
if ( !briefStyle )
00581 briefStyle =
new BriefHeaderStyle();
00582
return briefStyle;
00583 }
00584
00585
const HeaderStyle * HeaderStyle::plain() {
00586
if ( !plainStyle )
00587 plainStyle =
new PlainHeaderStyle();
00588
return plainStyle;
00589 }
00590
00591
const HeaderStyle * HeaderStyle::fancy() {
00592
if ( !fancyStyle )
00593 fancyStyle =
new FancyHeaderStyle();
00594
return fancyStyle;
00595 }
00596
00597 }