summaryrefslogtreecommitdiffstats
path: root/kmail/templateparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmail/templateparser.cpp')
-rw-r--r--kmail/templateparser.cpp187
1 files changed, 164 insertions, 23 deletions
diff --git a/kmail/templateparser.cpp b/kmail/templateparser.cpp
index 4112b58e..79df8509 100644
--- a/kmail/templateparser.cpp
+++ b/kmail/templateparser.cpp
@@ -43,21 +43,46 @@
#include "kmkernel.h"
#include <libkpimidentities/identity.h>
#include <libkpimidentities/identitymanager.h>
+#include "partNode.h"
+#include "attachmentcollector.h"
+#include "objecttreeparser.h"
+#include "util.h"
#include "templateparser.h"
+#include <mimelib/bodypart.h>
-TemplateParser::TemplateParser( KMMessage *amsg, const Mode amode,
- const TQString aselection,
- bool asmartQuote, bool anoQuote,
- bool aallowDecryption, bool aselectionIsBody ) :
- mMode( amode ), mFolder( 0 ), mIdentity( 0 ), mSelection( aselection ),
- mSmartQuote( asmartQuote ), mNoQuote( anoQuote ),
- mAllowDecryption( aallowDecryption ), mSelectionIsBody( aselectionIsBody ),
- mDebug( false ), mQuoteString( "> " ), mAppend( false )
+using namespace KMail;
+
+TemplateParser::TemplateParser( KMMessage *amsg, const Mode amode ) :
+ mMode( amode ), mFolder( 0 ), mIdentity( 0 ),
+ mAllowDecryption( false ),
+ mDebug( false ), mQuoteString( "> " ), mAppend( false ), mOrigRoot( 0 )
{
mMsg = amsg;
}
+void TemplateParser::setSelection( const TQString &selection )
+{
+ mSelection = selection;
+}
+
+void TemplateParser::setAllowDecryption( const bool allowDecryption )
+{
+ mAllowDecryption = allowDecryption;
+}
+
+bool TemplateParser::shouldStripSignature() const
+{
+ // Only strip the signature when replying, it should be preserved when forwarding
+ return ( mMode == Reply || mMode == ReplyAll) && GlobalSettings::stripSignature();
+}
+
+TemplateParser::~TemplateParser()
+{
+ delete mOrigRoot;
+ mOrigRoot = 0;
+}
+
int TemplateParser::parseQuotes( const TQString &prefix, const TQString &str,
TQString &quote ) const
{
@@ -279,36 +304,36 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
int len = parseQuotes( "QUOTEPIPE=", cmd, q );
i += len;
TQString pipe_cmd = q;
- if ( mOrigMsg && !mNoQuote ) {
- TQString str = pipe( pipe_cmd, mSelection );
+ if ( mOrigMsg ) {
+ TQString str = pipe( pipe_cmd, messageText( false ) );
TQString quote = mOrigMsg->asQuotedString( "", mQuoteString, str,
- mSmartQuote, mAllowDecryption );
+ shouldStripSignature(), mAllowDecryption );
body.append( quote );
}
} else if ( cmd.startsWith( "QUOTE" ) ) {
kdDebug() << "Command: QUOTE" << endl;
i += strlen( "QUOTE" );
- if ( mOrigMsg && !mNoQuote ) {
- TQString quote = mOrigMsg->asQuotedString( "", mQuoteString, mSelection,
- mSmartQuote, mAllowDecryption );
+ if ( mOrigMsg ) {
+ TQString quote = mOrigMsg->asQuotedString( "", mQuoteString, messageText( true ),
+ shouldStripSignature(), mAllowDecryption );
body.append( quote );
}
} else if ( cmd.startsWith( "QHEADERS" ) ) {
kdDebug() << "Command: QHEADERS" << endl;
i += strlen( "QHEADERS" );
- if ( mOrigMsg && !mNoQuote ) {
+ if ( mOrigMsg ) {
TQString quote = mOrigMsg->asQuotedString( "", mQuoteString,
mOrigMsg->headerAsSendableString(),
- mSmartQuote, false );
+ false, false );
body.append( quote );
}
} else if ( cmd.startsWith( "HEADERS" ) ) {
kdDebug() << "Command: HEADERS" << endl;
i += strlen( "HEADERS" );
- if ( mOrigMsg && !mNoQuote ) {
+ if ( mOrigMsg ) {
TQString str = mOrigMsg->headerAsSendableString();
body.append( str );
}
@@ -321,7 +346,7 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
i += len;
TQString pipe_cmd = q;
if ( mOrigMsg ) {
- TQString str = pipe(pipe_cmd, mSelection );
+ TQString str = pipe(pipe_cmd, messageText( false ) );
body.append( str );
}
@@ -363,7 +388,7 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
kdDebug() << "Command: TEXT" << endl;
i += strlen( "TEXT" );
if ( mOrigMsg ) {
- TQString quote = mOrigMsg->asPlainText( false, mAllowDecryption );
+ TQString quote = messageText( false );
body.append( quote );
}
@@ -379,10 +404,22 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
kdDebug() << "Command: OTEXT" << endl;
i += strlen( "OTEXT" );
if ( mOrigMsg ) {
- TQString quote = mOrigMsg->asPlainText( false, mAllowDecryption );
+ TQString quote = messageText( false );
body.append( quote );
}
+ } else if ( cmd.startsWith( "OADDRESSEESADDR" ) ) {
+ kdDebug() << "Command: OADDRESSEESADDR" << endl;
+ i += strlen( "OADDRESSEESADDR" );
+ const TQString to = mOrigMsg->to();
+ const TQString cc = mOrigMsg->cc();
+ if ( !to.isEmpty() )
+ body.append( i18n( "To:" ) + ' ' + to );
+ if ( !to.isEmpty() && !cc.isEmpty() )
+ body.append( '\n' );
+ if ( !cc.isEmpty() )
+ body.append( i18n( "CC:" ) + ' ' + cc );
+
} else if ( cmd.startsWith( "CCADDR" ) ) {
kdDebug() << "Command: CCADDR" << endl;
i += strlen( "CCADDR" );
@@ -829,20 +866,124 @@ void TemplateParser::processWithTemplate( const TQString &tmpl )
}
}
- // kdDebug() << "Message body: " << body << endl;
+ addProcessedBodyToMessage( body );
+}
+
+TQString TemplateParser::messageText( bool allowSelectionOnly )
+{
+ if ( !mSelection.isEmpty() && allowSelectionOnly )
+ return mSelection;
+
+ // No selection text, therefore we need to parse the object tree ourselves to get
+ partNode *root = parsedObjectTree();
+ return mOrigMsg->asPlainTextFromObjectTree( root, shouldStripSignature(), mAllowDecryption );
+}
+partNode* TemplateParser::parsedObjectTree()
+{
+ if ( mOrigRoot )
+ return mOrigRoot;
+
+ mOrigRoot = partNode::fromMessage( mOrigMsg );
+ ObjectTreeParser otp; // all defaults are ok
+ otp.parseObjectTree( mOrigRoot );
+ return mOrigRoot;
+}
+
+void TemplateParser::addProcessedBodyToMessage( const TQString &body )
+{
if ( mAppend ) {
+
+ // ### What happens here if the body is multipart or in some way encoded?
TQCString msg_body = mMsg->body();
msg_body.append( body.utf8() );
mMsg->setBody( msg_body );
- } else {
- mMsg->setBodyFromUnicode( body );
+ }
+ else {
+
+ // Get the attachments of the original mail
+ partNode *root = parsedObjectTree();
+ AttachmentCollector ac;
+ ac.collectAttachmentsFrom( root );
+
+ // Now, delete the old content and set the new content, which
+ // is either only the new text or the new text with some attachments.
+ mMsg->deleteBodyParts();
+
+ // Set To and CC from the template
+ if ( mMode == Forward ) {
+ if ( !mTo.isEmpty() ) {
+ mMsg->setTo( mMsg->to() + ',' + mTo );
+ }
+ if ( !mCC.isEmpty() )
+ mMsg->setCc( mMsg->cc() + ',' + mCC );
+ }
+
+ // If we have no attachment, simply create a text/plain part and
+ // set the processed template text as the body
+ if ( ac.attachments().empty() || mMode != Forward ) {
+ mMsg->headers().ContentType().FromString( DwString() ); // to get rid of old boundary
+ mMsg->headers().ContentType().Parse();
+ mMsg->headers().ContentType().SetType( DwMime::kTypeText );
+ mMsg->headers().ContentType().SetSubtype( DwMime::kSubtypePlain );
+ mMsg->headers().Assemble();
+ mMsg->setBodyFromUnicode( body );
+ mMsg->assembleIfNeeded();
+ }
+
+ // If we have some attachments, create a multipart/mixed mail and
+ // add the normal body as well as the attachments
+ else
+ {
+ mMsg->headers().ContentType().SetType( DwMime::kTypeMultipart );
+ mMsg->headers().ContentType().SetSubtype( DwMime::kSubtypeMixed );
+ mMsg->headers().ContentType().CreateBoundary( 0 );
+
+ KMMessagePart textPart;
+ textPart.setBodyFromUnicode( body );
+ mMsg->addDwBodyPart( mMsg->createDWBodyPart( &textPart ) );
+ mMsg->assembleIfNeeded();
+
+ int attachmentNumber = 1;
+ for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin();
+ it != ac.attachments().end(); ++it, attachmentNumber++ ) {
+
+ // When adding this body part, make sure to _not_ add the next bodypart
+ // as well, which mimelib would do, therefore creating a mail with many
+ // duplicate attachments (so many that KMail runs out of memory, in fact).
+ // Body::AddBodyPart is very misleading here...
+ ( *it )->dwPart()->SetNext( 0 );
+
+ DwBodyPart *cloned = static_cast<DwBodyPart*>( ( *it )->dwPart()->Clone() );
+
+ // If the content type has no name or filename parameter, add one, since otherwise the name
+ // would be empty in the attachment view of the composer, which looks confusing
+ if ( cloned->Headers().HasContentType() ) {
+ DwMediaType &ct = cloned->Headers().ContentType();
+
+ // Converting to a string here, since DwMediaType does not have a HasParameter() function
+ TQString ctStr = ct.AsString().c_str();
+ if ( !ctStr.lower().contains( "name=" ) && !ctStr.lower().contains( "filename=" ) ) {
+ DwParameter *nameParameter = new DwParameter;
+ nameParameter->SetAttribute( "name" );
+ nameParameter->SetValue( Util::dwString( KMMsgBase::encodeRFC2231StringAutoDetectCharset(
+ i18n( "Attachment %1" ).arg( attachmentNumber ) ) ) );
+ ct.AddParameter( nameParameter );
+ }
+ }
+
+ mMsg->addDwBodyPart( cloned );
+ mMsg->assembleIfNeeded();
+ }
+ }
}
}
TQString TemplateParser::findCustomTemplate( const TQString &tmplName )
{
CTemplates t( tmplName );
+ mTo = t.to();
+ mCC = t.cC();
TQString content = t.content();
if ( !content.isEmpty() ) {
return content;