2 * Copyright (C) 2006 Dmitry Morozhnikov <dmiceman@mail.ru>
3 * Copyright (C) 2011 Sudhendu Kumar <sudhendu.kumar.roy@gmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "templateparser.h"
21 #include "globalsettings_base.h"
23 #include "customtemplates_kfg.h"
24 #include "templatesconfiguration_kfg.h"
25 #include "templatesconfiguration.h"
28 #include <messagecore/attachmentcollector.h>
29 #include <messagecore/imagecollector.h>
30 #include <messagecore/stringutil.h>
32 #include <messageviewer/objecttreeparser.h>
34 #include <KPIMIdentities/Identity>
35 #include <KPIMIdentities/IdentityManager>
37 #include <KCalendarSystem>
41 #include <KMessageBox>
52 namespace TemplateParser
{
54 static const int PipeTimeout
= 15 * 1000;
56 QTextCodec
*selectCharset( const QStringList
&charsets
, const QString
&text
)
58 foreach ( const QString
&name
, charsets
) {
59 // We use KCharsets::codecForName() instead of QTextCodec::codecForName() here, because
60 // the former knows us-ascii is latin1.
63 if ( name
== QLatin1String( "locale" ) ) {
64 codec
= QTextCodec::codecForLocale();
66 codec
= KGlobal::charsets()->codecForName( name
, ok
);
69 kWarning() << "Could not get text codec for charset" << name
;
72 if( codec
->canEncode( text
) ) {
73 // Special check for us-ascii (needed because us-ascii is not exactly latin1).
74 if( name
== QLatin1String( "us-ascii" ) && !KMime::isUsAscii( text
) ) {
77 kDebug() << "Chosen charset" << name
<< codec
->name();
81 kDebug() << "No appropriate charset found.";
82 return KGlobal::charsets()->codecForName( "utf-8" );
85 TemplateParser::TemplateParser( const KMime::Message::Ptr
&amsg
, const Mode amode
) :
86 mMode( amode
), mIdentity( 0 ),
87 mAllowDecryption( true ),
88 mDebug( false ), mQuoteString( "> " ), m_identityManager( 0 ),
91 mQuotes( ReplyAsOriginalMessage
)
95 mEmptySource
= new MessageViewer::EmptySource
;
96 mEmptySource
->setAllowDecryption( mAllowDecryption
);
98 mOtp
= new MessageViewer::ObjectTreeParser( mEmptySource
);
99 mOtp
->setAllowAsync( false );
102 void TemplateParser::setSelection( const QString
&selection
)
104 mSelection
= selection
;
107 void TemplateParser::setAllowDecryption( const bool allowDecryption
)
109 mAllowDecryption
= allowDecryption
;
110 mEmptySource
->setAllowDecryption( mAllowDecryption
);
113 bool TemplateParser::shouldStripSignature() const
115 // Only strip the signature when replying, it should be preserved when forwarding
117 ( mMode
== Reply
|| mMode
== ReplyAll
)
119 && GlobalSettings::self()->stripSignature()
124 void TemplateParser::setIdentityManager( KPIMIdentities::IdentityManager
*ident
)
126 m_identityManager
= ident
;
129 void TemplateParser::setCharsets( const QStringList
&charsets
)
131 m_charsets
= charsets
;
134 TemplateParser::~TemplateParser()
139 int TemplateParser::parseQuotes( const QString
&prefix
, const QString
&str
,
140 QString
"e
) const
142 int pos
= prefix
.length();
144 int str_len
= str
.length();
146 // Also allow the german lower double-quote sign as quote separator, not only
147 // the standard ASCII quote ("). This fixes bug 166728.
148 QList
< QChar
> quoteChars
;
149 quoteChars
.append( '"' );
150 quoteChars
.append( 0x201C );
152 QChar
prev( QChar::Null
);
157 while ( pos
< str_len
) {
163 if ( !prev
.isNull() ) {
169 } else if ( quoteChars
.contains( c
) ) {
180 QString
TemplateParser::getFName( const QString
&str
)
183 // if there is ',' in name, than format is 'Last, First'
184 // else format is 'First Last'
185 // last resort -- return 'name' from 'name@domain'
188 if ( ( sep_pos
= str
.indexOf( QLatin1Char( '@' ) ) ) > 0 ) {
190 for ( i
= ( sep_pos
- 1 ); i
>= 0; --i
) {
192 if ( c
.isLetterOrNumber() ) {
198 } else if ( ( sep_pos
= str
.indexOf( QLatin1Char( ',' ) ) ) > 0 ) {
201 const int strLength( str
.length() );
202 for ( i
= sep_pos
; i
< strLength
; ++i
) {
204 if ( c
.isLetterOrNumber() ) {
207 } else if ( begin
) {
213 const int strLength( str
.length() );
214 for ( i
= 0; i
< strLength
; ++i
) {
216 if ( c
.isLetterOrNumber() ) {
226 QString
TemplateParser::getLName( const QString
&str
)
229 // if there is ',' in name, than format is 'Last, First'
230 // else format is 'First Last'
233 if ( ( sep_pos
= str
.indexOf( QLatin1Char( ',' ) ) ) > 0 ) {
235 for ( i
= sep_pos
; i
>= 0; --i
) {
237 if ( c
.isLetterOrNumber() ) {
244 if ( ( sep_pos
= str
.indexOf( QLatin1Char( ' ' ) ) ) > 0 ) {
246 const int strLength( str
.length() );
247 for ( int i
= sep_pos
; i
< strLength
; ++i
) {
249 if ( c
.isLetterOrNumber() ) {
252 } else if ( begin
) {
261 void TemplateParser::process( const KMime::Message::Ptr
&aorig_msg
,
262 const Akonadi::Collection
& afolder
)
264 if( aorig_msg
== 0 ) {
265 kDebug() << "aorig_msg == 0!";
268 mOrigMsg
= aorig_msg
;
270 const QString tmpl
= findTemplate();
271 if ( tmpl
.isEmpty() ) {
274 processWithTemplate( tmpl
);
277 void TemplateParser::process( const QString
&tmplName
, const KMime::Message::Ptr
&aorig_msg
,
278 const Akonadi::Collection
&afolder
)
280 mOrigMsg
= aorig_msg
;
282 const QString tmpl
= findCustomTemplate( tmplName
);
283 processWithTemplate( tmpl
);
286 void TemplateParser::processWithIdentity( uint uoid
, const KMime::Message::Ptr
&aorig_msg
,
287 const Akonadi::Collection
&afolder
)
290 process( aorig_msg
, afolder
);
293 void TemplateParser::processWithTemplate( const QString
&tmpl
)
295 mOtp
->parseObjectTree( mOrigMsg
.get() );
296 const int tmpl_len
= tmpl
.length();
297 QString plainBody
, htmlBody
;
300 for ( int i
= 0; i
< tmpl_len
; ++i
) {
302 // kDebug() << "Next char: " << c;
304 const QString cmd
= tmpl
.mid( i
+ 1 );
306 if ( cmd
.startsWith( QLatin1Char( '-' ) ) ) {
308 kDebug() << "Command: -";
312 } else if ( cmd
.startsWith( QLatin1String( "REM=" ) ) ) {
314 kDebug() << "Command: REM=";
316 int len
= parseQuotes( "REM=", cmd
, q
);
319 } else if ( cmd
.startsWith( QLatin1String( "INSERT=" ) ) ) {
320 // insert content of specified file as is
321 kDebug() << "Command: INSERT=";
323 int len
= parseQuotes( "INSERT=", cmd
, q
);
325 QString path
= KShell::tildeExpand( q
);
326 QFileInfo
finfo( path
);
327 if ( finfo
.isRelative() ) {
328 path
= QDir::homePath();
333 if ( file
.open( QIODevice::ReadOnly
) ) {
334 const QByteArray content
= file
.readAll();
335 const QString str
= QString::fromLocal8Bit( content
, content
.size() );
336 plainBody
.append( str
);
337 const QString body
= plainToHtml( str
);
338 htmlBody
.append( body
);
339 } else if ( mDebug
) {
343 "Cannot insert content from file %1: %2", path
, file
.errorString() ) );
346 } else if ( cmd
.startsWith( QLatin1String( "SYSTEM=" ) ) ) {
347 // insert content of specified file as is
348 kDebug() << "Command: SYSTEM=";
350 int len
= parseQuotes( "SYSTEM=", cmd
, q
);
352 const QString pipe_cmd
= q
;
353 const QString str
= pipe( pipe_cmd
, "" );
354 plainBody
.append( str
);
355 const QString body
= plainToHtml( str
);
356 htmlBody
.append( body
);
358 } else if ( cmd
.startsWith( QLatin1String( "PUT=" ) ) ) {
359 // insert content of specified file as is
360 kDebug() << "Command: PUT=";
362 int len
= parseQuotes( "PUT=", cmd
, q
);
364 QString path
= KShell::tildeExpand( q
);
365 QFileInfo
finfo( path
);
366 if ( finfo
.isRelative() ) {
367 path
= QDir::homePath();
372 if ( file
.open( QIODevice::ReadOnly
) ) {
373 const QByteArray content
= file
.readAll();
374 plainBody
.append( QString::fromLocal8Bit( content
, content
.size() ) );
376 const QString body
= plainToHtml( QString::fromLocal8Bit( content
, content
.size() ) );
377 htmlBody
.append( body
);
378 } else if ( mDebug
) {
382 "Cannot insert content from file %1: %2", path
, file
.errorString() ) );
385 } else if ( cmd
.startsWith( QLatin1String( "QUOTEPIPE=" ) ) ) {
386 // pipe message body through command and insert it as quotation
387 kDebug() << "Command: QUOTEPIPE=";
389 int len
= parseQuotes( "QUOTEPIPE=", cmd
, q
);
391 const QString pipe_cmd
= q
;
393 const QString plainStr
=
394 pipe( pipe_cmd
, plainMessageText( shouldStripSignature(), NoSelectionAllowed
) );
395 QString plainQuote
= quotedPlainText( plainStr
);
396 if ( plainQuote
.endsWith( '\n' ) ) {
397 plainQuote
.chop( 1 );
399 plainBody
.append( plainQuote
);
401 const QString htmlStr
=
402 pipe( pipe_cmd
, htmlMessageText( shouldStripSignature(), NoSelectionAllowed
) );
403 const QString htmlQuote
= quotedHtmlText( htmlStr
);
404 htmlBody
.append( htmlQuote
);
407 } else if ( cmd
.startsWith( QLatin1String( "QUOTE" ) ) ) {
408 kDebug() << "Command: QUOTE";
409 i
+= strlen( "QUOTE" );
412 quotedPlainText( plainMessageText( shouldStripSignature(), SelectionAllowed
) );
413 if ( plainQuote
.endsWith( '\n' ) ) {
414 plainQuote
.chop( 1 );
416 plainBody
.append( plainQuote
);
418 const QString htmlQuote
=
419 quotedHtmlText( htmlMessageText( shouldStripSignature(), SelectionAllowed
) );
420 htmlBody
.append( htmlQuote
);
423 } else if ( cmd
.startsWith( QLatin1String( "FORCEDPLAIN" ) ) ) {
424 kDebug() << "Command: FORCEDPLAIN";
425 mQuotes
= ReplyAsPlain
;
426 i
+= strlen( "FORCEDPLAIN" );
428 } else if ( cmd
.startsWith( QLatin1String( "FORCEDHTML" ) ) ) {
429 kDebug() << "Command: FORCEDHTML";
430 mQuotes
= ReplyAsHtml
;
431 i
+= strlen( "FORCEDHTML" );
433 } else if ( cmd
.startsWith( QLatin1String( "QHEADERS" ) ) ) {
434 kDebug() << "Command: QHEADERS";
435 i
+= strlen( "QHEADERS" );
438 quotedPlainText( MessageCore::StringUtil::headerAsSendableString( mOrigMsg
) );
439 if ( plainQuote
.endsWith( '\n' ) ) {
440 plainQuote
.chop( 1 );
442 plainBody
.append( plainQuote
);
444 const QString htmlQuote
=
445 quotedHtmlText( MessageCore::StringUtil::headerAsSendableString( mOrigMsg
) );
446 const QString str
= plainToHtml( htmlQuote
);
447 htmlBody
.append( str
);
450 } else if ( cmd
.startsWith( QLatin1String( "HEADERS" ) ) ) {
451 kDebug() << "Command: HEADERS";
452 i
+= strlen( "HEADERS" );
454 const QString str
= MessageCore::StringUtil::headerAsSendableString( mOrigMsg
);
455 plainBody
.append( str
);
456 const QString body
= plainToHtml( str
);
457 htmlBody
.append( body
);
460 } else if ( cmd
.startsWith( QLatin1String( "TEXTPIPE=" ) ) ) {
461 // pipe message body through command and insert it as is
462 kDebug() << "Command: TEXTPIPE=";
464 int len
= parseQuotes( "TEXTPIPE=", cmd
, q
);
466 const QString pipe_cmd
= q
;
468 const QString plainStr
=
469 pipe( pipe_cmd
, plainMessageText( shouldStripSignature(), NoSelectionAllowed
) );
470 plainBody
.append( plainStr
);
472 const QString htmlStr
=
473 pipe( pipe_cmd
, htmlMessageText( shouldStripSignature(), NoSelectionAllowed
) );
474 htmlBody
.append( htmlStr
);
477 } else if ( cmd
.startsWith( QLatin1String( "MSGPIPE=" ) ) ) {
478 // pipe full message through command and insert result as is
479 kDebug() << "Command: MSGPIPE=";
481 int len
= parseQuotes( "MSGPIPE=", cmd
, q
);
484 QString pipe_cmd
= q
;
485 const QString str
= pipe( pipe_cmd
, mOrigMsg
->encodedContent() );
486 plainBody
.append( str
);
488 const QString body
= plainToHtml( str
);
489 htmlBody
.append( body
);
492 } else if ( cmd
.startsWith( QLatin1String( "BODYPIPE=" ) ) ) {
493 // pipe message body generated so far through command and insert result as is
494 kDebug() << "Command: BODYPIPE=";
496 int len
= parseQuotes( "BODYPIPE=", cmd
, q
);
498 const QString pipe_cmd
= q
;
499 const QString plainStr
= pipe( pipe_cmd
, plainBody
);
500 plainBody
.append( plainStr
);
502 const QString htmlStr
= pipe( pipe_cmd
, htmlBody
);
503 const QString body
= plainToHtml( htmlStr
);
504 htmlBody
.append( body
);
506 } else if ( cmd
.startsWith( QLatin1String( "CLEARPIPE=" ) ) ) {
507 // pipe message body generated so far through command and
508 // insert result as is replacing current body
509 kDebug() << "Command: CLEARPIPE=";
511 int len
= parseQuotes( "CLEARPIPE=", cmd
, q
);
513 const QString pipe_cmd
= q
;
514 const QString plainStr
= pipe( pipe_cmd
, plainBody
);
515 plainBody
= plainStr
;
517 const QString htmlStr
= pipe( pipe_cmd
, htmlBody
);
520 KMime::Headers::Generic
*header
=
521 new KMime::Headers::Generic( "X-KMail-CursorPos", mMsg
.get(),
522 QString::number( 0 ), "utf-8" );
523 mMsg
->setHeader( header
);
525 } else if ( cmd
.startsWith( QLatin1String( "TEXT" ) ) ) {
526 kDebug() << "Command: TEXT";
527 i
+= strlen( "TEXT" );
529 const QString plainStr
= plainMessageText( shouldStripSignature(), NoSelectionAllowed
);
530 plainBody
.append( plainStr
);
532 const QString htmlStr
= htmlMessageText( shouldStripSignature(), NoSelectionAllowed
);
533 htmlBody
.append( htmlStr
);
536 } else if ( cmd
.startsWith( QLatin1String( "OTEXTSIZE" ) ) ) {
537 kDebug() << "Command: OTEXTSIZE";
538 i
+= strlen( "OTEXTSIZE" );
540 const QString str
= QString::fromLatin1( "%1" ).arg( mOrigMsg
->body().length() );
541 plainBody
.append( str
);
542 const QString body
= plainToHtml( str
);
543 htmlBody
.append( body
);
546 } else if ( cmd
.startsWith( QLatin1String( "OTEXT" ) ) ) {
547 kDebug() << "Command: OTEXT";
548 i
+= strlen( "OTEXT" );
550 const QString plainStr
= plainMessageText( shouldStripSignature(), NoSelectionAllowed
);
551 plainBody
.append( plainStr
);
553 const QString htmlStr
= htmlMessageText( shouldStripSignature(), NoSelectionAllowed
);
554 htmlBody
.append( htmlStr
);
557 } else if ( cmd
.startsWith( QLatin1String( "OADDRESSEESADDR" ) ) ) {
558 kDebug() << "Command: OADDRESSEESADDR";
559 i
+= strlen( "OADDRESSEESADDR" );
561 const QString to
= mOrigMsg
->to()->asUnicodeString();
562 const QString cc
= mOrigMsg
->cc()->asUnicodeString();
563 if ( !to
.isEmpty() ) {
564 QString toLine
= i18nc( "@item:intext email To", "To:" ) + QLatin1Char( ' ' ) + to
;
565 plainBody
.append( toLine
);
566 const QString body
= plainToHtml( toLine
);
567 htmlBody
.append( body
);
569 if ( !to
.isEmpty() && !cc
.isEmpty() ) {
570 plainBody
.append( QLatin1Char( '\n' ) );
571 const QString str
= plainToHtml( QString( QLatin1Char( '\n' ) ) );
572 htmlBody
.append( str
);
574 if ( !cc
.isEmpty() ) {
575 QString ccLine
= i18nc( "@item:intext email CC", "CC:" ) + QLatin1Char( ' ' ) + cc
;
576 plainBody
.append( ccLine
);
577 const QString str
= plainToHtml( ccLine
);
578 htmlBody
.append( str
);
582 } else if ( cmd
.startsWith( QLatin1String( "CCADDR" ) ) ) {
583 kDebug() << "Command: CCADDR";
584 i
+= strlen( "CCADDR" );
585 const QString str
= mMsg
->cc()->asUnicodeString();
586 plainBody
.append( str
);
587 const QString body
= plainToHtml( str
);
588 htmlBody
.append( body
);
590 } else if ( cmd
.startsWith( QLatin1String( "CCNAME" ) ) ) {
591 kDebug() << "Command: CCNAME";
592 i
+= strlen( "CCNAME" );
594 MessageCore::StringUtil::stripEmailAddr( mMsg
->cc()->asUnicodeString( ) );
595 plainBody
.append( str
);
596 const QString body
= plainToHtml( str
);
597 htmlBody
.append( body
);
599 } else if ( cmd
.startsWith( QLatin1String( "CCFNAME" ) ) ) {
600 kDebug() << "Command: CCFNAME";
601 i
+= strlen( "CCFNAME" );
603 MessageCore::StringUtil::stripEmailAddr( mMsg
->cc()->asUnicodeString( ) );
604 plainBody
.append( getFName( str
) );
605 const QString body
= plainToHtml( getFName( str
) );
606 htmlBody
.append( body
);
608 } else if ( cmd
.startsWith( QLatin1String( "CCLNAME" ) ) ) {
609 kDebug() << "Command: CCLNAME";
610 i
+= strlen( "CCLNAME" );
612 MessageCore::StringUtil::stripEmailAddr( mMsg
->cc()->asUnicodeString( ) );
613 plainBody
.append( getLName( str
) );
614 const QString body
= plainToHtml( getLName( str
) );
615 htmlBody
.append( body
);
617 } else if ( cmd
.startsWith( QLatin1String( "TOADDR" ) ) ) {
618 kDebug() << "Command: TOADDR";
619 i
+= strlen( "TOADDR" );
620 const QString str
= mMsg
->to()->asUnicodeString();
621 plainBody
.append( str
);
622 const QString body
= plainToHtml( str
);
623 htmlBody
.append( body
);
625 } else if ( cmd
.startsWith( QLatin1String( "TONAME" ) ) ) {
626 kDebug() << "Command: TONAME";
627 i
+= strlen( "TONAME" );
629 MessageCore::StringUtil::stripEmailAddr( mMsg
->to()->asUnicodeString( ) );
630 plainBody
.append( str
);
631 const QString body
= plainToHtml( str
);
632 htmlBody
.append( body
);
634 } else if ( cmd
.startsWith( QLatin1String( "TOFNAME" ) ) ) {
635 kDebug() << "Command: TOFNAME";
636 i
+= strlen( "TOFNAME" );
638 MessageCore::StringUtil::stripEmailAddr( mMsg
->to()->asUnicodeString( ) );
639 plainBody
.append( getFName( str
) );
640 const QString body
= plainToHtml( getFName( str
) );
641 htmlBody
.append( body
);
643 } else if ( cmd
.startsWith( QLatin1String( "TOLNAME" ) ) ) {
644 kDebug() << "Command: TOLNAME";
645 i
+= strlen( "TOLNAME" );
647 MessageCore::StringUtil::stripEmailAddr( mMsg
->to()->asUnicodeString( ) );
648 plainBody
.append( getLName( str
) );
649 const QString body
= plainToHtml( getLName( str
) );
650 htmlBody
.append( body
);
652 } else if ( cmd
.startsWith( QLatin1String( "TOLIST" ) ) ) {
653 kDebug() << "Command: TOLIST";
654 i
+= strlen( "TOLIST" );
655 const QString str
= mMsg
->to()->asUnicodeString();
656 plainBody
.append( str
);
657 const QString body
= plainToHtml( str
);
658 htmlBody
.append( body
);
660 } else if ( cmd
.startsWith( QLatin1String( "FROMADDR" ) ) ) {
661 kDebug() << "Command: FROMADDR";
662 i
+= strlen( "FROMADDR" );
663 const QString str
= mMsg
->from()->asUnicodeString();
664 plainBody
.append( str
);
665 const QString body
= plainToHtml( str
);
666 htmlBody
.append( body
);
668 } else if ( cmd
.startsWith( QLatin1String( "FROMNAME" ) ) ) {
669 kDebug() << "Command: FROMNAME";
670 i
+= strlen( "FROMNAME" );
672 MessageCore::StringUtil::stripEmailAddr( mMsg
->from()->asUnicodeString( ) );
673 plainBody
.append( str
);
674 const QString body
= plainToHtml( str
);
675 htmlBody
.append( body
);
677 } else if ( cmd
.startsWith( QLatin1String( "FROMFNAME" ) ) ) {
678 kDebug() << "Command: FROMFNAME";
679 i
+= strlen( "FROMFNAME" );
681 MessageCore::StringUtil::stripEmailAddr( mMsg
->from()->asUnicodeString( ) );
682 plainBody
.append( getFName( str
) );
683 const QString body
= plainToHtml( getFName( str
) );
684 htmlBody
.append( body
);
686 } else if ( cmd
.startsWith( QLatin1String( "FROMLNAME" ) ) ) {
687 kDebug() << "Command: FROMLNAME";
688 i
+= strlen( "FROMLNAME" );
690 MessageCore::StringUtil::stripEmailAddr( mMsg
->from()->asUnicodeString( ) );
691 plainBody
.append( getLName( str
) );
692 const QString body
= plainToHtml( getLName( str
) );
693 htmlBody
.append( body
);
695 } else if ( cmd
.startsWith( QLatin1String( "FULLSUBJECT" ) ) ) {
696 kDebug() << "Command: FULLSUBJECT";
697 i
+= strlen( "FULLSUBJECT" );
698 const QString str
= mMsg
->subject()->asUnicodeString();
699 plainBody
.append( str
);
700 const QString body
= plainToHtml( str
);
701 htmlBody
.append( body
);
703 } else if ( cmd
.startsWith( QLatin1String( "FULLSUBJ" ) ) ) {
704 kDebug() << "Command: FULLSUBJ";
705 i
+= strlen( "FULLSUBJ" );
706 const QString str
= mMsg
->subject()->asUnicodeString();
707 plainBody
.append( str
);
708 const QString body
= plainToHtml( str
);
709 htmlBody
.append( body
);
711 } else if ( cmd
.startsWith( QLatin1String( "MSGID" ) ) ) {
712 kDebug() << "Command: MSGID";
713 i
+= strlen( "MSGID" );
714 const QString str
= mMsg
->messageID()->asUnicodeString();
715 plainBody
.append( str
);
716 const QString body
= plainToHtml( str
);
717 htmlBody
.append( body
);
719 } else if ( cmd
.startsWith( QLatin1String( "OHEADER=" ) ) ) {
720 // insert specified content of header from original message
721 kDebug() << "Command: OHEADER=";
723 int len
= parseQuotes( "OHEADER=", cmd
, q
);
726 const QString hdr
= q
;
728 mOrigMsg
->headerByType( hdr
.toLocal8Bit() ) ?
729 mOrigMsg
->headerByType( hdr
.toLocal8Bit() )->asUnicodeString() :
731 plainBody
.append( str
);
732 const QString body
= plainToHtml( str
);
733 htmlBody
.append( body
);
736 } else if ( cmd
.startsWith( QLatin1String( "HEADER=" ) ) ) {
737 // insert specified content of header from current message
738 kDebug() << "Command: HEADER=";
740 int len
= parseQuotes( "HEADER=", cmd
, q
);
742 const QString hdr
= q
;
744 mMsg
->headerByType( hdr
.toLocal8Bit() ) ?
745 mMsg
->headerByType( hdr
.toLocal8Bit() )->asUnicodeString() :
747 plainBody
.append( str
);
748 const QString body
= plainToHtml( str
);
749 htmlBody
.append( body
);
751 } else if ( cmd
.startsWith( QLatin1String( "HEADER( " ) ) ) {
752 // insert specified content of header from current message
753 kDebug() << "Command: HEADER(";
754 QRegExp re
= QRegExp( "^HEADER\\((.+)\\)" );
755 re
.setMinimal( true );
756 int res
= re
.indexIn( cmd
);
759 i
+= strlen( "HEADER( " );
761 i
+= re
.matchedLength();
762 const QString hdr
= re
.cap( 1 );
764 mMsg
->headerByType( hdr
.toLocal8Bit() ) ?
765 mMsg
->headerByType( hdr
.toLocal8Bit() )->asUnicodeString() :
767 plainBody
.append( str
);
768 const QString body
= plainToHtml( str
);
769 htmlBody
.append( body
);
772 } else if ( cmd
.startsWith( QLatin1String( "OCCADDR" ) ) ) {
773 kDebug() << "Command: OCCADDR";
774 i
+= strlen( "OCCADDR" );
776 const QString str
= mOrigMsg
->cc()->asUnicodeString();
777 plainBody
.append( str
);
778 const QString body
= plainToHtml( str
);
779 htmlBody
.append( body
);
782 } else if ( cmd
.startsWith( QLatin1String( "OCCNAME" ) ) ) {
783 kDebug() << "Command: OCCNAME";
784 i
+= strlen( "OCCNAME" );
787 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->cc()->asUnicodeString( ) );
788 plainBody
.append( str
);
789 const QString body
= plainToHtml( str
);
790 htmlBody
.append( body
);
793 } else if ( cmd
.startsWith( QLatin1String( "OCCFNAME" ) ) ) {
794 kDebug() << "Command: OCCFNAME";
795 i
+= strlen( "OCCFNAME" );
798 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->cc()->asUnicodeString( ) );
799 plainBody
.append( getFName( str
) );
800 const QString body
= plainToHtml( getFName( str
) );
801 htmlBody
.append( body
);
804 } else if ( cmd
.startsWith( QLatin1String( "OCCLNAME" ) ) ) {
805 kDebug() << "Command: OCCLNAME";
806 i
+= strlen( "OCCLNAME" );
809 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->cc()->asUnicodeString( ) );
810 plainBody
.append( getLName( str
) );
811 const QString body
= plainToHtml( getLName( str
) );
812 htmlBody
.append( body
);
815 } else if ( cmd
.startsWith( QLatin1String( "OTOADDR" ) ) ) {
816 kDebug() << "Command: OTOADDR";
817 i
+= strlen( "OTOADDR" );
819 const QString str
= mOrigMsg
->to()->asUnicodeString();
820 plainBody
.append( str
);
821 const QString body
= plainToHtml( str
);
822 htmlBody
.append( body
);
825 } else if ( cmd
.startsWith( QLatin1String( "OTONAME" ) ) ) {
826 kDebug() << "Command: OTONAME";
827 i
+= strlen( "OTONAME" );
830 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->to()->asUnicodeString( ) );
831 plainBody
.append( str
);
832 const QString body
= plainToHtml( str
);
833 htmlBody
.append( body
);
836 } else if ( cmd
.startsWith( QLatin1String( "OTOFNAME" ) ) ) {
837 kDebug() << "Command: OTOFNAME";
838 i
+= strlen( "OTOFNAME" );
841 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->to()->asUnicodeString( ) );
842 plainBody
.append( getFName( str
) );
843 const QString body
= plainToHtml( getFName( str
) );
844 htmlBody
.append( body
);
847 } else if ( cmd
.startsWith( QLatin1String( "OTOLNAME" ) ) ) {
848 kDebug() << "Command: OTOLNAME";
849 i
+= strlen( "OTOLNAME" );
852 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->to()->asUnicodeString( ) );
853 plainBody
.append( getLName( str
) );
854 const QString body
= plainToHtml( getLName( str
) );
855 htmlBody
.append( body
);
858 } else if ( cmd
.startsWith( QLatin1String( "OTOLIST" ) ) ) {
859 kDebug() << "Command: OTOLIST";
860 i
+= strlen( "OTOLIST" );
862 const QString str
= mOrigMsg
->to()->asUnicodeString();
863 plainBody
.append( str
);
864 const QString body
= plainToHtml( str
);
865 htmlBody
.append( body
);
868 } else if ( cmd
.startsWith( QLatin1String( "OTO" ) ) ) {
869 kDebug() << "Command: OTO";
870 i
+= strlen( "OTO" );
872 const QString str
= mOrigMsg
->to()->asUnicodeString();
873 plainBody
.append( str
);
874 const QString body
= plainToHtml( str
);
875 htmlBody
.append( body
);
878 } else if ( cmd
.startsWith( QLatin1String( "OFROMADDR" ) ) ) {
879 kDebug() << "Command: OFROMADDR";
880 i
+= strlen( "OFROMADDR" );
882 const QString str
= mOrigMsg
->from()->asUnicodeString();
883 plainBody
.append( str
);
884 const QString body
= plainToHtml( str
);
885 htmlBody
.append( body
);
888 } else if ( cmd
.startsWith( QLatin1String( "OFROMNAME" ) ) ) {
889 kDebug() << "Command: OFROMNAME";
890 i
+= strlen( "OFROMNAME" );
893 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->from()->asUnicodeString() );
894 plainBody
.append( str
);
895 const QString body
= plainToHtml( str
);
896 htmlBody
.append( body
);
899 } else if ( cmd
.startsWith( QLatin1String( "OFROMFNAME" ) ) ) {
900 kDebug() << "Command: OFROMFNAME";
901 i
+= strlen( "OFROMFNAME" );
904 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->from()->asUnicodeString() );
905 plainBody
.append( getFName( str
) );
906 const QString body
= plainToHtml( getFName( str
) );
907 htmlBody
.append( body
);
910 } else if ( cmd
.startsWith( QLatin1String( "OFROMLNAME" ) ) ) {
911 kDebug() << "Command: OFROMLNAME";
912 i
+= strlen( "OFROMLNAME" );
915 MessageCore::StringUtil::stripEmailAddr( mOrigMsg
->from()->asUnicodeString() );
916 plainBody
.append( getLName( str
) );
917 const QString body
= plainToHtml( getLName( str
) );
918 htmlBody
.append( body
);
921 } else if ( cmd
.startsWith( QLatin1String( "OFULLSUBJECT" ) ) ) {
922 kDebug() << "Command: OFULLSUBJECT";
923 i
+= strlen( "OFULLSUBJECT" );
925 const QString str
= mOrigMsg
->subject()->asUnicodeString();
926 plainBody
.append( str
);
927 const QString body
= plainToHtml( str
);
928 htmlBody
.append( body
);
931 } else if ( cmd
.startsWith( QLatin1String( "OFULLSUBJ" ) ) ) {
932 kDebug() << "Command: OFULLSUBJ";
933 i
+= strlen( "OFULLSUBJ" );
935 const QString str
= mOrigMsg
->subject()->asUnicodeString();
936 plainBody
.append( str
);
937 const QString body
= plainToHtml( str
);
938 htmlBody
.append( body
);
941 } else if ( cmd
.startsWith( QLatin1String( "OMSGID" ) ) ) {
942 kDebug() << "Command: OMSGID";
943 i
+= strlen( "OMSGID" );
945 const QString str
= mOrigMsg
->messageID()->asUnicodeString();
946 plainBody
.append( str
);
947 const QString body
= plainToHtml( str
);
948 htmlBody
.append( body
);
951 } else if ( cmd
.startsWith( QLatin1String( "DATEEN" ) ) ) {
952 kDebug() << "Command: DATEEN";
953 i
+= strlen( "DATEEN" );
954 const QDateTime date
= QDateTime::currentDateTime();
955 KLocale
locale( "C" );
956 const QString str
= locale
.formatDate( date
.date(), KLocale::LongDate
);
957 plainBody
.append( str
);
958 const QString body
= plainToHtml( str
);
959 htmlBody
.append( body
);
961 } else if ( cmd
.startsWith( QLatin1String( "DATESHORT" ) ) ) {
962 kDebug() << "Command: DATESHORT";
963 i
+= strlen( "DATESHORT" );
964 const QDateTime date
= QDateTime::currentDateTime();
965 const QString str
= KGlobal::locale()->formatDate( date
.date(), KLocale::ShortDate
);
966 plainBody
.append( str
);
967 const QString body
= plainToHtml( str
);
968 htmlBody
.append( body
);
970 } else if ( cmd
.startsWith( QLatin1String( "DATE" ) ) ) {
971 kDebug() << "Command: DATE";
972 i
+= strlen( "DATE" );
973 const QDateTime date
= QDateTime::currentDateTime();
974 const QString str
= KGlobal::locale()->formatDate( date
.date(), KLocale::LongDate
);
975 plainBody
.append( str
);
976 const QString body
= plainToHtml( str
);
977 htmlBody
.append( body
);
979 } else if ( cmd
.startsWith( QLatin1String( "DOW" ) ) ) {
980 kDebug() << "Command: DOW";
981 i
+= strlen( "DOW" );
982 const QDateTime date
= QDateTime::currentDateTime();
983 const QString str
= KGlobal::locale()->calendar()->weekDayName( date
.date(),
984 KCalendarSystem::LongDayName
);
985 plainBody
.append( str
);
986 const QString body
= plainToHtml( str
);
987 htmlBody
.append( body
);
989 } else if ( cmd
.startsWith( QLatin1String( "TIMELONGEN" ) ) ) {
990 kDebug() << "Command: TIMELONGEN";
991 i
+= strlen( "TIMELONGEN" );
992 const QDateTime date
= QDateTime::currentDateTime();
993 KLocale
locale( "C" );
994 const QString str
= locale
.formatTime( date
.time(), true );
995 plainBody
.append( str
);
996 const QString body
= plainToHtml( str
);
997 htmlBody
.append( body
);
999 } else if ( cmd
.startsWith( QLatin1String( "TIMELONG" ) ) ) {
1000 kDebug() << "Command: TIMELONG";
1001 i
+= strlen( "TIMELONG" );
1002 const QDateTime date
= QDateTime::currentDateTime();
1003 const QString str
= KGlobal::locale()->formatTime( date
.time(), true );
1004 plainBody
.append( str
);
1005 const QString body
= plainToHtml( str
);
1006 htmlBody
.append( body
);
1008 } else if ( cmd
.startsWith( QLatin1String( "TIME" ) ) ) {
1009 kDebug() << "Command: TIME";
1010 i
+= strlen( "TIME" );
1011 const QDateTime date
= QDateTime::currentDateTime();
1012 const QString str
= KGlobal::locale()->formatTime( date
.time(), false );
1013 plainBody
.append( str
);
1014 const QString body
= plainToHtml( str
);
1015 htmlBody
.append( body
);
1017 } else if ( cmd
.startsWith( QLatin1String( "ODATEEN" ) ) ) {
1018 kDebug() << "Command: ODATEEN";
1019 i
+= strlen( "ODATEEN" );
1021 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1022 KLocale
locale( "C" );
1023 const QString str
= locale
.formatDate( date
.date(), KLocale::LongDate
);
1024 plainBody
.append( str
);
1025 const QString body
= plainToHtml( str
);
1026 htmlBody
.append( body
);
1029 } else if ( cmd
.startsWith( QLatin1String( "ODATESHORT" ) ) ) {
1030 kDebug() << "Command: ODATESHORT";
1031 i
+= strlen( "ODATESHORT" );
1033 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1034 const QString str
= KGlobal::locale()->formatDate( date
.date(), KLocale::ShortDate
);
1035 plainBody
.append( str
);
1036 const QString body
= plainToHtml( str
);
1037 htmlBody
.append( body
);
1040 } else if ( cmd
.startsWith( QLatin1String( "ODATE" ) ) ) {
1041 kDebug() << "Command: ODATE";
1042 i
+= strlen( "ODATE" );
1044 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1045 const QString str
= KGlobal::locale()->formatDate( date
.date(), KLocale::LongDate
);
1046 plainBody
.append( str
);
1047 const QString body
= plainToHtml( str
);
1048 htmlBody
.append( body
);
1051 } else if ( cmd
.startsWith( QLatin1String( "ODOW" ) ) ) {
1052 kDebug() << "Command: ODOW";
1053 i
+= strlen( "ODOW" );
1055 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1057 KGlobal::locale()->calendar()->weekDayName( date
.date(), KCalendarSystem::LongDayName
);
1058 plainBody
.append( str
);
1059 const QString body
= plainToHtml( str
);
1060 htmlBody
.append( body
);
1063 } else if ( cmd
.startsWith( QLatin1String( "OTIMELONGEN" ) ) ) {
1064 kDebug() << "Command: OTIMELONGEN";
1065 i
+= strlen( "OTIMELONGEN" );
1067 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1068 KLocale
locale( "C" );
1069 const QString str
= locale
.formatTime( date
.time(), true );
1070 plainBody
.append( str
);
1071 const QString body
= plainToHtml( str
);
1072 htmlBody
.append( body
);
1075 } else if ( cmd
.startsWith( QLatin1String( "OTIMELONG" ) ) ) {
1076 kDebug() << "Command: OTIMELONG";
1077 i
+= strlen( "OTIMELONG" );
1079 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1080 const QString str
= KGlobal::locale()->formatTime( date
.time(), true );
1081 plainBody
.append( str
);
1082 const QString body
= plainToHtml( str
);
1083 htmlBody
.append( body
);
1086 } else if ( cmd
.startsWith( QLatin1String( "OTIME" ) ) ) {
1087 kDebug() << "Command: OTIME";
1088 i
+= strlen( "OTIME" );
1090 const QDateTime date
= mOrigMsg
->date()->dateTime().dateTime();
1091 const QString str
= KGlobal::locale()->formatTime( date
.time(), false );
1092 plainBody
.append( str
);
1093 const QString body
= plainToHtml( str
);
1094 htmlBody
.append( body
);
1097 } else if ( cmd
.startsWith( QLatin1String( "BLANK" ) ) ) {
1099 kDebug() << "Command: BLANK";
1100 i
+= strlen( "BLANK" );
1102 } else if ( cmd
.startsWith( QLatin1String( "NOP" ) ) ) {
1104 kDebug() << "Command: NOP";
1105 i
+= strlen( "NOP" );
1107 } else if ( cmd
.startsWith( QLatin1String( "CLEAR" ) ) ) {
1108 // clear body buffer; not too useful yet
1109 kDebug() << "Command: CLEAR";
1110 i
+= strlen( "CLEAR" );
1113 KMime::Headers::Generic
*header
=
1114 new KMime::Headers::Generic( "X-KMail-CursorPos", mMsg
.get(),
1115 QString::number( 0 ), "utf-8" );
1116 mMsg
->setHeader( header
);
1117 } else if ( cmd
.startsWith( QLatin1String( "DEBUGOFF" ) ) ) {
1119 kDebug() << "Command: DEBUGOFF";
1120 i
+= strlen( "DEBUGOFF" );
1123 } else if ( cmd
.startsWith( QLatin1String( "DEBUG" ) ) ) {
1125 kDebug() << "Command: DEBUG";
1126 i
+= strlen( "DEBUG" );
1129 } else if ( cmd
.startsWith( QLatin1String( "CURSOR" ) ) ) {
1131 kDebug() << "Command: CURSOR";
1132 i
+= strlen( "CURSOR" );
1133 KMime::Headers::Generic
*header
=
1134 new KMime::Headers::Generic( "X-KMail-CursorPos", mMsg
.get(),
1135 QString::number( plainBody
.length() ), "utf-8" );
1136 mMsg
->setHeader( header
);
1137 //FIXME HTML part for header remaining
1138 } else if ( cmd
.startsWith( QLatin1String( "SIGNATURE" ) ) ) {
1139 kDebug() << "Command: SIGNATURE";
1140 i
+= strlen( "SIGNATURE" );
1141 plainBody
.append( getPlainSignature() );
1142 htmlBody
.append( getHtmlSignature() );
1145 // wrong command, do nothing
1146 plainBody
.append( c
);
1147 htmlBody
.append( c
);
1150 } else if ( dnl
&& ( c
== '\n' || c
== '\r' ) ) {
1152 if ( ( tmpl
.size() > i
+1 ) &&
1153 ( ( c
== '\n' && tmpl
[i
+ 1] == '\r' ) ||
1154 ( c
== '\r' && tmpl
[i
+ 1] == '\n' ) ) ) {
1160 plainBody
.append( c
);
1161 if( c
== '\n' || c
== '\r' ) {
1162 htmlBody
.append( QLatin1String( "<br />" ) );
1163 htmlBody
.append( c
);
1164 if( tmpl
.size() > i
+1 &&
1165 ( ( c
== '\n' && tmpl
[i
+ 1] == '\r' ) ||
1166 ( c
== '\r' && tmpl
[i
+ 1] == '\n' ) ) ) {
1167 htmlBody
.append( tmpl
[i
+ 1] );
1168 plainBody
.append( tmpl
[i
+ 1] );
1172 htmlBody
.append( c
);
1176 // Clear the HTML body if FORCEDPLAIN has set ReplyAsPlain, OR if,
1177 // there is no use of FORCED command but a configure setting has ReplyUsingHtml disabled,
1178 // OR the original mail has no HTML part.
1179 const KMime::Content
*content
= mOrigMsg
->mainBodyPart( "text/html" );
1180 if( mQuotes
== ReplyAsPlain
||
1181 ( mQuotes
!= ReplyAsHtml
&& !GlobalSettings::self()->replyUsingHtml() ) ||
1182 (!content
|| !content
->hasContent() ) ) {
1185 htmlBody
= makeValidHtml( htmlBody
);
1187 addProcessedBodyToMessage( plainBody
, htmlBody
);
1190 QString
TemplateParser::getPlainSignature() const
1192 const KPIMIdentities::Identity
&identity
=
1193 m_identityManager
->identityForUoid( mIdentity
);
1195 if ( identity
.isNull() ) {
1199 KPIMIdentities::Signature signature
=
1200 const_cast<KPIMIdentities::Identity
&>( identity
).signature();
1202 if ( signature
.type() == KPIMIdentities::Signature::Inlined
&&
1203 signature
.isInlinedHtml() ) {
1204 return signature
.toPlainText();
1206 return signature
.rawText();
1209 // TODO If %SIGNATURE command is on, then override it with signature from
1210 // "KMail configure->General->identity->signature".
1211 // There should be no two signatures.
1212 QString
TemplateParser::getHtmlSignature() const
1214 const KPIMIdentities::Identity
&identity
=
1215 m_identityManager
->identityForUoid( mIdentity
);
1216 if ( identity
.isNull() ) {
1220 KPIMIdentities::Signature signature
=
1221 const_cast<KPIMIdentities::Identity
&>( identity
).signature();
1223 if ( !signature
.isInlinedHtml() ) {
1224 Qt::escape( signature
.rawText() );
1225 return signature
.rawText().replace( QRegExp( "\n" ), "<br />" );
1227 return signature
.rawText();
1230 void TemplateParser::addProcessedBodyToMessage( const QString
&plainBody
,
1231 const QString
&htmlBody
) const
1233 // Get the attachments of the original mail
1234 MessageCore::AttachmentCollector ac
;
1235 ac
.collectAttachmentsFrom( mOrigMsg
.get() );
1237 MessageCore::ImageCollector ic
;
1238 ic
.collectImagesFrom( mOrigMsg
.get() );
1240 // Now, delete the old content and set the new content, which
1241 // is either only the new text or the new text with some attachments.
1242 KMime::Content::List parts
= mMsg
->contents();
1243 foreach ( KMime::Content
*content
, parts
) {
1244 mMsg
->removeContent( content
, true/*delete*/ );
1247 // Set To and CC from the template
1248 if ( !mTo
.isEmpty() ) {
1249 mMsg
->to()->fromUnicodeString( mMsg
->to()->asUnicodeString() + ',' + mTo
, "utf-8" );
1252 if ( !mCC
.isEmpty() ) {
1253 mMsg
->cc()->fromUnicodeString( mMsg
->cc()->asUnicodeString() + ',' + mCC
, "utf-8" );
1256 mMsg
->contentType()->clear(); // to get rid of old boundary
1258 const QByteArray boundary
= KMime::multiPartBoundary();
1259 KMime::Content
*const mainTextPart
=
1260 htmlBody
.isEmpty() ?
1261 createPlainPartContent( plainBody
) :
1262 createMultipartAlternativeContent( plainBody
, htmlBody
);
1263 mainTextPart
->assemble();
1265 KMime::Content
*textPart
= mainTextPart
;
1266 if ( !ic
.images().empty() ) {
1267 textPart
= createMultipartRelated( ic
, mainTextPart
);
1268 textPart
->assemble();
1271 // If we have some attachments, create a multipart/mixed mail and
1272 // add the normal body as well as the attachments
1273 KMime::Content
*mainPart
= textPart
;
1274 if ( !ac
.attachments().empty() && mMode
== Forward
) {
1275 mainPart
= createMultipartMixed( ac
, textPart
);
1276 mainPart
->assemble();
1279 mMsg
->setBody( mainPart
->encodedBody() );
1280 mMsg
->setHeader( mainPart
->contentType() );
1281 mMsg
->setHeader( mainPart
->contentTransferEncoding() );
1286 KMime::Content
*TemplateParser::createMultipartMixed( const MessageCore::AttachmentCollector
&ac
,
1287 KMime::Content
*textPart
) const
1289 KMime::Content
*mixedPart
= new KMime::Content( mMsg
.get() );
1290 const QByteArray boundary
= KMime::multiPartBoundary();
1291 mixedPart
->contentType()->setMimeType( "multipart/mixed" );
1292 mixedPart
->contentType()->setBoundary( boundary
);
1293 mixedPart
->contentTransferEncoding()->setEncoding( KMime::Headers::CE7Bit
);
1294 mixedPart
->addContent( textPart
);
1296 int attachmentNumber
= 1;
1297 foreach ( KMime::Content
*attachment
, ac
.attachments() ) {
1298 mixedPart
->addContent( attachment
);
1299 // If the content type has no name or filename parameter, add one, since otherwise the name
1300 // would be empty in the attachment view of the composer, which looks confusing
1301 if ( attachment
->contentType( false ) ) {
1302 if ( !attachment
->contentType()->hasParameter( "name" ) &&
1303 !attachment
->contentType()->hasParameter( "filename" ) ) {
1304 attachment
->contentType()->setParameter(
1305 "name", i18nc( "@item:intext", "Attachment %1", attachmentNumber
) );
1313 KMime::Content
*TemplateParser::createMultipartRelated( const MessageCore::ImageCollector
&ic
,
1314 KMime::Content
*mainTextPart
) const
1316 KMime::Content
*relatedPart
= new KMime::Content( mMsg
.get() );
1317 const QByteArray boundary
= KMime::multiPartBoundary();
1318 relatedPart
->contentType()->setMimeType( "multipart/related" );
1319 relatedPart
->contentType()->setBoundary( boundary
);
1320 relatedPart
->contentTransferEncoding()->setEncoding( KMime::Headers::CE7Bit
);
1321 relatedPart
->addContent( mainTextPart
);
1322 foreach ( KMime::Content
*image
, ic
.images() ) {
1323 kWarning() << "Adding" << image
->contentID() << "as an embedded image";
1324 relatedPart
->addContent( image
);
1329 KMime::Content
*TemplateParser::createPlainPartContent( const QString
&plainBody
) const
1331 KMime::Content
*textPart
= new KMime::Content( mMsg
.get() );
1332 textPart
->contentType()->setMimeType( "text/plain" );
1333 QTextCodec
*charset
= selectCharset( m_charsets
, plainBody
);
1334 textPart
->contentType()->setCharset( charset
->name() );
1335 textPart
->contentTransferEncoding()->setEncoding( KMime::Headers::CE8Bit
);
1336 textPart
->fromUnicodeString( plainBody
);
1340 KMime::Content
*TemplateParser::createMultipartAlternativeContent( const QString
&plainBody
,
1341 const QString
&htmlBody
) const
1343 KMime::Content
*multipartAlternative
= new KMime::Content( mMsg
.get() );
1344 multipartAlternative
->contentType()->setMimeType( "multipart/alternative" );
1345 const QByteArray boundary
= KMime::multiPartBoundary();
1346 multipartAlternative
->contentType()->setBoundary( boundary
);
1348 KMime::Content
*textPart
= createPlainPartContent( plainBody
);
1349 multipartAlternative
->addContent( textPart
);
1351 KMime::Content
*htmlPart
= new KMime::Content( mMsg
.get() );
1352 htmlPart
->contentType()->setMimeType( "text/html" );
1353 QTextCodec
*charset
= selectCharset( m_charsets
, htmlBody
);
1354 htmlPart
->contentType()->setCharset( charset
->name() );
1355 htmlPart
->contentTransferEncoding()->setEncoding( KMime::Headers::CE8Bit
);
1356 htmlPart
->fromUnicodeString( htmlBody
);
1357 multipartAlternative
->addContent( htmlPart
);
1359 return multipartAlternative
;
1362 QString
TemplateParser::findCustomTemplate( const QString
&tmplName
)
1365 CTemplates
t( tmplName
);
1368 const QString content
= t
.content();
1369 if ( !content
.isEmpty() ) {
1372 return findTemplate();
1375 return findTemplate();
1379 QString
TemplateParser::findTemplate()
1381 // kDebug() << "Trying to find template for mode" << mode;
1387 if ( !mFolder
.isValid() ) { // find folder message belongs to
1388 mFolder
= mMsg
->parentCollection();
1389 if ( !mFolder
.isValid() ) {
1391 mFolder
= mOrigMsg
->parentCollection();
1393 if ( !mFolder
.isValid() ) {
1394 kDebug() << "Oops! No folder for message";
1399 kDebug() << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO
;
1401 kDebug() << "Folder found:" << mFolder
;
1402 if ( mFolder
.isValid() ) { // only if a folder was found
1403 QString fid
= QString::number( mFolder
.id() );
1404 Templates
fconf( fid
);
1405 if ( fconf
.useCustomTemplates() ) { // does folder use custom templates?
1408 tmpl
= fconf
.templateNewMessage();
1411 tmpl
= fconf
.templateReply();
1414 tmpl
= fconf
.templateReplyAll();
1417 tmpl
= fconf
.templateForward();
1420 kDebug() << "Unknown message mode:" << mMode
;
1423 mQuoteString
= fconf
.quoteString();
1424 if ( !tmpl
.isEmpty() ) {
1425 return tmpl
; // use folder-specific template
1430 if ( !mIdentity
) { // find identity message belongs to
1431 kDebug() << "AKONADI PORT: verify Akonadi::Item() here " << Q_FUNC_INFO
;
1433 mIdentity
= identityUoid( mMsg
);
1434 if ( !mIdentity
&& mOrigMsg
) {
1435 kDebug() << "AKONADI PORT: verify Akonadi::Item() here " << Q_FUNC_INFO
;
1436 mIdentity
= identityUoid( mOrigMsg
);
1438 mIdentity
= m_identityManager
->identityForUoidOrDefault( mIdentity
).uoid();
1440 kDebug() << "Oops! No identity for message";
1443 kDebug() << "Identity found:" << mIdentity
;
1447 iid
= TemplatesConfiguration::configIdString( mIdentity
); // templates ID for that identity
1449 iid
= "IDENTITY_NO_IDENTITY"; // templates ID for no identity
1452 Templates
iconf( iid
);
1453 if ( iconf
.useCustomTemplates() ) { // does identity use custom templates?
1456 tmpl
= iconf
.templateNewMessage();
1459 tmpl
= iconf
.templateReply();
1462 tmpl
= iconf
.templateReplyAll();
1465 tmpl
= iconf
.templateForward();
1468 kDebug() << "Unknown message mode:" << mMode
;
1471 mQuoteString
= iconf
.quoteString();
1472 if ( !tmpl
.isEmpty() ) {
1473 return tmpl
; // use identity-specific template
1478 switch( mMode
) { // use the global template
1480 tmpl
= GlobalSettings::self()->templateNewMessage();
1483 tmpl
= GlobalSettings::self()->templateReply();
1486 tmpl
= GlobalSettings::self()->templateReplyAll();
1489 tmpl
= GlobalSettings::self()->templateForward();
1492 kDebug() << "Unknown message mode:" << mMode
;
1496 mQuoteString
= GlobalSettings::self()->quoteString();
1500 QString
TemplateParser::pipe( const QString
&cmd
, const QString
&buf
)
1505 process
.setOutputChannelMode( KProcess::SeparateChannels
);
1506 process
.setShellCommand( cmd
);
1508 if ( process
.waitForStarted( PipeTimeout
) ) {
1509 bool finished
= false;
1510 if ( !buf
.isEmpty() ) {
1511 process
.write( buf
.toLatin1() );
1513 if ( buf
.isEmpty() || process
.waitForBytesWritten( PipeTimeout
) ) {
1514 if ( !buf
.isEmpty() ) {
1515 process
.closeWriteChannel();
1517 if ( process
.waitForFinished( PipeTimeout
) ) {
1518 success
= ( process
.exitStatus() == QProcess::NormalExit
);
1529 // The process has started, but did not finish in time. Kill it.
1537 if ( !success
&& mDebug
) {
1541 "Pipe command <command>%1</command> failed.", cmd
) );
1545 return process
.readAllStandardOutput();
1551 void TemplateParser::setWordWrap( bool wrap
, int wrapColWidth
)
1554 mColWrap
= wrapColWidth
;
1557 QString
TemplateParser::plainMessageText( bool aStripSignature
,
1558 AllowSelection isSelectionAllowed
) const
1560 if ( !mSelection
.isEmpty() && ( isSelectionAllowed
== SelectionAllowed
) ) {
1568 QString result
= mOtp
->plainTextContent();
1570 if ( result
.isEmpty() ) { //HTML-only mails
1571 result
= mOtp
->convertedTextContent();
1574 if ( aStripSignature
) {
1575 result
= MessageCore::StringUtil::stripSignature( result
);
1581 QString
TemplateParser::htmlMessageText( bool aStripSignature
, AllowSelection isSelectionAllowed
)
1583 if( !mSelection
.isEmpty() && ( isSelectionAllowed
== SelectionAllowed
) ) {
1584 //TODO implement mSelection for HTML
1588 QString htmlElement
= mOtp
->htmlContent();
1590 if ( htmlElement
.isEmpty() ) { //plain mails only
1591 htmlElement
= mOtp
->convertedHtmlContent();
1595 page
.settings()->setAttribute( QWebSettings::JavascriptEnabled
, false );
1596 page
.settings()->setAttribute( QWebSettings::JavaEnabled
, false );
1597 page
.settings()->setAttribute( QWebSettings::PluginsEnabled
, false );
1598 page
.settings()->setAttribute( QWebSettings::AutoLoadImages
, false );
1600 page
.currentFrame()->setHtml( htmlElement
);
1602 //TODO to be tested/verified if this is not an issue
1603 page
.settings()->setAttribute( QWebSettings::JavascriptEnabled
, true );
1604 const QString bodyElement
= page
.currentFrame()->evaluateJavaScript(
1605 "document.getElementsByTagName('body')[0].innerHTML" ).toString();
1607 mHeadElement
= page
.currentFrame()->evaluateJavaScript(
1608 "document.getElementsByTagName('head')[0].innerHTML" ).toString();
1610 page
.settings()->setAttribute( QWebSettings::JavascriptEnabled
, false );
1612 if( !bodyElement
.isEmpty() ) {
1613 if ( aStripSignature
) {
1614 //FIXME strip signature works partially for HTML mails
1615 return MessageCore::StringUtil::stripSignature( bodyElement
);
1620 if ( aStripSignature
) {
1621 //FIXME strip signature works partially for HTML mails
1622 return MessageCore::StringUtil::stripSignature( htmlElement
);
1627 QString
TemplateParser::quotedPlainText( const QString
&selection
) const
1629 QString content
= selection
;
1630 // Remove blank lines at the beginning:
1631 const int firstNonWS
= content
.indexOf( QRegExp( "\\S" ) );
1632 const int lineStart
= content
.lastIndexOf( '\n', firstNonWS
);
1633 if ( lineStart
>= 0 ) {
1634 content
.remove( 0, static_cast<unsigned int>( lineStart
) );
1637 const QString indentStr
=
1638 MessageCore::StringUtil::formatString( mQuoteString
, mOrigMsg
->from()->asUnicodeString() );
1640 if ( GlobalSettings::self()->smartQuote() && mWrap
) {
1641 content
= MessageCore::StringUtil::smartQuote( content
, mColWrap
- indentStr
.length() );
1644 content
.replace( '\n', '\n' + indentStr
);
1645 content
.prepend( indentStr
);
1651 QString
TemplateParser::quotedHtmlText( const QString
&selection
) const
1653 QString content
= selection
;
1654 //TODO 1) look for all the variations of <br> and remove the blank lines
1655 //2) implement vertical bar for quoted HTML mail.
1656 //3) After vertical bar is implemented, If a user wants to edit quoted message,
1657 // then the <blockquote> tags below should open and close as when required.
1659 //Add blockquote tag, so that quoted message can be differentiated from normal message
1660 content
= "<blockquote>" + content
+ "</blockquote>";
1664 uint
TemplateParser::identityUoid( const KMime::Message::Ptr
&msg
) const
1667 if ( msg
->headerByType( "X-KMail-Identity" ) ) {
1668 idString
= msg
->headerByType( "X-KMail-Identity" )->asUnicodeString().trimmed();
1671 int id
= idString
.toUInt( &ok
);
1673 if ( !ok
|| id
== 0 ) {
1674 id
= m_identityManager
->identityForAddress(
1675 msg
->to()->asUnicodeString() + ", " + msg
->cc()->asUnicodeString() ).uoid();
1681 bool TemplateParser::isHtmlSignature() const
1683 const KPIMIdentities::Identity
&identity
=
1684 m_identityManager
->identityForUoid( mIdentity
);
1686 if ( identity
.isNull() ) {
1690 const KPIMIdentities::Signature signature
=
1691 const_cast<KPIMIdentities::Identity
&>( identity
).signature();
1693 return signature
.isInlinedHtml();
1696 QString
TemplateParser::plainToHtml( const QString
&body
) const
1699 str
= Qt::escape( str
);
1700 str
.replace( QRegExp( "\n" ), "<br />\n" );
1704 //TODO implement this function using a DOM tree parser
1705 QString
TemplateParser::makeValidHtml( QString
&body
)
1708 regEx
.setMinimal( true );
1709 regEx
.setPattern( "<html.*>" );
1711 if ( !body
.isEmpty() && !body
.contains( regEx
) ) {
1712 regEx
.setPattern( "<body.*>" );
1713 if ( !body
.contains( regEx
) ) {
1714 body
= "<body>" + body
+ "<br/></body>";
1716 regEx
.setPattern( "<head.*>" );
1717 if ( !body
.contains( regEx
) ) {
1718 body
= "<head>" + mHeadElement
+"</head>" + body
;
1720 body
= "<html>" + body
+ "</html>";
1727 #include "templateparser.moc"