kmail

headerstyle.cpp
1/*
2 headerstyle.cpp
3
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2003 Marc Mutz <mutz@kde.org>
6
7 KMail is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License, version 2, as
9 published by the Free Software Foundation.
10
11 KMail is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 In addition, as a special exception, the copyright holders give
21 permission to link the code of this program with any edition of
22 the TQt library by Trolltech AS, Norway (or with modified versions
23 of TQt that use the same license as TQt), and distribute linked
24 combinations including the two. You must obey the GNU General
25 Public License in all respects for all of the code used other than
26 TQt. If you modify this file, you may extend this exception to
27 your version of the file, but you are not obligated to do so. If
28 you do not wish to do so, delete this exception statement from
29 your version.
30*/
31
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "headerstyle.h"
37
38#include "headerstrategy.h"
39#include "kmkernel.h"
40#include "linklocator.h"
41#include "kmmessage.h"
42#include "spamheaderanalyzer.h"
43#include "globalsettings.h"
44
45#include <libemailfunctions/email.h>
46#include <libtdepim/kxface.h>
47using namespace KPIM;
48
49#include <mimelib/string.h>
50#include <mimelib/field.h>
51#include <mimelib/headers.h>
52
53#include <kdebug.h>
54#include <tdelocale.h>
55#include <tdeglobal.h>
56#include <tdeimproxy.h>
57#include <tdeabc/stdaddressbook.h>
58#include <tdeabc/addresseelist.h>
59#include <kmdcodec.h>
60#include <tqdatetime.h>
61#include <tqbuffer.h>
62#include <tqbitmap.h>
63#include <tqimage.h>
64#include <tqapplication.h>
65#include <tqregexp.h>
66
67#include <tdestandarddirs.h>
68
69namespace KMail {
70
71 //
72 // Convenience functions:
73 //
74 static inline TQString directionOf( const TQString & str ) {
75 return str.isRightToLeft() ? "rtl" : "ltr" ;
76 }
77
78#if 0
79 // Converts to html. Changes URLs into href's, escapes HTML special
80 // chars and inserts the result into an <div> or <span> tag with
81 // "dir" set to "rtl" or "ltr" depending on the direction of @p str.
82 static TQString convertToHtmlBlock( const TQString & str, bool useSpan=false ) {
83 TQString dir = directionOf( str );
84 TQString format = "<%1 dir=\"%3\">%4</%2>";
85 return format.arg( useSpan ? "span" : "div" )
86 .arg( useSpan ? "span" : "div" )
87 .arg( dir )
88 .arg( LinkLocator::convertToHtml( str ) );
89 }
90#endif
91
92 // ### tmp wrapper to make kmreaderwin code working:
93 static TQString strToHtml( const TQString & str,
94 int flags = LinkLocator::PreserveSpaces ) {
95 return LinkLocator::convertToHtml( str, flags );
96 }
97
98 //
99 // BriefHeaderStyle
100 // Show everything in a single line, don't show header field names.
101 //
102
103 class BriefHeaderStyle : public HeaderStyle {
104 friend class ::KMail::HeaderStyle;
105 protected:
106 BriefHeaderStyle() : HeaderStyle() {}
107 virtual ~BriefHeaderStyle() {}
108
109 public:
110 const char * name() const { return "brief"; }
111 const HeaderStyle * next() const { return plain(); }
112 const HeaderStyle * prev() const { return fancy(); }
113
114 TQString format( const KMMessage * message, const HeaderStrategy * strategy,
115 const TQString & vCardName, bool printing, bool topLevel ) const;
116 };
117
118 TQString BriefHeaderStyle::format( const KMMessage * message,
119 const HeaderStrategy * strategy,
120 const TQString & vCardName, bool printing, bool topLevel ) const {
121 Q_UNUSED( topLevel );
122 if ( !message ) return TQString();
123 if ( !strategy )
124 strategy = HeaderStrategy::brief();
125
126 // The direction of the header is determined according to the direction
127 // of the application layout.
128
129 TQString dir = TQApplication::reverseLayout() ? "rtl" : "ltr" ;
130
131 // However, the direction of the message subject within the header is
132 // determined according to the contents of the subject itself. Since
133 // the "Re:" and "Fwd:" prefixes would always cause the subject to be
134 // considered left-to-right, they are ignored when determining its
135 // direction.
136
137 TQString subjectDir;
138 if (!message->subject().isEmpty())
139 subjectDir = directionOf( message->cleanSubject() );
140 else
141 subjectDir = directionOf( i18n("No Subject") );
142
143 // Prepare the date string (when printing always use the localized date)
144 TQString dateString;
145 if( printing ) {
146 TQDateTime dateTime;
147 TDELocale * locale = TDEGlobal::locale();
148 dateTime.setTime_t( message->date() );
149 dateString = locale->formatDateTime( dateTime );
150 } else {
151 dateString = message->dateStr();
152 }
153
154 TQString headerStr = "<div class=\"header\" dir=\"" + dir + "\">\n";
155
156 if ( strategy->showHeader( "subject" ) )
157 headerStr += "<div dir=\"" + subjectDir + "\">\n"
158 "<b style=\"font-size:130%\">" +
159 strToHtml( message->subject() ) +
160 "</b></div>\n";
161
162 TQStringList headerParts;
163
164 if ( strategy->showHeader( "from" ) ) {
165 TQString fromStr = message->from();
166 if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
167 fromStr = message->fromStrip(); // let's use that
168 TQString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true );
169 if ( !vCardName.isEmpty() )
170 fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\">" + i18n("[vCard]") + "</a>";
171 headerParts << fromPart;
172 }
173
174 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
175 headerParts << i18n("CC: ") + KMMessage::emailAddrAsAnchor( message->cc(), true );
176
177 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
178 headerParts << i18n("BCC: ") + KMMessage::emailAddrAsAnchor( message->bcc(), true );
179
180 if ( strategy->showHeader( "date" ) )
181 headerParts << strToHtml(message->dateShortStr());
182
183 // remove all empty (modulo whitespace) entries and joins them via ", \n"
184 headerStr += " (" + headerParts.grep( TQRegExp( "\\S" ) ).join( ",\n" ) + ')';
185
186 headerStr += "</div>\n";
187
188 // ### iterate over the rest of strategy->headerToDisplay() (or
189 // ### all headers if DefaultPolicy == Display) (elsewhere, too)
190 return headerStr;
191 }
192
193 //
194 // PlainHeaderStyle:
195 // show every header field on a line by itself,
196 // show subject larger
197 //
198
199 class PlainHeaderStyle : public HeaderStyle {
200 friend class ::KMail::HeaderStyle;
201 protected:
202 PlainHeaderStyle() : HeaderStyle() {}
203 virtual ~PlainHeaderStyle() {}
204
205 public:
206 const char * name() const { return "plain"; }
207 const HeaderStyle * next() const { return fancy(); }
208 const HeaderStyle * prev() const { return brief(); }
209
210 TQString format( const KMMessage * message, const HeaderStrategy * strategy,
211 const TQString & vCardName, bool printing, bool topLevel ) const;
212
213 private:
214 TQString formatAllMessageHeaders( const KMMessage * message ) const;
215 };
216
217 TQString PlainHeaderStyle::format( const KMMessage * message,
218 const HeaderStrategy * strategy,
219 const TQString & vCardName, bool printing, bool topLevel ) const {
220 Q_UNUSED( topLevel );
221 if ( !message ) return TQString();
222 if ( !strategy )
223 strategy = HeaderStrategy::rich();
224
225 // The direction of the header is determined according to the direction
226 // of the application layout.
227
228 TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
229
230 // However, the direction of the message subject within the header is
231 // determined according to the contents of the subject itself. Since
232 // the "Re:" and "Fwd:" prefixes would always cause the subject to be
233 // considered left-to-right, they are ignored when determining its
234 // direction.
235
236 TQString subjectDir;
237 if (!message->subject().isEmpty())
238 subjectDir = directionOf( message->cleanSubject() );
239 else
240 subjectDir = directionOf( i18n("No Subject") );
241
242 // Prepare the date string (when printing always use the localized date)
243 TQString dateString;
244 if( printing ) {
245 TQDateTime dateTime;
246 TDELocale* locale = TDEGlobal::locale();
247 dateTime.setTime_t( message->date() );
248 dateString = locale->formatDateTime( dateTime );
249 }
250 else {
251 dateString = message->dateStr();
252 }
253
254 TQString headerStr;
255
256 if ( strategy->headersToDisplay().isEmpty()
257 && strategy->defaultPolicy() == HeaderStrategy::Display ) {
258 // crude way to emulate "all" headers - Note: no strings have
259 // i18n(), so direction should always be ltr.
260 headerStr= TQString("<div class=\"header\" dir=\"ltr\">");
261 headerStr += formatAllMessageHeaders( message );
262 return headerStr + "</div>";
263 }
264
265 headerStr = TQString("<div class=\"header\" dir=\"%1\">").arg(dir);
266
267 //case HdrLong:
268 if ( strategy->showHeader( "subject" ) )
269 headerStr += TQString("<div dir=\"%1\"><b style=\"font-size:130%\">" +
270 strToHtml(message->subject()) + "</b></div>\n")
271 .arg(subjectDir);
272
273 if ( strategy->showHeader( "date" ) )
274 headerStr.append(i18n("Date: ") + strToHtml(dateString)+"<br>\n");
275
276#if 0
277 // Get Instant Messaging presence
278 TQString presence;
279 TQString tdeabcUid;
280 if ( strategy->showHeader( "status" ) )
281 {
282 TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
283 TDEABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
284 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
285 tdeabcUid = addresses[0].uid();
286 presence = imProxy->presenceString( tdeabcUid );
287 }
288#endif
289
290 if ( strategy->showHeader( "from" ) ) {
291 TQString fromStr = message->from();
292 if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
293 fromStr = message->fromStrip(); // let's use that
294 headerStr.append(i18n("From: ") +
295 KMMessage::emailAddrAsAnchor( fromStr, false, "", true ) );
296 if ( !vCardName.isEmpty() )
297 headerStr.append("&nbsp;&nbsp;<a href=\"" + vCardName +
298 "\">" + i18n("[vCard]") + "</a>" );
299#if 0
300 if ( !presence.isEmpty() && strategy->showHeader( "status" ) )
301 headerStr.append("&nbsp;&nbsp;(<span name=\"presence-" + tdeabcUid + "\">" + presence + "</span>)" );
302#endif
303
304 if ( strategy->showHeader( "organization" )
305 && !message->headerField("Organization").isEmpty())
306 headerStr.append("&nbsp;&nbsp;(" +
307 strToHtml(message->headerField("Organization")) + ")");
308 headerStr.append("<br>\n");
309 }
310
311 if ( strategy->showHeader( "to" ) )
312 headerStr.append(i18n("To: ")+
313 KMMessage::emailAddrAsAnchor(message->to(),false) + "<br>\n");
314
315 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
316 headerStr.append(i18n("CC: ")+
317 KMMessage::emailAddrAsAnchor(message->cc(),false) + "<br>\n");
318
319 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
320 headerStr.append(i18n("BCC: ")+
321 KMMessage::emailAddrAsAnchor(message->bcc(),false) + "<br>\n");
322
323 if ( strategy->showHeader( "reply-to" ) && !message->replyTo().isEmpty())
324 headerStr.append(i18n("Reply to: ")+
325 KMMessage::emailAddrAsAnchor(message->replyTo(),false) + "<br>\n");
326
327 headerStr += "</div>\n";
328
329 return headerStr;
330 }
331
332 TQString PlainHeaderStyle::formatAllMessageHeaders( const KMMessage * message ) const {
333 const DwHeaders & headers = message->headers();
334 TQString result;
335
336 for ( const DwField * field = headers.FirstField() ; field ; field = field->Next() ) {
337 result += ( field->FieldNameStr() + ": " ).c_str();
338 result += strToHtml( field->FieldBodyStr().c_str() );
339 result += "<br>\n";
340 }
341
342 return result;
343 }
344
345 //
346 // FancyHeaderStyle:
347 // Like PlainHeaderStyle, but with slick frames and background colours.
348 //
349
350 class FancyHeaderStyle : public HeaderStyle {
351 friend class ::KMail::HeaderStyle;
352 protected:
353 FancyHeaderStyle() : HeaderStyle() {}
354 virtual ~FancyHeaderStyle() {}
355
356 public:
357 const char * name() const { return "fancy"; }
358 const HeaderStyle * next() const { return enterprise(); }
359 const HeaderStyle * prev() const { return plain(); }
360
361 TQString format( const KMMessage * message, const HeaderStrategy * strategy,
362 const TQString & vCardName, bool printing, bool topLevel ) const;
363 static TQString imgToDataUrl( const TQImage & image,
364 const char *fmt = "PNG" );
365
366 private:
367 static TQString drawSpamMeter( double percent, const TQString & filterHeader );
368
369 };
370
371 TQString FancyHeaderStyle::drawSpamMeter( double percent,
372 const TQString & filterHeader )
373 {
374 TQImage meterBar( 20, 1, 8, 24 );
375 const unsigned short gradient[20][3] = {
376 { 0, 255, 0 },
377 { 27, 254, 0 },
378 { 54, 252, 0 },
379 { 80, 250, 0 },
380 { 107, 249, 0 },
381 { 135, 247, 0 },
382 { 161, 246, 0 },
383 { 187, 244, 0 },
384 { 214, 242, 0 },
385 { 241, 241, 0 },
386 { 255, 228, 0 },
387 { 255, 202, 0 },
388 { 255, 177, 0 },
389 { 255, 151, 0 },
390 { 255, 126, 0 },
391 { 255, 101, 0 },
392 { 255, 76, 0 },
393 { 255, 51, 0 },
394 { 255, 25, 0 },
395 { 255, 0, 0 }
396 };
397 meterBar.setColor( 21, tqRgb( 255, 255, 255 ) );
398 meterBar.setColor( 22, tqRgb( 170, 170, 170 ) );
399 if ( percent < 0 ) // grey is for errors
400 meterBar.fill( 22 );
401 else {
402 meterBar.fill( 21 );
403 int max = TQMIN( 20, static_cast<int>( percent ) / 5 );
404 for ( int i = 0; i < max; ++i ) {
405 meterBar.setColor( i+1, tqRgb( gradient[i][0], gradient[i][1],
406 gradient[i][2] ) );
407 meterBar.setPixel( i, 0, i+1 );
408 }
409 }
410 TQString titleText = i18n("%1% probability of being spam.\n\nFull report:\n%2")
411 .arg( TQString::number( percent ), filterHeader );
412 return TQString("<img src=\"%1\" width=\"%2\" height=\"%3\" style=\"border: 1px solid black;\" title=\"%4\"> &nbsp;")
413 .arg( imgToDataUrl( meterBar, "PPM" ), TQString::number( 20 ),
414 TQString::number( 5 ), titleText );
415 }
416
417
418 TQString FancyHeaderStyle::format( const KMMessage * message,
419 const HeaderStrategy * strategy,
420 const TQString & vCardName, bool printing, bool topLevel ) const {
421 Q_UNUSED( topLevel );
422 if ( !message ) return TQString();
423 if ( !strategy )
424 strategy = HeaderStrategy::rich();
425
426 TDEConfigGroup configReader( KMKernel::config(), "Reader" );
427
428 // ### from kmreaderwin begin
429 // The direction of the header is determined according to the direction
430 // of the application layout.
431
432 TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
433 TQString headerStr = TQString("<div class=\"fancy header\" dir=\"%1\">\n").arg(dir);
434
435 // However, the direction of the message subject within the header is
436 // determined according to the contents of the subject itself. Since
437 // the "Re:" and "Fwd:" prefixes would always cause the subject to be
438 // considered left-to-right, they are ignored when determining its
439 // direction.
440
441 TQString subjectDir;
442 if ( !message->subject().isEmpty() )
443 subjectDir = directionOf( message->cleanSubject() );
444 else
445 subjectDir = directionOf( i18n("No Subject") );
446
447 // Prepare the date string (when printing always use the localized date)
448 TQString dateString;
449 if( printing ) {
450 TQDateTime dateTime;
451 TDELocale* locale = TDEGlobal::locale();
452 dateTime.setTime_t( message->date() );
453 dateString = locale->formatDateTime( dateTime );
454 }
455 else {
456 dateString = message->dateStr();
457 }
458
459 // Spam header display.
460 // If the spamSpamStatus config value is true then we look for headers
461 // from a few spam filters and try to create visually meaningful graphics
462 // out of the spam scores.
463
464 TQString spamHTML;
465
466 if ( configReader.readBoolEntry( "showSpamStatus", true ) ) {
467 SpamScores scores = SpamHeaderAnalyzer::getSpamScores( message );
468 for ( SpamScoresIterator it = scores.begin(); it != scores.end(); ++it )
469 spamHTML += (*it).agent() + " " +
470 drawSpamMeter( (*it).score(), (*it).spamHeader() );
471 }
472
473 TQString userHTML;
474 TQString presence;
475
476 // IM presence and tdeabc photo
477
478 ::KIMProxy *imProxy = KMKernel::self()->imProxy();
479 TQString tdeabcUid;
480 TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
481 TDEABC::AddresseeList addresses = addressBook->findByEmail( KPIM::getFirstEmailAddress( message->from() ) );
482
483 TQString photoURL;
484 int photoWidth = 60;
485 int photoHeight = 60;
486 if( addresses.count() == 1 )
487 {
488 // tdeabcUid is embedded in im: URIs to indicate which IM contact to message
489 tdeabcUid = addresses[0].uid();
490
491 if ( imProxy->initialize() ) {
492 // im status
493 presence = imProxy->presenceString( tdeabcUid );
494 if ( !presence.isEmpty() )
495 {
496 TQString presenceIcon = TQString::fromLatin1( " <img src=\"%1\"/>" )
497 .arg( imgToDataUrl( imProxy->presenceIcon( tdeabcUid ).convertToImage() ) );
498 presence += presenceIcon;
499 }
500 }
501 // picture
502 if ( addresses[0].photo().isIntern() )
503 {
504 // get photo data and convert to data: url
505 //kdDebug( 5006 ) << "INTERNAL photo found" << endl;
506 TQImage photo = addresses[0].photo().data();
507 if ( !photo.isNull() )
508 {
509 photoWidth = photo.width();
510 photoHeight = photo.height();
511 // scale below 60, otherwise it can get way too large
512 if ( photoHeight > 60 ) {
513 double ratio = ( double )photoHeight / ( double )photoWidth;
514 photoHeight = 60;
515 photoWidth = (int)( 60 / ratio );
516 photo = photo.smoothScale( photoWidth, photoHeight );
517 }
518 photoURL = imgToDataUrl( photo );
519 }
520 }
521 else
522 {
523 //kdDebug( 5006 ) << "URL found" << endl;
524 photoURL = addresses[0].photo().url();
525 if ( photoURL.startsWith("/") )
526 photoURL.prepend( "file:" );
527 }
528 }
529 else // TODO: find a usable one
530 {
531 kdDebug( 5006 ) << "Multiple / No addressees matched email address; Count is " << addresses.count() << endl;
532 userHTML = "&nbsp;";
533 }
534
535 if( photoURL.isEmpty() ) {
536 // no photo, look for a Face header
537 TQString faceheader = message->headerField( "Face" );
538 if ( !faceheader.isEmpty() ) {
539 TQImage faceimage;
540
541 kdDebug( 5006 ) << "Found Face: header" << endl;
542
543 TQCString facestring = faceheader.utf8();
544 // Spec says header should be less than 998 bytes
545 // Face: is 5 characters
546 if ( facestring.length() < 993 ) {
547 TQByteArray facearray;
548 KCodecs::base64Decode(facestring, facearray);
549
550 TQImage faceimage;
551 if ( faceimage.loadFromData( facearray, "png" ) ) {
552 // Spec says image must be 48x48 pixels
553 if ( (48 == faceimage.width()) && (48 == faceimage.height()) ) {
554 photoURL = imgToDataUrl( faceimage );
555 photoWidth = 48;
556 photoHeight = 48;
557 } else {
558 kdDebug( 5006 ) << "Face: header image is" << faceimage.width() << "by" << faceimage.height() <<"not 48x48 Pixels" << endl;
559 }
560 } else {
561 kdDebug( 5006 ) << "Failed to load decoded png from Face: header" << endl;
562 }
563 } else {
564 kdDebug( 5006 ) << "Face: header too long at " << facestring.length() << endl;
565 }
566 }
567 }
568
569 if( photoURL.isEmpty() )
570 {
571 // no photo, look for a X-Face header
572 TQString xfaceURL;
573 TQString xfhead = message->headerField( "X-Face" );
574 if ( !xfhead.isEmpty() )
575 {
576 KXFace xf;
577 photoURL = imgToDataUrl( xf.toImage( xfhead ) );
578 photoWidth = 48;
579 photoHeight = 48;
580
581 }
582 }
583
584 if( !photoURL.isEmpty() )
585 {
586 //kdDebug( 5006 ) << "Got a photo: " << photoURL << endl;
587 userHTML = TQString("<img src=\"%1\" width=\"%2\" height=\"%3\">")
588 .arg( photoURL ).arg( photoWidth ).arg( photoHeight );
589 if ( presence.isEmpty() ) {
590 userHTML = TQString("<div class=\"senderpic\">") + userHTML + "</div>";
591 } else {
592 userHTML = TQString( "<div class=\"senderpic\">"
593 "<a href=\"im:%1\">%2<div class=\"senderstatus\">"
594 "<span name=\"presence-%3\">%4</span></div></a>"
595 "</div>" ).arg( tdeabcUid )
596 .arg( userHTML )
597 .arg( tdeabcUid )
598 .arg( presence );
599 }
600 } else {
601 // we don't have a photo, just show presence, if we have it
602 if ( !presence.isEmpty() )
603 userHTML = TQString( "<a href=\"im:%1\"><div class=\"senderstatus\">"
604 "<span name=\"presence-%2\">%3</span></div></a>" )
605 .arg( tdeabcUid )
606 .arg( tdeabcUid )
607 .arg( presence );
608 }
609#if 0
610 // Disabled 'Launch IM' link in headers - Will
611 if ( imProxy->imAppsAvailable() )
612 presence = "<a name=\"launchim\" href=\"kmail:startIMApp\">" + i18n("Launch IM") + "</a></span>";
613 // do nothing - no im apps available, leave presence empty
614 //presence = i18n( "DCOP/InstantMessenger not installed" );
615 kdDebug( 5006 ) << "final presence: '" << presence << "'" << endl;
616#endif
617
618 TQString timeHTML;
619 if ( GlobalSettings::self()->showCurrentTime() && strategy->showHeader( "date" ) ) {
620 DwHeaders& header = message->headers();
621 if ( header.HasDate() ) {
622 DwDateTime& origDate = header.Date();
623 int zone = origDate.Zone();
624 // kdDebug() << "FancyHeaderStyle::format() zone offset (in minutes): " << zone << endl;
625
626 // copyed from mimelib -- code to determine local timezone
627 time_t t_now = time((time_t*) 0);
628#if defined(HAVE_GMTIME_R)
629 struct tm utc;
630 gmtime_r(&t_now, &utc);
631 struct tm local;
632 localtime_r(&t_now, &local);
633#else
634 struct tm utc = *gmtime(&t_now);
635 struct tm local = *localtime(&t_now);
636#endif
637 DwUint32 t_local = 0;
638 t_local = 24 * t_local + local.tm_hour;
639 t_local = 60 * t_local + local.tm_min;
640 t_local = 60 * t_local + local.tm_sec;
641 DwUint32 t_utc = 0;
642 t_utc = 24 * t_utc + utc.tm_hour;
643 t_utc = 60 * t_utc + utc.tm_min;
644 t_utc = 60 * t_utc + utc.tm_sec;
645
646 // kdDebug() << "FancyHeaderStyle::format() local zone offset (in minutes): " << lzone << endl;
647
648 TQTime currTime = TQTime::currentTime( TQt::UTC );
649
650 // kdDebug() << "FancyHeaderStyle::format() current time: " << currTime << endl;
651
652 // now currTime contain message sender local time
653 currTime = currTime.addSecs( zone * 60 );
654
655 TQString timeofday;
656 TQString color;
657 TQString bg_color;
658 TQString bg_image;
659 if ( currTime > TQTime( 0, 0, 0 ) && currTime <= TQTime( 6, 0, 0 ) ) {
660 timeofday = i18n( "Night" );
661 color = "white";
662 bg_color = "#000B6B";
663 bg_image = "url(data:image/png;base64,"
664 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAIAAAASmSbdAAAAS0lEQVQI11WOsRGAQAzDOG/LHoz9"
665 "kikIcF+kSBxbPs7LoNGVapAI0Zn+O+8NUwldozn6io7G7kdS/5zi7i+BvUM/5uSXlIfzMHx/bmWR"
666 "k++yj9rZAAAAAElFTkSuQmCC)";
667 }
668 else if ( currTime > TQTime( 6, 0, 0 ) && currTime <= TQTime( 12, 0, 0 ) ) {
669 timeofday = i18n( "Morning" );
670 color = "black";
671 bg_color = "#00A6FF";
672 bg_image = "url(data:image/png;base64,"
673 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAWklEQVQI122OQQ7DMAzDaP3/dfuO"
674 "pWSHJgva7iZIBk3m/Ew5hexCHVCilewzFHKEbFZqgxJQWyzKhWKl9unqddJj8+L9sl0oR2gUim+o"
675 "zu4uSh7kn67/DNv+C4tsZOtjAWEHAAAAAElFTkSuQmCC)";
676 }
677 else if ( currTime > TQTime( 12, 0, 0 ) && currTime <= TQTime( 18, 0, 0 ) ) {
678 timeofday = i18n( "Afternoon" );
679 color = "black";
680 bg_color = "#00A6FF";
681 bg_image = "url(data:image/png;base64,"
682 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAPUlEQVQI132OwQ0AIAwCSfcfw91c"
683 "QsCfRm399HFwoWjdDhMICQhxHSWMQPhkTCoqWRZU2h5i9tr4GZfmV5t3wWUI3h+NugAAAABJRU5E"
684 "rkJggg==)";
685 }
686 else {
687 timeofday = i18n( "Evening" );
688 color = "white";
689 bg_color = "#0014CC";
690 bg_image = "url(data:image/png;base64,"
691 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAyCAYAAACd+7GKAAAAWklEQVQI11WOyRHAMAgDNQuUlBrS"
692 "fyFpAfKwje0PwyEt0vN+hVsJpzS6QML2ziWcFI6mZBZNSVDXYehyUgI1XsLI9eimHDH6kW0ddVIO"
693 "xx7JjrtshlbXlLDSD+WhJ+hwqWo8AAAAAElFTkSuQmCC)";
694 }
695
696 TQString tformat;
697 if ( TDEGlobal::locale()->use12Clock() ) {
698 tformat = "h:mm AP";
699 }
700 else {
701 tformat = "h:mm";
702 }
703
704 // kdDebug() << "FancyHeaderStyle::format() current time: " << currTime << " (" << timeofday << ")" << endl;
705
706 timeHTML.append( TQString(
707 "<div id=\"sendersCurrentTime\" style=\""
708 "border:1px solid %1;"
709 "color:%2;"
710 "background-image:%3;"
711 "background-position:center left;"
712 "background-repeat:repeat-x;"
713 "text-align:center;"
714 "font-size:12px;"
715 "padding:2px;"
716 "width:150px;"
717 "height:45px;"
718 "margin: 0px 0px 3px 0px;"
719 "\" class=\"curtime\">%4<br />%5<br />%6</div>"
720 )
721 .arg( bg_color )
722 .arg( color )
723 .arg( bg_image )
724 .arg( i18n( "Sender's Current Time:" ) )
725 .arg( currTime.toString( tformat ) )
726 .arg( timeofday )
727 );
728 }
729 else {
730 // kdDebug() << "FancyHeaderStyle::format() no date header to display" << endl;
731 }
732 }
733
734 //case HdrFancy:
735 // the subject line and box below for details
736 if ( strategy->showHeader( "subject" ) ) {
737 const int flags = LinkLocator::PreserveSpaces |
738 ( GlobalSettings::self()->showEmoticons() ?
739 LinkLocator::ReplaceSmileys : 0 );
740 headerStr += TQString("<div dir=\"%1\">%2</div>\n")
741 .arg(subjectDir)
742 .arg(message->subject().isEmpty()?
743 i18n("No Subject") :
744 strToHtml( message->subject(), flags ));
745 }
746 headerStr += "<table class=\"outer\"><tr><td width=\"100%\"><table>\n";
747 //headerStr += "<table>\n";
748 // from line
749 // the mailto: URLs can contain %3 etc., therefore usage of multiple
750 // TQString::arg is not possible
751 if ( strategy->showHeader( "from" ) ) {
752 TQString fromStr = message->from();
753 if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
754 fromStr = message->fromStrip(); // let's use that
755 headerStr += TQString("<tr><th>%1</th>\n"
756 "<td>")
757 .arg(i18n("From: "))
758 + KMMessage::emailAddrAsAnchor( fromStr, false )
759 + ( !message->headerField( "Resent-From" ).isEmpty() ? "&nbsp;"
760 + i18n("(resent from %1)")
762 message->headerField( "Resent-From" ),false) )
763 : TQString("") )
764 + ( !vCardName.isEmpty() ? "&nbsp;&nbsp;<a href=\"" + vCardName + "\">"
765 + i18n("[vCard]") + "</a>"
766 : TQString("") )
767#if 0
768 + ( ( !presence.isEmpty() )
769 ? "&nbsp;&nbsp;(<span name=\"presence-" + tdeabcUid + "\">" + presence + "</span>)"
770 : TQString("") )
771#endif
772 + ( message->headerField("Organization").isEmpty()
773 ? TQString("")
774 : "&nbsp;&nbsp;("
775 + strToHtml(message->headerField("Organization"))
776 + ")")
777 + "</td></tr>\n";
778 }
779 // to line
780 if ( strategy->showHeader( "to" ) )
781 headerStr.append(TQString("<tr><th>%1</th>\n"
782 "<td>%2</td></tr>\n")
783 .arg(i18n("To: "))
784 .arg(KMMessage::emailAddrAsAnchor(message->to(),false)));
785
786 // cc line, if any
787 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty())
788 headerStr.append(TQString("<tr><th>%1</th>\n"
789 "<td>%2</td></tr>\n")
790 .arg(i18n("CC: "))
791 .arg(KMMessage::emailAddrAsAnchor(message->cc(),false)));
792
793 // Bcc line, if any
794 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty())
795 headerStr.append(TQString("<tr><th>%1</th>\n"
796 "<td>%2</td></tr>\n")
797 .arg(i18n("BCC: "))
798 .arg(KMMessage::emailAddrAsAnchor(message->bcc(),false)));
799
800 if ( strategy->showHeader( "date" ) )
801 headerStr.append(TQString("<tr><th>%1</th>\n"
802 "<td dir=\"%2\">%3</td></tr>\n")
803 .arg(i18n("Date: "))
804 .arg( directionOf( message->dateStr() ) )
805 .arg(strToHtml(dateString)));
806
807 if ( GlobalSettings::self()->showUserAgent() ) {
808 if ( strategy->showHeader( "user-agent" ) ) {
809 if ( !message->headerField("User-Agent").isEmpty() ) {
810 headerStr.append(TQString("<tr><th>%1</th>\n"
811 "<td>%2</td></tr>\n")
812 .arg(i18n("User-Agent: "))
813 .arg( strToHtml( message->headerField("User-Agent") ) ) );
814 }
815 }
816
817 if ( strategy->showHeader( "x-mailer" ) ) {
818 if ( !message->headerField("X-Mailer").isEmpty() ) {
819 headerStr.append(TQString("<tr><th>%1</th>\n"
820 "<td>%2</td></tr>\n")
821 .arg(i18n("X-Mailer: "))
822 .arg( strToHtml( message->headerField("X-Mailer") ) ) );
823 }
824 }
825 }
826
827 // FIXME: Show status in synthetic header style field. Decide whether this or current in brackets style is best and remove one.
828 /* if( strategy->showHeader( "status" ) )
829 headerStr.append( TQString( "<tr><th>%1</th>\n"
830 "<td dir=\"%2\">%3</td></tr>\n")
831 .arg(i18n("Sender status: "))
832 .arg( directionOf( onlineStatus ) )
833 .arg(onlineStatus));
834 */
835 headerStr.append( TQString("<tr><td colspan=\"2\"><div id=\"attachmentInjectionPoint\"></div></td></tr>" ) );
836 headerStr.append(
837 TQString( "</table></td><td align=\"center\" valign=\"top\">%1%2</td></tr></table>\n" )
838 .arg(timeHTML)
839 .arg(userHTML) );
840
841 if ( !spamHTML.isEmpty() )
842 headerStr.append( TQString( "<div class=\"spamheader\" dir=\"%1\"><b>%2</b>&nbsp;<span style=\"padding-left: 20px;\">%3</span></div>\n")
843 .arg( subjectDir, i18n("Spam Status:"), spamHTML ) );
844
845 headerStr += "</div>\n\n";
846 return headerStr;
847 }
848
849 TQString FancyHeaderStyle::imgToDataUrl( const TQImage &image, const char* fmt )
850 {
851 TQByteArray ba;
852 TQBuffer buffer( ba );
853 buffer.open( IO_WriteOnly );
854 image.save( &buffer, fmt );
855 return TQString::fromLatin1("data:image/%1;base64,%2")
856 .arg( fmt, KCodecs::base64Encode( ba ).data() );
857 }
858
859// #####################
860
861 class EnterpriseHeaderStyle : public HeaderStyle {
862 friend class ::KMail::HeaderStyle;
863 protected:
864 EnterpriseHeaderStyle() : HeaderStyle() {}
865 virtual ~EnterpriseHeaderStyle() {}
866
867 public:
868 const char * name() const { return "enterprise"; }
869 const HeaderStyle * next() const { return brief(); }
870 const HeaderStyle * prev() const { return fancy(); }
871
872 TQString format( const KMMessage * message, const HeaderStrategy * strategy,
873 const TQString & vCardName, bool printing, bool topLevel ) const;
874 };
875
876 TQString EnterpriseHeaderStyle::format( const KMMessage * message,
877 const HeaderStrategy * strategy,
878 const TQString & vCardName, bool printing, bool topLevel ) const {
879 if ( !message ) return TQString();
880 if ( !strategy )
881 strategy = HeaderStrategy::brief();
882
883 // The direction of the header is determined according to the direction
884 // of the application layout.
885
886 TQString dir = TQApplication::reverseLayout() ? "rtl" : "ltr" ;
887
888 // However, the direction of the message subject within the header is
889 // determined according to the contents of the subject itself. Since
890 // the "Re:" and "Fwd:" prefixes would always cause the subject to be
891 // considered left-to-right, they are ignored when determining its
892 // direction.
893
894 TQString subjectDir;
895 if (!message->subject().isEmpty())
896 subjectDir = directionOf( message->cleanSubject() );
897 else
898 subjectDir = directionOf( i18n("No Subject") );
899
900 // colors depend on if its encapsulated or not
901 TQColor fontColor(TQt::white);
902 TQString linkColor = "class =\"white\"";
903 const TQColor activeColor = tqApp->palette().active().highlight();
904 TQColor activeColorDark = activeColor.dark(130);
905 // reverse colors for encapsulated
906 if( !topLevel ){
907 activeColorDark = activeColor.dark(50);
908 fontColor = TQColor(TQt::black);
909 linkColor = "class =\"black\"";
910 }
911
912 // Prepare the date string (when printing always use the localized date)
913 TQString dateString;
914 if( printing ) {
915 TQDateTime dateTime;
916 TDELocale * locale = TDEGlobal::locale();
917 dateTime.setTime_t( message->date() );
918 dateString = locale->formatDateTime( dateTime );
919 } else {
920 dateString = message->dateStr();
921 }
922
923 TQString imgpath(locate("data","kmail/pics/"));
924 imgpath.append("enterprise_");
925 const TQString borderSettings(" padding-top: 0px; padding-bottom: 0px; border-width: 0px ");
926 TQString headerStr ("");
927
928 // 3D borders
929 if(topLevel)
930 headerStr +=
931 "<div style=\"position: fixed; top: 0px; left: 0px; background-color: #606060; "
932 "width: 10px; min-height: 100%;\">&nbsp;</div>"
933 "<div style=\"position: fixed; top: 0px; right: 0px; background-color: #606060; "
934 "width: 10px; min-height: 100%;\">&nbsp;</div>";
935
936 headerStr += ""
937 "<div style=\"margin-left: 10px; top: 0px;\"><span style=\"font-size: 10px; font-weight: bold;\">"+dateString+"</span></div>"
938 // #0057ae
939 "<table style=\"background: "+activeColorDark.name()+"; border-collapse:collapse; top: 14px; min-width: 200px; \" cellpadding=0> \n"
940 " <tr> \n"
941 " <td style=\"min-width: 6px; background-image: url("+imgpath+"top_left.png); \"></td> \n"
942 " <td style=\"height: 6px; width: 100%; background: url("+imgpath+"top.png); \"></td> \n"
943 " <td style=\"min-width: 6px; background: url("+imgpath+"top_right.png); \"></td> </tr> \n"
944 " <tr> \n"
945 " <td style=\"min-width: 6px; max-width: 6px; background: url("+imgpath+"left.png); \"></td> \n"
946 " <td style=\"\"> \n";
947
948 headerStr +=
949 " <div class=\"noprint\" style=\"z-index: 1; float:right; position: relative; top: -35px; right: 20px ;\">\n"
950 " <img src=\""+imgpath+"icon.png\">\n"
951 " </div>\n";
952
953 headerStr +=
954 " <table style=\"color: "+fontColor.name()+" ! important; margin: 1px; border-spacing: 0px;\" cellpadding=0> \n";
955
956 // subject
957 //strToHtml( message->subject() )
958 if ( strategy->showHeader( "subject" ) ){
959 headerStr +=
960 " <tr> \n"
961 " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; "+borderSettings+"\"></td> \n"
962 " <td style=\"font-weight: bolder; font-size: 120%; padding-right: 91px; "+borderSettings+"\">"+message->subject()+"</td> \n"
963 " </tr> \n";
964 }
965
966 // from
967 if ( strategy->showHeader( "from" ) ){
968 TQString fromStr = message->from();
969 if ( fromStr.isEmpty() ) // no valid email in from, maybe just a name
970 fromStr = message->fromStrip(); // let's use that
971 // TODO vcard
972 TQString fromPart = KMMessage::emailAddrAsAnchor( fromStr, true, linkColor );
973 if ( !vCardName.isEmpty() )
974 fromPart += "&nbsp;&nbsp;<a href=\"" + vCardName + "\" "+linkColor+">" + i18n("[vCard]") + "</a>";
975 //TODO strategy date
976 //if ( strategy->showHeader( "date" ) )
977 headerStr +=
978 " <tr> \n"
979 " <td style=\"font-size: 6px; padding-left: 5px; padding-right: 24px; text-align: right; "+borderSettings+"\">"+i18n("From: ")+"</td> \n"
980 " <td style=\""+borderSettings+"\">"+ fromPart +"</td> "
981 " </tr> ";
982 }
983
984 // to line
985 if( strategy->showHeader( "to" ) )
986 headerStr +=
987 " <tr> "
988 " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("To: ") + "</td> "
989 " <td style=\"" + borderSettings + "\">" +
990 KMMessage::emailAddrAsAnchor( message->to(), false, linkColor ) +
991 " </td> "
992 " </tr>\n";
993
994 // cc line, if any
995 if ( strategy->showHeader( "cc" ) && !message->cc().isEmpty() )
996 headerStr +=
997 " <tr> "
998 " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("CC: ") + "</td> "
999 " <td style=\"" + borderSettings + "\">" +
1000 KMMessage::emailAddrAsAnchor( message->cc(), false, linkColor ) +
1001 " </td> "
1002 " </tr>\n";
1003
1004 // bcc line, if any
1005 if ( strategy->showHeader( "bcc" ) && !message->bcc().isEmpty() )
1006 headerStr +=
1007 " <tr> "
1008 " <td style=\"font-size: 6px; text-align: right; padding-left: 5px; padding-right: 24px; " + borderSettings + "\">" + i18n("BCC: ") + "</td> "
1009 " <td style=\"" + borderSettings + "\">" +
1010 KMMessage::emailAddrAsAnchor( message->bcc(), false, linkColor ) +
1011 " </td> "
1012 " </tr>\n";
1013
1014 // header-bottom
1015 headerStr +=
1016 " </table> \n"
1017 " </td> \n"
1018 " <td style=\"min-width: 6px; max-height: 15px; background: url("+imgpath+"right.png); \"></td> \n"
1019 " </tr> \n"
1020 " <tr> \n"
1021 " <td style=\"min-width: 6px; background: url("+imgpath+"s_left.png); \"></td> \n"
1022 " <td style=\"height: 35px; width: 80%; background: url("+imgpath+"sbar.png);\"> \n"
1023 " <img src=\""+imgpath+"sw.png\" style=\"margin: 0px; height: 30px; overflow:hidden; \"> \n"
1024 " <img src=\""+imgpath+"sp_right.png\" style=\"float: right; \"> </td> \n"
1025 " <td style=\"min-width: 6px; background: url("+imgpath+"s_right.png); \"></td> \n"
1026 " </tr> \n"
1027 " </table> \n";
1028
1029 // kmail icon
1030 if(topLevel) {
1031
1032 // attachments
1033 headerStr +=
1034 "<div class=\"noprint\" style=\"position: absolute; top: 60px; right: 20px; width: 91px; height: 200px;\">"
1035 "<div id=\"attachmentInjectionPoint\"></div>"
1036 "</div>\n";
1037 }
1038
1039 if ( printing ) {
1040 //provide a bit more left padding when printing
1041 //kolab/issue3254 (printed mail cut at the left side)
1042 headerStr += "<div style=\"padding: 6px; padding-left: 10px;\">";
1043 } else {
1044 headerStr += "<div style=\"padding: 6px;\">";
1045 }
1046
1047 // TODO
1048 // spam status
1049 // ### iterate over the rest of strategy->headerToDisplay() (or
1050 // ### all headers if DefaultPolicy == Display) (elsewhere, too)
1051 return headerStr;
1052 }
1053
1054// #####################
1055
1056 //
1057 // HeaderStyle abstract base:
1058 //
1059
1060 HeaderStyle::HeaderStyle() {
1061
1062 }
1063
1064 HeaderStyle::~HeaderStyle() {
1065
1066 }
1067
1068 const HeaderStyle * HeaderStyle::create( Type type ) {
1069 switch ( type ) {
1070 case Brief: return brief();
1071 case Plain: return plain();
1072 case Fancy: return fancy();
1073 case Enterprise: return enterprise();
1074 }
1075 kdFatal( 5006 ) << "HeaderStyle::create(): Unknown header style ( type == "
1076 << (int)type << " ) requested!" << endl;
1077 return 0; // make compiler happy
1078 }
1079
1080 const HeaderStyle * HeaderStyle::create( const TQString & type ) {
1081 TQString lowerType = type.lower();
1082 if ( lowerType == "brief" ) return brief();
1083 if ( lowerType == "plain" ) return plain();
1084 if ( lowerType == "enterprise" ) return enterprise();
1085 //if ( lowerType == "fancy" ) return fancy(); // not needed, see below
1086 // don't kdFatal here, b/c the strings are user-provided
1087 // (TDEConfig), so fail gracefully to the default:
1088 return fancy();
1089 }
1090
1091 static const HeaderStyle * briefStyle = 0;
1092 static const HeaderStyle * plainStyle = 0;
1093 static const HeaderStyle * fancyStyle = 0;
1094 static const HeaderStyle * enterpriseStyle = 0;
1095
1096 const HeaderStyle * HeaderStyle::brief() {
1097 if ( !briefStyle )
1098 briefStyle = new BriefHeaderStyle();
1099 return briefStyle;
1100 }
1101
1102 const HeaderStyle * HeaderStyle::plain() {
1103 if ( !plainStyle )
1104 plainStyle = new PlainHeaderStyle();
1105 return plainStyle;
1106 }
1107
1108 const HeaderStyle * HeaderStyle::fancy() {
1109 if ( !fancyStyle )
1110 fancyStyle = new FancyHeaderStyle();
1111 return fancyStyle;
1112 }
1113
1114 const HeaderStyle * HeaderStyle::enterprise() {
1115 if ( !enterpriseStyle )
1116 enterpriseStyle = new EnterpriseHeaderStyle();
1117 return enterpriseStyle;
1118 }
1119
1120} // namespace KMail
::KIMProxy * imProxy()
Get a reference to KMail's KIMProxy instance.
Definition: kmkernel.cpp:2421
static KMKernel * self()
normal control stuff
Definition: kmkernel.h:259
This is a Mime Message.
Definition: kmmessage.h:68
TQString from() const
Get or set the 'From' header field.
Definition: kmmessage.cpp:2015
TQString bcc() const
Get or set the 'Bcc' header field.
Definition: kmmessage.cpp:1968
TQString to() const
Get or set the 'To' header field.
Definition: kmmessage.cpp:1894
TQString subject() const
Get or set the 'Subject' header field.
Definition: kmmessage.cpp:2049
static TQString emailAddrAsAnchor(const TQString &emailAddr, bool stripped=true, const TQString &cssStyle=TQString(), bool link=true)
Converts the email address(es) to (a) nice HTML mailto: anchor(s).
Definition: kmmessage.cpp:3840
TQString cc() const
Get or set the 'Cc' header field.
Definition: kmmessage.cpp:1940
TQString headerField(const TQCString &name) const
Returns the value of a header field with the given name.
Definition: kmmessage.cpp:2289
TQString replyTo() const
Get or set the 'ReplyTo' header field.
Definition: kmmessage.cpp:1919
TQCString dateShortStr() const
Returns the message date in asctime format or an empty string if the message lacks a Date header.
Definition: kmmessage.cpp:1815
DwHeaders & headers() const
get the DwHeaders (make sure to call setNeedsAssembly() function after directly modyfying internal da...
Definition: kmmessage.cpp:2546
TQString dateStr() const
Get or set the 'Date' header field.
Definition: kmmessage.cpp:1797
static SpamScores getSpamScores(const KMMessage *message)
Extract scores from known anti-spam headers.
folderdiaquotatab.h
Definition: aboutdata.cpp:40