150
86
#include <unistd.h>
151
87
#include <stdlib.h>
152
88
#include <sys/stat.h>
154
89
#include <stdio.h>
155
90
#include <ctype.h>
156
91
#include <string.h>
161
#include <QTextDocument>
164
94
using namespace KMail;
166
// This function returns the complete data that were in this
167
// message parts - *after* all encryption has been removed that
169
// - This is used to store the message in decrypted form.
170
void KMReaderWin::objectTreeToDecryptedMsg( partNode* node,
171
QByteArray& resultingData,
172
KMMessage& theMessage,
173
bool weAreReplacingTheRootNode,
176
kDebug() << "-------------------------------------------------";
177
kDebug() << "START" << "(" << recCount << ")";
180
kDebug(5006) << node->typeString() << '/' << node->subTypeString();
182
partNode* curNode = node;
183
partNode* dataNode = curNode;
184
partNode * child = node->firstChild();
185
const bool bIsMultipart = node->type() == DwMime::kTypeMultipart;
186
bool bKeepPartAsIs = false;
188
switch( curNode->type() ) {
189
case DwMime::kTypeMultipart: {
190
switch( curNode->subType() ) {
191
case DwMime::kSubtypeSigned: {
192
bKeepPartAsIs = true;
195
case DwMime::kSubtypeEncrypted: {
203
case DwMime::kTypeMessage: {
204
switch( curNode->subType() ) {
205
case DwMime::kSubtypeRfc822: {
213
case DwMime::kTypeApplication: {
214
switch( curNode->subType() ) {
215
case DwMime::kSubtypeOctetStream: {
220
case DwMime::kSubtypePkcs7Signature: {
221
// note: subtype Pkcs7Signature specifies a signature part
222
// which we do NOT want to remove!
223
bKeepPartAsIs = true;
226
case DwMime::kSubtypePkcs7Mime: {
227
// note: subtype Pkcs7Mime can also be signed
228
// and we do NOT want to remove the signature!
229
if ( child && curNode->encryptionState() != KMMsgNotEncrypted )
239
DwHeaders& rootHeaders( theMessage.headers() );
240
DwBodyPart * part = dataNode->dwPart() ? dataNode->dwPart() : 0;
242
(part && part->hasHeaders())
244
: ( (weAreReplacingTheRootNode || !dataNode->parentNode())
247
if( dataNode == curNode ) {
248
kDebug() << "dataNode == curNode: Save curNode without replacing it.";
250
// A) Store the headers of this part IF curNode is not the root node
251
// AND we are not replacing a node that already *has* replaced
252
// the root node in previous recursion steps of this function...
254
if( dataNode->parentNode() && !weAreReplacingTheRootNode ) {
255
kDebug() << "dataNode is NOT replacing the root node: Store the headers.";
256
resultingData += headers->AsString().c_str();
257
} else if( weAreReplacingTheRootNode && part && part->hasHeaders() ){
258
kDebug() << "dataNode replace the root node: Do NOT store the headers but change";
259
kDebug() << " the Message's headers accordingly.";
260
kDebug() << " old Content-Type =" << rootHeaders.ContentType().AsString().c_str();
261
kDebug() << " new Content-Type =" << headers->ContentType( ).AsString().c_str();
262
rootHeaders.ContentType() = headers->ContentType();
263
theMessage.setContentTransferEncodingStr(
264
headers->HasContentTransferEncoding()
265
? headers->ContentTransferEncoding().AsString().c_str()
267
rootHeaders.ContentDescription() = headers->ContentDescription();
268
rootHeaders.ContentDisposition() = headers->ContentDisposition();
269
theMessage.setNeedsAssembly();
273
if ( bKeepPartAsIs ) {
274
resultingData += dataNode->encodedBody();
277
// B) Store the body of this part.
278
if( headers && bIsMultipart && dataNode->firstChild() ) {
279
kDebug() << "is valid Multipart, processing children:";
280
QByteArray boundary = headers->ContentType().Boundary().c_str();
281
curNode = dataNode->firstChild();
282
// store children of multipart
284
kDebug() << "--boundary";
285
if( resultingData.size() &&
286
( '\n' != resultingData.at( resultingData.size()-1 ) ) )
287
resultingData += '\n';
288
resultingData += '\n';
289
resultingData += "--";
290
resultingData += boundary;
291
resultingData += '\n';
292
// note: We are processing a harmless multipart that is *not*
293
// to be replaced by one of it's children, therefor
294
// we set their doStoreHeaders to true.
295
objectTreeToDecryptedMsg( curNode,
300
curNode = curNode->nextSibling();
302
kDebug() << "--boundary--";
303
resultingData += "\n--";
304
resultingData += boundary;
305
resultingData += "--\n\n";
306
kDebug() << "Multipart processing children - DONE";
309
kDebug() << "is Simple part or invalid Multipart, storing body data .. DONE";
310
resultingData += part->Body().AsString().c_str();
314
kDebug() << "dataNode != curNode: Replace curNode by dataNode.";
315
bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parentNode();
316
if( rootNodeReplaceFlag ) {
317
kDebug() << " Root node will be replaced.";
319
kDebug() << " Root node will NOT be replaced.";
321
// store special data to replace the current part
322
// (e.g. decrypted data or embedded RfC 822 data)
323
objectTreeToDecryptedMsg( dataNode,
330
kDebug() << "END" << "(" << recCount << ")";
335
===========================================================================
338
E N D O F T E M P O R A R Y M I M E C O D E
341
===========================================================================
354
void KMReaderWin::createWidgets() {
355
QVBoxLayout * vlay = new QVBoxLayout( this );
356
vlay->setMargin( 0 );
357
mSplitter = new QSplitter( Qt::Vertical, this );
358
mSplitter->setObjectName( "mSplitter" );
359
mSplitter->setChildrenCollapsible( false );
360
vlay->addWidget( mSplitter );
361
mMimePartTree = new KMMimePartTree( this, mSplitter );
362
mMimePartTree->setObjectName( "mMimePartTree" );
363
mBox = new KHBox( mSplitter );
364
setStyleDependantFrameWidth();
365
mBox->setFrameStyle( mMimePartTree->frameStyle() );
366
mColorBar = new HtmlStatusBar( mBox );
367
mColorBar->setObjectName( "mColorBar" );
368
connect( mColorBar, SIGNAL( clicked() ),
369
this, SLOT( slotToggleHtmlMode() ) );
370
mViewer = new KHTMLPart( mBox );
371
mViewer->setObjectName( "mViewer" );
372
// Remove the shortcut for the selectAll action from khtml part. It's redefined to
373
// CTRL-SHIFT-A in kmail and clashes with kmails CTRL-A action.
374
KAction *selectAll = qobject_cast<KAction*>(
375
mViewer->actionCollection()->action( "selectAll" ) );
377
selectAll->setShortcut( KShortcut() );
379
kDebug() << "Failed to find khtml's selectAll action to remove it's shortcut";
381
// Remove the shortcut for the find action from khtml part. It's redefined to
382
// CTRL-F in kmail and clashes with khtml CTRL-F action.
383
KAction *afind = qobject_cast<KAction*>(
384
mViewer->actionCollection()->action( "find" ) );
386
afind->setShortcut( KShortcut() );
388
kDebug() << "Failed to find khtml's find action to remove it's shortcut";
391
mSplitter->setStretchFactor( mSplitter->indexOf(mMimePartTree), 0 );
392
mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
395
const int KMReaderWin::delay = 150;
95
using namespace MailCommon;
397
97
//-----------------------------------------------------------------------------
398
98
KMReaderWin::KMReaderWin(QWidget *aParent,
490
KToggleAction *raction = 0;
493
KActionMenu *headerMenu = new KActionMenu(i18nc("View->", "&Headers"), this);
494
ac->addAction("view_headers", headerMenu );
495
headerMenu->setHelpText( i18n("Choose display style of message headers") );
497
connect( headerMenu, SIGNAL(triggered(bool)),
498
this, SLOT(slotCycleHeaderStyles()) );
500
QActionGroup *group = new QActionGroup( this );
501
raction = new KToggleAction( i18nc("View->headers->", "&Enterprise Headers"), this);
502
ac->addAction( "view_headers_enterprise", raction );
503
connect( raction, SIGNAL(triggered(bool)), SLOT(slotEnterpriseHeaders()) );
504
raction->setHelpText( i18n("Show the list of headers in Enterprise style") );
505
group->addAction( raction );
506
headerMenu->addAction( raction );
508
raction = new KToggleAction(i18nc("View->headers->", "&Fancy Headers"), this);
509
ac->addAction("view_headers_fancy", raction );
510
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotFancyHeaders()));
511
raction->setHelpText( i18n("Show the list of headers in a fancy format") );
512
group->addAction( raction );
513
headerMenu->addAction( raction );
515
raction = new KToggleAction(i18nc("View->headers->", "&Brief Headers"), this);
516
ac->addAction("view_headers_brief", raction );
517
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotBriefHeaders()));
518
raction->setHelpText( i18n("Show brief list of message headers") );
519
group->addAction( raction );
520
headerMenu->addAction( raction );
522
raction = new KToggleAction(i18nc("View->headers->", "&Standard Headers"), this);
523
ac->addAction("view_headers_standard", raction );
524
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotStandardHeaders()));
525
raction->setHelpText( i18n("Show standard list of message headers") );
526
group->addAction( raction );
527
headerMenu->addAction( raction );
529
raction = new KToggleAction(i18nc("View->headers->", "&Long Headers"), this);
530
ac->addAction("view_headers_long", raction );
531
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotLongHeaders()));
532
raction->setHelpText( i18n("Show long list of message headers") );
533
group->addAction( raction );
534
headerMenu->addAction( raction );
536
raction = new KToggleAction(i18nc("View->headers->", "&All Headers"), this);
537
ac->addAction("view_headers_all", raction );
538
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotAllHeaders()));
539
raction->setHelpText( i18n("Show all message headers") );
540
group->addAction( raction );
541
headerMenu->addAction( raction );
544
KActionMenu *attachmentMenu = new KActionMenu(i18nc("View->", "&Attachments"), this);
545
ac->addAction("view_attachments", attachmentMenu );
546
attachmentMenu->setHelpText( i18n("Choose display style of attachments") );
547
connect( attachmentMenu, SIGNAL(triggered(bool)),
548
this, SLOT(slotCycleAttachmentStrategy()) );
550
group = new QActionGroup( this );
551
raction = new KToggleAction(i18nc("View->attachments->", "&As Icons"), this);
552
ac->addAction("view_attachments_as_icons", raction );
553
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotIconicAttachments()));
554
raction->setHelpText( i18n("Show all attachments as icons. Click to see them.") );
555
group->addAction( raction );
556
attachmentMenu->addAction( raction );
558
raction = new KToggleAction(i18nc("View->attachments->", "&Smart"), this);
559
ac->addAction("view_attachments_smart", raction );
560
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotSmartAttachments()));
561
raction->setHelpText( i18n("Show attachments as suggested by sender.") );
562
group->addAction( raction );
563
attachmentMenu->addAction( raction );
565
raction = new KToggleAction(i18nc("View->attachments->", "&Inline"), this);
566
ac->addAction("view_attachments_inline", raction );
567
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotInlineAttachments()));
568
raction->setHelpText( i18n("Show all attachments inline (if possible)") );
569
group->addAction( raction );
570
attachmentMenu->addAction( raction );
572
raction = new KToggleAction(i18nc("View->attachments->", "&Hide"), this);
573
ac->addAction("view_attachments_hide", raction );
574
connect(raction, SIGNAL(triggered(bool) ), SLOT(slotHideAttachments()));
575
raction->setHelpText( i18n("Do not show attachments in the message viewer") );
576
group->addAction( raction );
577
attachmentMenu->addAction( raction );
579
// Set Encoding submenu
580
mSelectEncodingAction = new KSelectAction(KIcon("character-set"), i18n("&Set Encoding"), this);
581
mSelectEncodingAction->setToolBarMode( KSelectAction::MenuMode );
582
ac->addAction("encoding", mSelectEncodingAction );
583
connect(mSelectEncodingAction,SIGNAL( triggered(int)),
584
SLOT( slotSetEncoding() ));
585
QStringList encodings = KMMsgBase::supportedEncodings( false );
586
encodings.prepend( i18n( "Auto" ) );
587
mSelectEncodingAction->setItems( encodings );
588
mSelectEncodingAction->setCurrentItem( 0 );
594
147
// new message to
595
148
mMailToComposeAction = new KAction( KIcon( "mail-message-new" ),
596
149
i18n( "New Message To..." ), this );
664
189
ac->addAction( "saveas_url", mUrlSaveAsAction );
665
190
connect( mUrlSaveAsAction, SIGNAL(triggered(bool)), SLOT(slotUrlSave()) );
668
mToggleFixFontAction = new KToggleAction( i18n( "Use Fi&xed Font" ), this );
669
ac->addAction( "toggle_fixedfont", mToggleFixFontAction );
670
connect( mToggleFixFontAction, SIGNAL(triggered(bool)), SLOT(slotToggleFixedFont()) );
671
mToggleFixFontAction->setShortcut( QKeySequence( Qt::Key_X ) );
673
// Show message structure viewer
674
mToggleMimePartTreeAction = new KToggleAction( i18n( "Show Message Structure" ), this );
675
ac->addAction( "toggle_mimeparttree", mToggleMimePartTreeAction );
676
connect( mToggleMimePartTreeAction, SIGNAL(toggled(bool)),
677
SLOT(slotToggleMimePartTree()));
682
mScrollUpAction = new KAction( i18n("Scroll Message Up"), this );
683
mScrollUpAction->setShortcut( QKeySequence( Qt::Key_Up ) );
684
ac->addAction( "scroll_up", mScrollUpAction );
685
connect( mScrollUpAction, SIGNAL( triggered( bool ) ),
686
this, SLOT( slotScrollUp() ) );
688
mScrollDownAction = new KAction( i18n("Scroll Message Down"), this );
689
mScrollDownAction->setShortcut( QKeySequence( Qt::Key_Down ) );
690
ac->addAction( "scroll_down", mScrollDownAction );
691
connect( mScrollDownAction, SIGNAL( triggered( bool ) ),
692
this, SLOT( slotScrollDown() ) );
694
mScrollUpMoreAction = new KAction( i18n("Scroll Message Up (More)"), this );
695
mScrollUpMoreAction->setShortcut( QKeySequence( Qt::Key_PageUp ) );
696
ac->addAction( "scroll_up_more", mScrollUpMoreAction );
697
connect( mScrollUpMoreAction, SIGNAL( triggered( bool ) ),
698
this, SLOT( slotScrollPrior() ) );
700
mScrollDownMoreAction = new KAction( i18n("Scroll Message Down (More)"), this );
701
mScrollDownMoreAction->setShortcut( QKeySequence( Qt::Key_PageDown ) );
702
ac->addAction( "scroll_down_more", mScrollDownMoreAction );
703
connect( mScrollDownMoreAction, SIGNAL( triggered( bool ) ),
704
this, SLOT( slotScrollNext() ) );
707
// Actions not in menu
710
// Toggle HTML display mode.
711
mToggleDisplayModeAction = new KToggleAction( i18n( "Toggle HTML Display Mode" ), this );
712
ac->addAction( "toggle_html_display_mode", mToggleDisplayModeAction );
713
connect( mToggleDisplayModeAction, SIGNAL( triggered( bool ) ), SLOT( slotToggleHtmlMode() ) );
714
mToggleDisplayModeAction->setHelpText( i18n( "Toggle display mode between HTML and plain text" ) );
193
KAction *action = new KAction(KIcon("edit-find"), i18n("&Find in Message..."), this);
194
ac->addAction("find_in_messages", action );
195
connect(action, SIGNAL(triggered(bool)), SLOT(slotFind()));
196
action->setShortcut(KStandardShortcut::find());
717
200
void KMReaderWin::setUseFixedFont( bool useFixedFont )
719
mUseFixedFont = useFixedFont;
720
if ( mToggleFixFontAction )
722
mToggleFixFontAction->setChecked( mUseFixedFont );
726
// little helper function
727
KToggleAction *KMReaderWin::actionForHeaderStyle( const HeaderStyle * style, const HeaderStrategy * strategy ) {
728
if ( !mActionCollection )
730
const char * actionName = 0;
731
if ( style == HeaderStyle::enterprise() )
732
actionName = "view_headers_enterprise";
733
if ( style == HeaderStyle::fancy() )
734
actionName = "view_headers_fancy";
735
else if ( style == HeaderStyle::brief() )
736
actionName = "view_headers_brief";
737
else if ( style == HeaderStyle::plain() ) {
738
if ( strategy == HeaderStrategy::standard() )
739
actionName = "view_headers_standard";
740
else if ( strategy == HeaderStrategy::rich() )
741
actionName = "view_headers_long";
742
else if ( strategy == HeaderStrategy::all() )
743
actionName = "view_headers_all";
746
return static_cast<KToggleAction*>(mActionCollection->action(actionName));
751
KToggleAction *KMReaderWin::actionForAttachmentStrategy( const AttachmentStrategy * as ) {
752
if ( !mActionCollection )
754
const char * actionName = 0;
755
if ( as == AttachmentStrategy::iconic() )
756
actionName = "view_attachments_as_icons";
757
else if ( as == AttachmentStrategy::smart() )
758
actionName = "view_attachments_smart";
759
else if ( as == AttachmentStrategy::inlined() )
760
actionName = "view_attachments_inline";
761
else if ( as == AttachmentStrategy::hidden() )
762
actionName = "view_attachments_hide";
765
return static_cast<KToggleAction*>(mActionCollection->action(actionName));
770
void KMReaderWin::slotEnterpriseHeaders() {
771
setHeaderStyleAndStrategy( HeaderStyle::enterprise(),
772
HeaderStrategy::rich() );
773
if( !mExternalWindow )
777
void KMReaderWin::slotFancyHeaders() {
778
setHeaderStyleAndStrategy( HeaderStyle::fancy(),
779
HeaderStrategy::rich() );
780
if( !mExternalWindow )
784
void KMReaderWin::slotBriefHeaders() {
785
setHeaderStyleAndStrategy( HeaderStyle::brief(),
786
HeaderStrategy::brief() );
787
if( !mExternalWindow )
791
void KMReaderWin::slotStandardHeaders() {
792
setHeaderStyleAndStrategy( HeaderStyle::plain(),
793
HeaderStrategy::standard());
797
void KMReaderWin::slotLongHeaders() {
798
setHeaderStyleAndStrategy( HeaderStyle::plain(),
799
HeaderStrategy::rich() );
800
if( !mExternalWindow )
804
void KMReaderWin::slotAllHeaders() {
805
setHeaderStyleAndStrategy( HeaderStyle::plain(),
806
HeaderStrategy::all() );
807
if( !mExternalWindow )
811
void KMReaderWin::slotLevelQuote( int l )
202
mViewer->setUseFixedFont( useFixedFont );
205
bool KMReaderWin::isFixedFont() const
817
void KMReaderWin::slotCycleHeaderStyles() {
818
const HeaderStrategy * strategy = headerStrategy();
819
const HeaderStyle * style = headerStyle();
821
const char * actionName = 0;
822
if ( style == HeaderStyle::enterprise() ) {
824
actionName = "view_headers_fancy";
826
if ( style == HeaderStyle::fancy() ) {
828
actionName = "view_headers_brief";
829
} else if ( style == HeaderStyle::brief() ) {
830
slotStandardHeaders();
831
actionName = "view_headers_standard";
832
} else if ( style == HeaderStyle::plain() ) {
833
if ( strategy == HeaderStrategy::standard() ) {
835
actionName = "view_headers_long";
836
} else if ( strategy == HeaderStrategy::rich() ) {
838
actionName = "view_headers_all";
839
} else if ( strategy == HeaderStrategy::all() ) {
840
slotEnterpriseHeaders();
841
actionName = "view_headers_enterprise";
846
static_cast<KToggleAction*>( mActionCollection->action( actionName ) )->setChecked( true );
850
void KMReaderWin::slotIconicAttachments() {
851
setAttachmentStrategy( AttachmentStrategy::iconic() );
854
void KMReaderWin::slotSmartAttachments() {
855
setAttachmentStrategy( AttachmentStrategy::smart() );
858
void KMReaderWin::slotInlineAttachments() {
859
setAttachmentStrategy( AttachmentStrategy::inlined() );
862
void KMReaderWin::slotHideAttachments() {
863
setAttachmentStrategy( AttachmentStrategy::hidden() );
866
void KMReaderWin::slotCycleAttachmentStrategy() {
867
setAttachmentStrategy( attachmentStrategy()->next() );
868
KToggleAction * action = actionForAttachmentStrategy( attachmentStrategy() );
870
action->setChecked( true );
207
return mViewer->isFixedFont();
874
210
//-----------------------------------------------------------------------------
875
211
KMReaderWin::~KMReaderWin()
877
clearBodyPartMementos();
878
delete mHtmlWriter; mHtmlWriter = 0;
880
if (mAutoDelete) delete message();
881
delete mRootNode; mRootNode = 0;
886
//-----------------------------------------------------------------------------
887
void KMReaderWin::slotMessageArrived( KMMessage *msg )
889
if (msg && ((KMMsgBase*)msg)->isMessage()) {
890
if ( msg->getMsgSerNum() == mWaitingForSerNum ) {
893
kDebug() << "Ignoring update";
898
//-----------------------------------------------------------------------------
899
void KMReaderWin::update( KMail::Interface::Observable * observable )
903
saveRelativePosition();
911
KMMessage* msg = static_cast<KMMessage*>( observable );
914
// find our partNode and update it
915
if ( !msg->lastUpdatedPart() ) {
916
kDebug() << "No updated part";
919
partNode* node = mRootNode->findNodeForDwPart( msg->lastUpdatedPart() );
921
kDebug() << "Can't find node for part";
924
node->setDwPart( msg->lastUpdatedPart() );
926
// update the tmp file
927
// we have to set it writeable temporarily
928
::chmod( QFile::encodeName( mAtmCurrentName ), S_IRWXU );
929
QByteArray data = node->msgPart().bodyDecodedBinary();
930
if ( node->msgPart().type() == DwMime::kTypeText && data.size() > 0 ) {
931
// convert CRLF to LF before writing text attachments to disk
932
const size_t newsize = KMail::Util::crlf2lf( data.data(), data.size() );
933
data.truncate( newsize );
935
KPIMUtils::kByteArrayToFile( data, mAtmCurrentName, false, false, false );
936
::chmod( QFile::encodeName( mAtmCurrentName ), S_IRUSR );
941
//-----------------------------------------------------------------------------
942
void KMReaderWin::removeTempFiles()
944
for (QStringList::Iterator it = mTempFiles.begin(); it != mTempFiles.end();
950
for (QStringList::Iterator it = mTempDirs.begin(); it != mTempDirs.end();
953
QDir(*it).rmdir(*it);
959
//-----------------------------------------------------------------------------
960
bool KMReaderWin::event(QEvent *e)
962
if (e->type() == QEvent::PaletteChange)
965
mCSSHelper = new KMail::CSSHelper( mViewer->view() );
967
message()->readConfig();
968
update( true ); // Force update
971
return QWidget::event(e);
975
216
//-----------------------------------------------------------------------------
976
217
void KMReaderWin::readConfig(void)
979
mCSSHelper = new KMail::CSSHelper( mViewer->view() );
981
mNoMDNsWhenEncrypted = GlobalSettings::self()->notSendWhenEncrypted();
983
mUseFixedFont = GlobalSettings::self()->useFixedFont();
984
if ( mToggleFixFontAction )
985
mToggleFixFontAction->setChecked( mUseFixedFont );
987
mHtmlMail = GlobalSettings::self()->htmlMail();
988
mHtmlLoadExternal = GlobalSettings::self()->htmlLoadExternal();
990
KToggleAction *raction = actionForHeaderStyle( headerStyle(), headerStrategy() );
992
raction->setChecked( true );
994
setAttachmentStrategy( AttachmentStrategy::create( GlobalSettings::self()->attachmentStrategy() ) );
995
raction = actionForAttachmentStrategy( attachmentStrategy() );
997
raction->setChecked( true );
999
const int mimeH = GlobalSettings::self()->mimePaneHeight();
1000
const int messageH = GlobalSettings::self()->messagePaneHeight();
1001
mSplitterSizes.clear();
1002
if ( GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom )
1003
mSplitterSizes << messageH << mimeH;
1005
mSplitterSizes << mimeH << messageH;
1009
readGlobalOverrideCodec();
1011
// Note that this call triggers an update, see this call has to be at the
1012
// bottom when all settings are already est.
1013
setHeaderStyleAndStrategy( HeaderStyle::create( GlobalSettings::self()->headerStyle() ),
1014
HeaderStrategy::create( GlobalSettings::self()->headerSetDisplayed() ) );
1018
mColorBar->update();
1019
KMMessage::readConfig();
1023
void KMReaderWin::adjustLayout() {
1024
if ( GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom )
1025
mSplitter->addWidget( mMimePartTree );
1027
mSplitter->insertWidget( 0, mMimePartTree );
1028
mSplitter->setSizes( mSplitterSizes );
1030
if ( GlobalSettings::self()->mimeTreeMode() == GlobalSettings::EnumMimeTreeMode::Always &&
1032
mMimePartTree->show();
1034
mMimePartTree->hide();
1036
if ( GlobalSettings::self()->showColorbar() && mMsgDisplay )
1043
void KMReaderWin::saveSplitterSizes() const {
1044
if ( !mSplitter || !mMimePartTree )
1046
if ( mMimePartTree->isHidden() )
1047
return; // don't rely on QSplitter maintaining sizes for hidden widgets.
1049
const bool mimeTreeAtBottom = GlobalSettings::self()->mimeTreeLocation() == GlobalSettings::EnumMimeTreeLocation::bottom;
1050
GlobalSettings::self()->setMimePaneHeight( mSplitter->sizes()[ mimeTreeAtBottom ? 1 : 0 ] );
1051
GlobalSettings::self()->setMessagePaneHeight( mSplitter->sizes()[ mimeTreeAtBottom ? 0 : 1 ] );
1054
//-----------------------------------------------------------------------------
1055
void KMReaderWin::writeConfig( bool sync ) const {
1056
GlobalSettings::self()->setUseFixedFont( mUseFixedFont );
1057
if ( headerStyle() )
1058
GlobalSettings::self()->setHeaderStyle( headerStyle()->name() );
1059
if ( headerStrategy() )
1060
GlobalSettings::self()->setHeaderSetDisplayed( headerStrategy()->name() );
1061
if ( attachmentStrategy() )
1062
GlobalSettings::self()->setAttachmentStrategy( attachmentStrategy()->name() );
1064
saveSplitterSizes();
1067
kmkernel->slotRequestConfigSync();
1070
//-----------------------------------------------------------------------------
1071
void KMReaderWin::initHtmlWidget(void)
1073
mViewer->widget()->setFocusPolicy(Qt::WheelFocus);
1074
// Let's better be paranoid and disable plugins (it defaults to enabled):
1075
mViewer->setPluginsEnabled(false);
1076
mViewer->setJScriptEnabled(false); // just make this explicit
1077
mViewer->setJavaEnabled(false); // just make this explicit
1078
mViewer->setMetaRefreshEnabled(false);
1079
mViewer->setURLCursor( QCursor( Qt::PointingHandCursor ) );
1080
// Espen 2000-05-14: Getting rid of thick ugly frames
1081
mViewer->view()->setLineWidth(0);
1082
// register our own event filter for shift-click
1083
mViewer->view()->widget()->installEventFilter( this );
1085
if ( !htmlWriter() ) {
1086
mPartHtmlWriter = new KHtmlPartHtmlWriter( mViewer, 0 );
1087
#ifdef KMAIL_READER_HTML_DEBUG
1088
mHtmlWriter = new TeeHtmlWriter( new FileHtmlWriter( QString() ),
1091
mHtmlWriter = mPartHtmlWriter;
1095
// We do a queued connection below, and for that we need to register the meta types of the
1098
// Why do we do a queued connection instead of a direct one? slotUrlOpen() handles those clicks,
1099
// and can end up in the click handler for accepting invitations. That handler can pop up a dialog
1100
// asking the user for a comment on the invitation reply. This dialog is started with exec(), i.e.
1101
// executes a sub-eventloop. This sub-eventloop then eventually re-enters the KHTML event handler,
1102
// which then thinks we started a drag, and therefore adds a silly drag object to the cursor, with
1103
// urls like x-kmail-whatever/43/8/accept, and we don't want that drag object.
1105
// Therefore, use queued connections to avoid the reentry of the KHTML event loop, so we don't
1106
// get the drag object.
1107
static bool metaTypesRegistered = false;
1108
if ( !metaTypesRegistered ) {
1109
qRegisterMetaType<KParts::OpenUrlArguments>( "KParts::OpenUrlArguments" );
1110
qRegisterMetaType<KParts::BrowserArguments>( "KParts::BrowserArguments" );
1111
qRegisterMetaType<KParts::WindowArgs>( "KParts::WindowArgs" );
1112
metaTypesRegistered = true;
1115
connect(mViewer->browserExtension(),
1116
SIGNAL(openUrlRequest(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),this,
1117
SLOT(slotUrlOpen(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),
1118
Qt::QueuedConnection);
1119
connect(mViewer->browserExtension(),
1120
SIGNAL(createNewWindow(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),this,
1121
SLOT(slotUrlOpen(const KUrl &, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)),
1122
Qt::QueuedConnection);
1123
connect(mViewer,SIGNAL(onURL(const QString &)),this,
1124
SLOT(slotUrlOn(const QString &)));
1125
connect(mViewer,SIGNAL(popupMenu(const QString &, const QPoint &)),
1126
SLOT(slotUrlPopup(const QString &, const QPoint &)));
219
mViewer->readConfig();
1129
222
void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy * strategy ) {
1130
mAttachmentStrategy = strategy ? strategy : AttachmentStrategy::smart();
223
mViewer->setAttachmentStrategy( strategy );
1134
void KMReaderWin::setHeaderStyleAndStrategy( const HeaderStyle * style,
226
void KMReaderWin::setHeaderStyleAndStrategy( HeaderStyle * style,
1135
227
const HeaderStrategy * strategy ) {
1136
mHeaderStyle = style ? style : HeaderStyle::fancy();
1137
mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich();
228
mViewer->setHeaderStyleAndStrategy( style, strategy );
1141
230
//-----------------------------------------------------------------------------
1142
231
void KMReaderWin::setOverrideEncoding( const QString & encoding )
1144
if ( encoding == mOverrideEncoding )
1147
mOverrideEncoding = encoding;
1148
if ( mSelectEncodingAction ) {
1149
if ( encoding.isEmpty() ) {
1150
mSelectEncodingAction->setCurrentItem( 0 );
1153
QStringList encodings = mSelectEncodingAction->items();
1155
for ( QStringList::const_iterator it = encodings.constBegin(), end = encodings.constEnd(); it != end; ++it, ++i ) {
1156
if ( KMMsgBase::encodingForName( *it ) == encoding ) {
1157
mSelectEncodingAction->setCurrentItem( i );
1161
if ( i == encodings.size() ) {
1162
// the value of encoding is unknown => use Auto
1163
kWarning() <<"Unknown override character encoding \"" << encoding
1164
<< "\". Using Auto instead.";
1165
mSelectEncodingAction->setCurrentItem( 0 );
1166
mOverrideEncoding.clear();
1173
//-----------------------------------------------------------------------------
1174
const QTextCodec * KMReaderWin::overrideCodec() const
1176
if ( mOverrideEncoding.isEmpty() || mOverrideEncoding == "Auto" ) // Auto
1179
return KMMsgBase::codecForName( mOverrideEncoding.toLatin1() );
1182
//-----------------------------------------------------------------------------
1183
void KMReaderWin::slotSetEncoding()
1185
if ( mSelectEncodingAction->currentItem() == 0 ) // Auto
1186
mOverrideEncoding.clear();
1188
mOverrideEncoding = KMMsgBase::encodingForName( mSelectEncodingAction->currentText() );
1192
//-----------------------------------------------------------------------------
1193
void KMReaderWin::readGlobalOverrideCodec()
1195
// if the global character encoding wasn't changed then there's nothing to do
1196
if ( GlobalSettings::self()->overrideCharacterEncoding() == mOldGlobalOverrideEncoding )
1199
setOverrideEncoding( GlobalSettings::self()->overrideCharacterEncoding() );
1200
mOldGlobalOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding();
1203
//-----------------------------------------------------------------------------
1204
void KMReaderWin::setOriginalMsg( unsigned long serNumOfOriginalMessage, int nodeIdOffset )
1206
mSerNumOfOriginalMessage = serNumOfOriginalMessage;
1207
mNodeIdOffset = nodeIdOffset;
1210
//-----------------------------------------------------------------------------
1211
void KMReaderWin::setMsg( KMMessage* aMsg, bool force )
1214
kDebug() << "(" << aMsg->getMsgSerNum() <<", last" << mLastSerNum <<")" << aMsg->subject()
1215
<< aMsg->fromStrip() << ", readyToShow" << (aMsg->readyToShow());
1218
// Reset message-transient state
1219
if (aMsg && aMsg->getMsgSerNum() != mLastSerNum ){
1220
mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin()-1;
1221
clearBodyPartMementos();
1226
bool complete = true;
1228
!aMsg->readyToShow() &&
1229
(aMsg->getMsgSerNum() != mLastSerNum) &&
1230
!aMsg->isComplete() )
1233
// If not forced and there is aMsg and aMsg is same as mMsg then return
1234
if (!force && aMsg && mLastSerNum != 0 && aMsg->getMsgSerNum() == mLastSerNum)
1237
// (de)register as observer
1238
if (aMsg && message())
1239
message()->detach( this );
1241
aMsg->attach( this );
1244
// connect to the updates if we have hancy headers
1246
mDelayedMarkTimer.stop();
1250
mWaitingForSerNum = 0; // otherwise it has been set
1253
mLastSerNum = aMsg->getMsgSerNum();
1254
// Check if the serial number can be used to find the assoc KMMessage
1255
// If so, keep only the serial number (and not mMessage), to avoid a dangling mMessage
1256
// when going to another message in the mainwindow.
1257
// Otherwise, keep only mMessage, this is fine for standalone KMReaderMainWins since
1258
// we're working on a copy of the KMMessage, which we own.
1259
if (message() != aMsg) {
1266
aMsg->setOverrideCodec( overrideCodec() );
1267
aMsg->setDecodeHTML( htmlMail() );
1268
// FIXME: workaround to disable DND for IMAP load-on-demand
1269
if ( !aMsg->isComplete() )
1270
mViewer->setDNDEnabled( false );
1272
mViewer->setDNDEnabled( true );
1275
// only display the msg if it is complete
1276
// otherwise we'll get flickering with progressively loaded messages
1279
// Avoid flicker, somewhat of a cludge
1281
// stop the timer to avoid calling updateReaderWin twice
1282
mUpdateReaderWinTimer.stop();
1285
else if (mUpdateReaderWinTimer.isActive()) {
1286
mUpdateReaderWinTimer.setInterval( delay );
1288
mUpdateReaderWinTimer.start( 0 );
1292
if ( aMsg && (aMsg->status().isUnread() || aMsg->status().isNew())
1293
&& GlobalSettings::self()->delayedMarkAsRead() ) {
1294
if ( GlobalSettings::self()->delayedMarkTime() != 0 )
1295
mDelayedMarkTimer.start( GlobalSettings::self()->delayedMarkTime() * 1000 );
233
mViewer->setOverrideEncoding( encoding );
1301
236
//-----------------------------------------------------------------------------
1302
237
void KMReaderWin::clearCache()
1304
mUpdateReaderWinTimer.stop();
1306
mDelayedMarkTimer.stop();
1308
mWaitingForSerNum = 0;
1312
242
// enter items for the "Important changes" list here:
1313
243
static const char * const kmailChanges[] = {
244
I18N_NOOP( "KMail is now based on the Akonadi Personal Information Management framework, which brings many "
245
"changes all around.")
1316
247
static const int numKMailChanges =
1317
248
sizeof kmailChanges / sizeof *kmailChanges;
1452
366
displaySplashPage( info.toString() );
1455
void KMReaderWin::enableMsgDisplay() {
1461
//-----------------------------------------------------------------------------
1463
void KMReaderWin::updateReaderWin()
1465
if ( !mMsgDisplay ) {
1469
mViewer->setOnlyLocalReferences( !htmlLoadExternal() );
1471
htmlWriter()->reset();
1474
if ( GlobalSettings::self()->showColorbar() ) {
1482
mMimePartTree->hide();
1483
mMimePartTree->clearAndResetSortOrder();
1484
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
1485
htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) + "</body></html>" );
1486
htmlWriter()->end();
1489
if ( mSavedRelativePosition ) {
1490
QScrollBar *scrollBar = mViewer->view()->verticalScrollBar();
1491
scrollBar->setValue( scrollBar->maximum() * mSavedRelativePosition );
1492
mSavedRelativePosition = 0;
1496
//-----------------------------------------------------------------------------
1497
int KMReaderWin::pointsToPixel(int pointSize) const
1499
return (pointSize * mViewer->view()->logicalDpiY() + 36) / 72;
1502
//-----------------------------------------------------------------------------
1503
void KMReaderWin::showHideMimeTree() {
1504
if ( GlobalSettings::self()->mimeTreeMode() == GlobalSettings::EnumMimeTreeMode::Always )
1505
mMimePartTree->show();
1507
// don't rely on QSplitter maintaining sizes for hidden widgets:
1508
saveSplitterSizes();
1509
mMimePartTree->hide();
1511
if ( mToggleMimePartTreeAction && ( mToggleMimePartTreeAction->isChecked() != mMimePartTree->isVisible() ) )
1512
mToggleMimePartTreeAction->setChecked( mMimePartTree->isVisible() );
1515
void KMReaderWin::displayMessage() {
1516
KMMessage * msg = message();
1518
mMimePartTree->clearAndResetSortOrder();
1524
msg->setOverrideCodec( overrideCodec() );
1526
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
1527
htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
1530
setWindowTitle(msg->subject());
1534
mColorBar->setNormalMode();
1538
htmlWriter()->queue("</body></html>");
1539
htmlWriter()->flush();
1541
// For some reason the DOM is not complete at this moment.
1542
// But if the below functions are called using a singleShot timer
1543
// everything just seems to work.
1544
QTimer::singleShot( 1, this, SLOT( toggleFullAddressList() ) );
1545
QTimer::singleShot( 1, this, SLOT(injectAttachments()) );
1548
static bool message_was_saved_decrypted_before( const KMMessage * msg )
1552
kDebug() << "msgId =" << msg->msgId();
1553
return msg->msgId().trimmed().startsWith( "<DecryptedMsg." );
1556
//-----------------------------------------------------------------------------
1557
void KMReaderWin::parseMsg(KMMessage* aMsg)
1559
KMMessagePart msgPart;
1563
aMsg->setIsBeingParsed( true );
1565
if ( mRootNode && !mRootNode->processed() ) {
1566
kWarning() << "The root node is not yet processed! Danger!";
1571
mRootNode = partNode::fromMessage( aMsg, this );
1572
const QByteArray mainCntTypeStr = mRootNode->typeString() + '/' + mRootNode->subTypeString();
1574
QString cntDesc = aMsg->subject();
1575
if( cntDesc.isEmpty() )
1576
cntDesc = i18n("( body part )");
1577
KIO::filesize_t cntSize = aMsg->msgSize();
1579
if( aMsg->contentTransferEncodingStr().isEmpty() )
1582
cntEnc = aMsg->contentTransferEncodingStr();
1584
// fill the MIME part tree viewer
1585
mRootNode->fillMimePartTree( 0, mMimePartTree, cntDesc, mainCntTypeStr,
1588
// Check if any part of this message is a v-card
1589
// v-cards can be either text/x-vcard or text/directory, so we need to check
1591
partNode* vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeXVCard );
1593
vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeDirectory );
1595
bool hasVCard = false;
1597
// ### FIXME: We should only do this if the vCard belongs to the sender,
1598
// ### i.e. if the sender's email address is contained in the vCard.
1599
const QByteArray vCard = vCardNode->msgPart().bodyDecodedBinary();
1600
KABC::VCardConverter t;
1601
if ( !t.parseVCards( vCard ).isEmpty() ) {
1603
kDebug() << "FOUND A VALID VCARD";
1604
writeMessagePartToTempFile( &vCardNode->msgPart(), vCardNode->nodeId() );
1607
htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard ? vCardNode : 0, true ) );
1609
// show message content
1610
ObjectTreeParser otp( this );
1611
otp.setAllowAsync( true );
1612
otp.parseObjectTree( mRootNode );
1614
// store encrypted/signed status information in the KMMessage
1615
// - this can only be done *after* calling parseObjectTree()
1616
KMMsgEncryptionState encryptionState = mRootNode->overallEncryptionState();
1617
KMMsgSignatureState signatureState = mRootNode->overallSignatureState();
1618
// Don't crash when switching message while GPG passphrase entry dialog is shown #53185
1619
if (aMsg != message()) {
1623
aMsg->setEncryptionState( encryptionState );
1624
// Don't reset the signature state to "not signed" (e.g. if one canceled the
1625
// decryption of a signed messages which has already been decrypted before).
1626
if ( signatureState != KMMsgNotSigned ||
1627
aMsg->signatureState() == KMMsgSignatureStateUnknown ) {
1628
aMsg->setSignatureState( signatureState );
1631
bool emitReplaceMsgByUnencryptedVersion = false;
1632
const KConfigGroup reader( KMKernel::config(), "Reader" );
1633
if ( reader.readEntry( "store-displayed-messages-unencrypted", false ) ) {
1635
// Hack to make sure the S/MIME CryptPlugs follows the strict requirement
1636
// of german government:
1637
// --> All received encrypted messages *must* be stored in unencrypted form
1638
// after they have been decrypted once the user has read them.
1639
// ( "Aufhebung der Verschluesselung nach dem Lesen" )
1641
// note: Since there is no configuration option for this, we do that for
1642
// all kinds of encryption now - *not* just for S/MIME.
1643
// This could be changed in the objectTreeToDecryptedMsg() function
1644
// by deciding when (or when not, resp.) to set the 'dataNode' to
1645
// something different than 'curNode'.
1648
kDebug() << "\n\n\nSpecial post-encryption handling:\n1.";
1649
kDebug() << "(aMsg == msg) =" << (aMsg == message());
1650
kDebug() << "aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() = " << (aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder());
1651
kDebug() << "message_was_saved_decrypted_before( aMsg ) = " << message_was_saved_decrypted_before( aMsg );
1652
kDebug() << "this->decryptMessage() = " << decryptMessage();
1653
kDebug() << "otp.hasPendingAsyncJobs() = " << otp.hasPendingAsyncJobs();
1654
kDebug() << " (KMMsgFullyEncrypted == encryptionState) = " << (KMMsgFullyEncrypted == encryptionState);
1655
kDebug() <<"|| (KMMsgPartiallyEncrypted == encryptionState) =" << (KMMsgPartiallyEncrypted == encryptionState);
1656
// only proceed if we were called the normal way - not by
1657
// double click on the message (==not running in a separate window)
1658
if( (aMsg == message())
1659
// don't remove encryption in the outbox folder :)
1660
&& ( aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() )
1661
// only proceed if this message was not saved encryptedly before
1662
&& !message_was_saved_decrypted_before( aMsg )
1663
// only proceed if the message has actually been decrypted
1665
// only proceed if no pending async jobs are running:
1666
&& !otp.hasPendingAsyncJobs()
1667
// only proceed if this message is (at least partially) encrypted
1668
&& ( (KMMsgFullyEncrypted == encryptionState)
1669
|| (KMMsgPartiallyEncrypted == encryptionState) ) ) {
1671
kDebug() << "Calling objectTreeToDecryptedMsg()";
1673
QByteArray decryptedData;
1674
// note: The following call may change the message's headers.
1675
objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg );
1676
kDebug() << "Resulting data:" << decryptedData;
1678
if( !decryptedData.isEmpty() ) {
1679
kDebug() << "Composing unencrypted message";
1681
aMsg->setBody( decryptedData );
1682
KMMessage* unencryptedMessage = new KMMessage( *aMsg );
1683
unencryptedMessage->setParent( 0 );
1684
// because this did not work:
1686
DwMessage dwMsg( DwString( aMsg->asString() ) );
1687
dwMsg.Body() = DwBody( DwString( resultString.data() ) );
1688
dwMsg.Body().Parse();
1689
KMMessage* unencryptedMessage = new KMMessage( &dwMsg );
1691
kDebug() << "Resulting message:" << unencryptedMessage->asString();
1692
kDebug() << "Attach unencrypted message to aMsg";
1693
aMsg->setUnencryptedMsg( unencryptedMessage );
1694
emitReplaceMsgByUnencryptedVersion = true;
1699
// store message id to avoid endless recursions
1700
setIdOfLastViewedMessage( aMsg->msgId() );
1702
if( emitReplaceMsgByUnencryptedVersion ) {
1703
kDebug() << "Invoce saving in decrypted form:";
1704
emit replaceMsgByUnencryptedVersion();
1709
aMsg->setIsBeingParsed( false );
1713
//-----------------------------------------------------------------------------
1714
QString KMReaderWin::writeMsgHeader( KMMessage* aMsg, partNode *vCardNode, bool topLevel )
1716
if ( !headerStyle() ) {
1717
kFatal() << "Trying to writeMsgHeader() without a header style set!";
1719
if ( !headerStrategy() ) {
1720
kFatal() << "trying to writeMsgHeader() without a header strategy set!";
1724
href = vCardNode->asHREF( "body" );
1726
return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting, topLevel );
1729
//-----------------------------------------------------------------------------
1730
QString KMReaderWin::writeMessagePartToTempFile( KMMessagePart* aMsgPart,
1733
// If the message part is already written to a file, no point in doing it again.
1734
// This function is called twice actually, once from the rendering of the attachment
1735
// in the body and once for the header.
1736
const partNode * node = mRootNode->findId( aPartNum );
1737
KUrl existingFileName = tempFileUrlFromPartNode( node );
1738
if ( !existingFileName.isEmpty() ) {
1739
return existingFileName.toLocalFile();
1742
QString fileName = aMsgPart->fileName();
1743
if( fileName.isEmpty() )
1744
fileName = aMsgPart->name();
1746
QString fname = createTempDir( QString::number( aPartNum ) );
1747
if ( fname.isEmpty() )
1750
// strip off a leading path
1751
int slashPos = fileName.lastIndexOf( '/' );
1752
if( -1 != slashPos )
1753
fileName = fileName.mid( slashPos + 1 );
1754
if( fileName.isEmpty() )
1755
fileName = "unnamed";
1756
fname += '/' + fileName;
1758
QByteArray data = aMsgPart->bodyDecodedBinary();
1759
if ( aMsgPart->type() == DwMime::kTypeText && data.size() > 0 ) {
1760
// convert CRLF to LF before writing text attachments to disk
1761
const size_t newsize = KMail::Util::crlf2lf( data.data(), data.size() );
1762
data.truncate( newsize );
1764
if( !KPIMUtils::kByteArrayToFile( data, fname, false, false, false ) )
1767
mTempFiles.append( fname );
1768
// make file read-only so that nobody gets the impression that he might
1769
// edit attached files (cf. bug #52813)
1770
::chmod( QFile::encodeName( fname ), S_IRUSR );
1775
QString KMReaderWin::createTempDir( const QString ¶m )
1777
KTemporaryFile *tempFile = new KTemporaryFile();
1778
tempFile->setSuffix( '.' + param );
1780
QString fname = tempFile->fileName();
1783
if ( ::access( QFile::encodeName( fname ), W_OK ) != 0 ) {
1784
// Not there or not writable
1785
if( KDE_mkdir( QFile::encodeName( fname ), 0 ) != 0 ||
1786
::chmod( QFile::encodeName( fname ), S_IRWXU ) != 0 ) {
1787
return QString(); //failed create
1791
assert( !fname.isNull() );
1793
mTempDirs.append( fname );
1797
//-----------------------------------------------------------------------------
1798
void KMReaderWin::showVCard( KMMessagePart * msgPart ) {
1799
const QByteArray vCard = msgPart->bodyDecodedBinary();
1801
VCardViewer *vcv = new VCardViewer(this, vCard );
1802
vcv->setObjectName( "vCardDialog" );
1806
//-----------------------------------------------------------------------------
1807
void KMReaderWin::printMsg( KMMessage* aMsg )
1809
disconnect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) );
1810
connect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) );
1811
setMsg( aMsg, true );
1814
//-----------------------------------------------------------------------------
1815
void KMReaderWin::slotPrintMsg()
1817
disconnect( mPartHtmlWriter, SIGNAL( finished() ), this, SLOT( slotPrintMsg() ) );
1818
if (!message()) return;
1819
mViewer->view()->print();
1824
//-----------------------------------------------------------------------------
1825
int KMReaderWin::msgPartFromUrl( const KUrl &aUrl )
1827
if ( aUrl.isEmpty() ) return -1;
1828
if ( !aUrl.isLocalFile() ) return -1;
1830
QString path = aUrl.toLocalFile();
1831
uint right = path.lastIndexOf( '/' );
1832
uint left = path.lastIndexOf( '.', right );
1835
int res = path.mid( left + 1, right - left - 1 ).toInt( &ok );
1836
return ( ok ) ? res : -1;
1840
//-----------------------------------------------------------------------------
1841
void KMReaderWin::resizeEvent( QResizeEvent * )
1843
if( !mResizeTimer.isActive() )
1846
// Combine all resize operations that are requested as long a
1849
mResizeTimer.start( 100 );
1854
//-----------------------------------------------------------------------------
1855
void KMReaderWin::slotDelayedResize()
1857
mSplitter->setGeometry( 0, 0, width(), height() );
1861
//-----------------------------------------------------------------------------
1862
void KMReaderWin::slotTouchMessage()
1867
if ( !message()->status().isNew() && !message()->status().isUnread() )
1871
serNums.append( message()->getMsgSerNum() );
1872
KMCommand *command = new KMSetStatusCommand( MessageStatus::statusRead(), serNums );
1875
// should we send an MDN?
1876
if ( mNoMDNsWhenEncrypted &&
1877
message()->encryptionState() != KMMsgNotEncrypted &&
1878
message()->encryptionState() != KMMsgEncryptionStateUnknown )
1881
KMFolder *folder = message()->parent();
1883
( folder->isOutbox() || folder->isSent() || folder->isTrash() ||
1884
folder->isDrafts() || folder->isTemplates() ) )
1887
if ( KMMessage * receipt = message()->createMDN( MDN::ManualAction,
1889
true /* allow GUI */ ) )
1890
if ( !kmkernel->msgSender()->send( receipt ) ) // send or queue
1891
KMessageBox::error( this, i18n("Could not send MDN.") );
1895
//-----------------------------------------------------------------------------
1896
void KMReaderWin::closeEvent( QCloseEvent *e )
1898
QWidget::closeEvent( e );
1903
bool foundSMIMEData( const QString aUrl,
1904
QString& displayName,
1908
static QString showCertMan("showCertificate#");
1912
int i1 = aUrl.indexOf( showCertMan );
1914
i1 += showCertMan.length();
1915
int i2 = aUrl.indexOf(" ### ", i1);
1918
displayName = aUrl.mid( i1, i2-i1 );
1920
i2 = aUrl.indexOf(" ### ", i1);
1923
libName = aUrl.mid( i1, i2-i1 );
1926
keyId = aUrl.mid( i2 );
1928
int len = aUrl.length();
1930
keyId = aUrl.mid( i2, 2 );
1932
while( len > i2+1 ) {
1934
keyId += aUrl.mid( i2, 2 );
1942
return !keyId.isEmpty();
1946
//-----------------------------------------------------------------------------
1947
void KMReaderWin::slotUrlOn(const QString &aUrl)
1949
const KUrl url(aUrl);
1951
if ( url.protocol() == "kmail" || url.protocol() == "x-kmail" || url.protocol() == "attachment"
1952
|| (url.protocol().isEmpty() && url.path().isEmpty()) ) {
1953
mViewer->setDNDEnabled( false );
1955
mViewer->setDNDEnabled( true );
1958
if ( aUrl.trimmed().isEmpty() ) {
1959
KPIM::BroadcastStatus::instance()->reset();
1960
mHoveredUrl = KUrl();
1966
const QString msg = URLHandlerManager::instance()->statusBarMessage( url, this );
1968
if ( msg.isEmpty() ) {
1969
kWarning() << "Unhandled URL hover!";
1971
KPIM::BroadcastStatus::instance()->setTransientStatusMsg( msg );
1975
//-----------------------------------------------------------------------------
1976
void KMReaderWin::slotUrlOpen(const KUrl &aUrl, const KParts::OpenUrlArguments &, const KParts::BrowserArguments &)
1980
if ( URLHandlerManager::instance()->handleClick( aUrl, this ) )
1983
kWarning() << "Unhandled URL click!";
1984
emit urlClicked( aUrl, Qt::LeftButton );
1987
//-----------------------------------------------------------------------------
1988
void KMReaderWin::slotUrlPopup(const QString &aUrl, const QPoint& aPos)
1990
const KUrl url( aUrl );
1993
if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) )
1997
kWarning() << "Unhandled URL right-click!";
1998
emit popupMenu( *message(), url, aPos );
2002
// Checks if the given node has a parent node that is a DIV which has an ID attribute
2003
// with the value specified here
2004
static bool hasParentDivWithId( const DOM::Node &start, const QString &id )
2006
if ( start.isNull() )
2009
if ( start.nodeName().string() == "div" ) {
2010
for ( unsigned int i = 0; i < start.attributes().length(); i++ ) {
2011
if ( start.attributes().item( i ).nodeName().string() == "id" &&
2012
start.attributes().item( i ).nodeValue().string() == id )
2017
if ( !start.parentNode().isNull() )
2018
return hasParentDivWithId( start.parentNode(), id );
2022
//-----------------------------------------------------------------------------
2023
void KMReaderWin::prepareHandleAttachment( int id, const QString& fileName )
2026
mAtmCurrentName = fileName;
2029
//-----------------------------------------------------------------------------
2030
void KMReaderWin::showAttachmentPopup( int id, const QString & name, const QPoint &p )
2032
prepareHandleAttachment( id, name );
2033
KMenu *menu = new KMenu();
2036
QSignalMapper *attachmentMapper = new QSignalMapper( menu );
2037
connect( attachmentMapper, SIGNAL( mapped( int ) ),
2038
this, SLOT( slotHandleAttachment( int ) ) );
2040
action = menu->addAction(SmallIcon("document-open"),i18nc("to open", "Open"));
2041
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2042
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Open );
2044
action = menu->addAction(i18n("Open With..."));
2045
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2046
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::OpenWith );
2048
action = menu->addAction(i18nc("to view something", "View") );
2049
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2050
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::View );
2052
const bool attachmentInHeader = hasParentDivWithId( mViewer->nodeUnderMouse(), "attachmentInjectionPoint" );
2053
const bool hasScrollbar = mViewer->view()->verticalScrollBar()->isVisible();
2054
if ( attachmentInHeader && hasScrollbar ) {
2055
action = menu->addAction( i18n( "Scroll To" ) );
2056
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2057
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::ScrollTo );
2060
action = menu->addAction(SmallIcon("document-save-as"),i18n("Save As...") );
2061
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2062
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Save );
2064
action = menu->addAction(SmallIcon("edit-copy"), i18n("Copy") );
2065
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2066
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Copy );
2068
const bool canChange = message()->parent() ? !message()->parent()->isReadOnly() : false;
2070
if ( GlobalSettings::self()->allowAttachmentEditing() ) {
2071
action = menu->addAction(SmallIcon("document-properties"), i18n("Edit Attachment") );
2072
connect( action, SIGNAL(triggered()), attachmentMapper, SLOT(map()) );
2073
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Edit );
2074
action->setEnabled( canChange );
2076
if ( GlobalSettings::self()->allowAttachmentDeletion() ) {
2077
action = menu->addAction(SmallIcon("edit-delete"), i18n("Delete Attachment") );
2078
connect( action, SIGNAL(triggered()), attachmentMapper, SLOT(map()) );
2079
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Delete );
2080
action->setEnabled( canChange );
2082
if ( name.endsWith( QLatin1String(".xia"), Qt::CaseInsensitive ) &&
2083
Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
2084
action = menu->addAction( i18n( "Decrypt With Chiasmus..." ) );
2085
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2086
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::ChiasmusEncrypt );
2088
action = menu->addAction(i18n("Properties") );
2089
connect( action, SIGNAL( triggered(bool) ), attachmentMapper, SLOT( map() ) );
2090
attachmentMapper->setMapping( action, KMHandleAttachmentCommand::Properties );
2095
//-----------------------------------------------------------------------------
2096
void KMReaderWin::setStyleDependantFrameWidth()
2100
// set the width of the frame to a reasonable value for the current GUI style
2102
#if 0 // is this hack still needed with kde4?
2103
if( !qstrcmp( style()->metaObject()->className(), "KeramikStyle" ) )
2104
frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
2107
frameWidth = style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
2108
if ( frameWidth < 0 )
2110
if ( frameWidth != mBox->lineWidth() )
2111
mBox->setLineWidth( frameWidth );
2114
//-----------------------------------------------------------------------------
2115
void KMReaderWin::styleChange( QStyle& oldStyle )
2117
setStyleDependantFrameWidth();
2118
QWidget::styleChange( oldStyle );
2121
//-----------------------------------------------------------------------------
2122
void KMReaderWin::slotHandleAttachment( int choice )
2125
partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
2126
if ( choice == KMHandleAttachmentCommand::Delete ) {
2127
slotDeleteAttachment( node );
2128
} else if ( choice == KMHandleAttachmentCommand::Edit ) {
2129
slotEditAttachment( node );
2130
} else if ( choice == KMHandleAttachmentCommand::Copy ) {
2134
KUrl kUrl = tempFileUrlFromPartNode( node );
2135
QUrl url = QUrl::fromPercentEncoding( kUrl.toEncoded() );
2137
if ( !url.isValid() )
2141
QMimeData *mimeData = new QMimeData;
2142
mimeData->setUrls( urls );
2143
QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
2144
} else if ( choice == KMHandleAttachmentCommand::ScrollTo ) {
2145
scrollToAttachment( node );
2148
KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
2149
node, message(), mAtmCurrent, mAtmCurrentName,
2150
KMHandleAttachmentCommand::AttachmentAction( choice ), KService::Ptr( 0 ), this );
2151
connect( command, SIGNAL( showAttachment( int, const QString& ) ),
2152
this, SLOT( slotAtmView( int, const QString& ) ) );
2157
//-----------------------------------------------------------------------------
2158
void KMReaderWin::slotToggleHtmlMode()
2160
setHtmlOverride( !htmlMail() );
2164
369
//-----------------------------------------------------------------------------
2165
370
void KMReaderWin::slotFind()
2167
mViewer->findText();
2170
//-----------------------------------------------------------------------------
2171
void KMReaderWin::slotToggleFixedFont()
2173
mUseFixedFont = !mUseFixedFont;
2177
//-----------------------------------------------------------------------------
2178
void KMReaderWin::slotToggleMimePartTree()
2180
if ( mToggleMimePartTreeAction->isChecked() )
2181
GlobalSettings::self()->setMimeTreeMode( GlobalSettings::EnumMimeTreeMode::Always );
2183
GlobalSettings::self()->setMimeTreeMode( GlobalSettings::EnumMimeTreeMode::Never );
2187
374
//-----------------------------------------------------------------------------
2188
375
void KMReaderWin::slotCopySelectedText()
2192
379
QApplication::clipboard()->setText( selection );
2196
//-----------------------------------------------------------------------------
2197
void KMReaderWin::atmViewMsg( KMMessagePart* aMsgPart, int nodeId )
2199
assert(aMsgPart!=0);
2200
KMMessage* msg = new KMMessage;
2201
msg->fromString(aMsgPart->bodyDecoded());
2203
msg->setMsgSerNum( 0 ); // because lookups will fail
2204
// some information that is needed for imap messages with LOD
2205
msg->setParent( message()->parent() );
2206
msg->setUID(message()->UID());
2207
msg->setReadyToShow(true);
2208
KMReaderMainWin *win = new KMReaderMainWin();
2209
win->showMsg( overrideEncoding(), msg, message()->getMsgSerNum(), nodeId );
2214
void KMReaderWin::setMsgPart( partNode * node ) {
2215
htmlWriter()->reset();
2217
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2218
htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
2221
ObjectTreeParser otp( this, 0, true );
2222
otp.parseObjectTree( node );
2225
htmlWriter()->queue( "</body></html>" );
2226
htmlWriter()->flush();
2229
//-----------------------------------------------------------------------------
2230
void KMReaderWin::setMsgPart( KMMessagePart* aMsgPart, bool aHTML,
2231
const QString& aFileName, const QString& pname )
2233
// Cancel scheduled updates of the reader window, as that would stop the
2234
// timer of the HTML writer, which would make viewing attachment not work
2235
// anymore as not all HTML is written to the HTML part.
2236
// We're updating the reader window here ourselves anyway.
2237
mUpdateReaderWinTimer.stop();
2239
KCursorSaver busy(KBusyPtr::busy());
2240
if (kasciistricmp(aMsgPart->typeStr(), "message")==0) {
2241
// if called from compose win
2242
KMMessage* msg = new KMMessage;
2243
assert(aMsgPart!=0);
2244
msg->fromString(aMsgPart->bodyDecoded());
2245
mMainWindow->setWindowTitle(msg->subject());
2247
setAutoDelete(true);
2248
} else if (kasciistricmp(aMsgPart->typeStr(), "text")==0) {
2249
if (kasciistricmp(aMsgPart->subtypeStr(), "x-vcard") == 0 ||
2250
kasciistricmp(aMsgPart->subtypeStr(), "directory") == 0) {
2251
showVCard( aMsgPart );
2254
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2255
htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
2257
if (aHTML && (kasciistricmp(aMsgPart->subtypeStr(), "html")==0)) { // HTML
2258
// ### this is broken. It doesn't stip off the HTML header and footer!
2259
htmlWriter()->queue( aMsgPart->bodyToUnicode( overrideCodec() ) );
2260
mColorBar->setHtmlMode();
2261
} else { // plain text
2262
const QByteArray str = aMsgPart->bodyDecoded();
2263
ObjectTreeParser otp( this );
2264
otp.writeBodyStr( str,
2265
overrideCodec() ? overrideCodec() : aMsgPart->codec(),
2266
message() ? message()->from() : QString() );
2268
htmlWriter()->queue("</body></html>");
2269
htmlWriter()->flush();
2270
mMainWindow->setWindowTitle(i18n("View Attachment: %1", pname));
2271
} else if (kasciistricmp(aMsgPart->typeStr(), "image")==0 ||
2272
(kasciistricmp(aMsgPart->typeStr(), "application")==0 &&
2273
kasciistricmp(aMsgPart->subtypeStr(), "postscript")==0))
2275
if (aFileName.isEmpty()) return; // prevent crash
2276
// Open the window with a size so the image fits in (if possible):
2277
QImageReader *iio = new QImageReader();
2278
iio->setFileName(aFileName);
2279
if( iio->canRead() ) {
2280
QImage img = iio->read();
2281
QRect desk = KGlobalSettings::desktopGeometry(mMainWindow);
2282
// determine a reasonable window size
2284
if( img.width() < 50 )
2286
else if( img.width()+20 < desk.width() )
2287
width = img.width()+20;
2289
width = desk.width();
2290
if( img.height() < 50 )
2292
else if( img.height()+20 < desk.height() )
2293
height = img.height()+20;
2295
height = desk.height();
2296
mMainWindow->resize( width, height );
2298
// Just write the img tag to HTML:
2299
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2300
htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
2301
htmlWriter()->write( "<img src=\"file:" +
2302
KUrl::toPercentEncoding( aFileName ) +
2303
"\" border=\"0\">\n"
2304
"</body></html>\n" );
2305
htmlWriter()->end();
2306
setWindowTitle( i18n("View Attachment: %1", pname ) );
2310
htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
2311
htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
2312
htmlWriter()->queue( "<pre>" );
2314
QString str = aMsgPart->bodyDecoded();
2315
// A QString cannot handle binary data. So if it's shorter than the
2316
// attachment, we assume the attachment is binary:
2317
if( str.length() < aMsgPart->decodedSize() ) {
2318
str.prepend( i18np("[KMail: Attachment contains binary data. Trying to show first character.]",
2319
"[KMail: Attachment contains binary data. Trying to show first %1 characters.]",
2320
str.length()) + QChar::fromLatin1('\n') );
2322
htmlWriter()->queue( Qt::escape( str ) );
2323
htmlWriter()->queue( "</pre>" );
2324
htmlWriter()->queue("</body></html>");
2325
htmlWriter()->flush();
2326
mMainWindow->setWindowTitle(i18n("View Attachment: %1", pname));
2331
//-----------------------------------------------------------------------------
2332
void KMReaderWin::slotAtmView( int id, const QString& name )
2334
partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
2337
mAtmCurrentName = name;
2338
if ( mAtmCurrentName.isEmpty() )
2339
mAtmCurrentName = tempFileUrlFromPartNode( node ).toLocalFile();
2341
KMMessagePart& msgPart = node->msgPart();
2342
QString pname = msgPart.fileName();
2343
if (pname.isEmpty()) pname=msgPart.name();
2344
if (pname.isEmpty()) pname=msgPart.contentDescription();
2345
if (pname.isEmpty()) pname="unnamed";
2346
// image Attachment is saved already
2347
if (kasciistricmp(msgPart.typeStr(), "message")==0) {
2348
atmViewMsg( &msgPart,id );
2349
} else if ((kasciistricmp(msgPart.typeStr(), "text")==0) &&
2350
( (kasciistricmp(msgPart.subtypeStr(), "x-vcard")==0) ||
2351
(kasciistricmp(msgPart.subtypeStr(), "directory")==0) )) {
2352
setMsgPart( &msgPart, htmlMail(), name, pname );
2354
KMReaderMainWin *win = new KMReaderMainWin(&msgPart, htmlMail(),
2355
name, pname, overrideEncoding() );
2361
//-----------------------------------------------------------------------------
2362
void KMReaderWin::openAttachment( int id, const QString & name )
2364
mAtmCurrentName = name;
2367
QString str, pname, cmd, fileName;
2369
partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
2371
kWarning() << "Could not find node" << id;
2374
if ( mAtmCurrentName.isEmpty() )
2375
mAtmCurrentName = tempFileUrlFromPartNode( node ).toLocalFile();
2377
KMMessagePart& msgPart = node->msgPart();
2378
if (kasciistricmp(msgPart.typeStr(), "message")==0)
2380
atmViewMsg( &msgPart, id );
2384
QByteArray contentTypeStr( msgPart.typeStr() + '/' + msgPart.subtypeStr() );
2385
kAsciiToLower( contentTypeStr.data() );
2387
// determine the MIME type of the attachment
2388
KMimeType::Ptr mimetype;
2389
// prefer the value of the Content-Type header
2390
mimetype = KMimeType::mimeType( QString::fromLatin1( contentTypeStr ), KMimeType::ResolveAliases );
2391
if ( !mimetype.isNull() && mimetype->is( KABC::Addressee::mimeType() ) ) {
2392
showVCard( &msgPart );
2396
// special case treatment on mac
2397
if ( KMail::Util::handleUrlOnMac( mAtmCurrentName ) )
2400
if ( mimetype.isNull() || mimetype->name() == "application/octet-stream" ) {
2401
// consider the filename if mimetype can not be found by content-type
2402
mimetype = KMimeType::findByPath( name, 0, true /* no disk access */ );
2404
if ( ( mimetype->name() == "application/octet-stream" )
2405
&& msgPart.isComplete() ) {
2406
// consider the attachment's contents if neither the Content-Type header
2407
// nor the filename give us a clue
2408
mimetype = KMimeType::findByFileContent( name );
2411
KService::Ptr offer =
2412
KMimeTypeTrader::self()->preferredService( mimetype->name(), "Application" );
2414
QString filenameText = msgPart.fileName();
2415
if ( filenameText.isEmpty() )
2416
filenameText = msgPart.name();
2418
KMail::AttachmentDialog dialog( this, filenameText, offer ? offer->name() : QString(),
2419
QString::fromLatin1( "askSave_" ) + mimetype->name() );
2420
const int choice = dialog.exec();
2422
if ( choice == KMail::AttachmentDialog::Save ) {
2424
KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
2425
message(), mAtmCurrent, mAtmCurrentName, KMHandleAttachmentCommand::Save,
2427
connect( command, SIGNAL( showAttachment( int, const QString& ) ),
2428
this, SLOT( slotAtmView( int, const QString& ) ) );
2431
else if ( ( choice == KMail::AttachmentDialog::Open ) ||
2432
( choice == KMail::AttachmentDialog::OpenWith ) ) {
2433
KMHandleAttachmentCommand::AttachmentAction action;
2434
if ( choice == KMail::AttachmentDialog::Open )
2435
action = KMHandleAttachmentCommand::Open;
2437
action = KMHandleAttachmentCommand::OpenWith;
2439
KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
2440
message(), mAtmCurrent, mAtmCurrentName, action, offer, this );
2441
connect( command, SIGNAL( showAttachment( int, const QString& ) ),
2442
this, SLOT( slotAtmView( int, const QString& ) ) );
2445
kDebug() << "Canceled opening attachment";
2449
//-----------------------------------------------------------------------------
2450
void KMReaderWin::slotScrollUp()
2452
mViewer->view()->scrollBy( 0, -10 );
2456
//-----------------------------------------------------------------------------
2457
void KMReaderWin::slotScrollDown()
2459
mViewer->view()->scrollBy( 0, 10 );
2462
bool KMReaderWin::atBottom() const
2464
KHTMLView *view = mViewer->view();
2465
return view->contentsY() + view->visibleHeight() >= view->contentsHeight();
2468
//-----------------------------------------------------------------------------
2469
void KMReaderWin::slotJumpDown()
2471
mViewer->view()->scrollBy( 0, mViewer->view()->visibleHeight() );
2474
//-----------------------------------------------------------------------------
2475
void KMReaderWin::slotScrollPrior()
2477
mViewer->view()->scrollBy( 0, -(int)(mViewer->widget()->height() * 0.8 ) );
2480
//-----------------------------------------------------------------------------
2481
void KMReaderWin::slotScrollNext()
2483
mViewer->view()->scrollBy( 0, (int)(mViewer->widget()->height() * 0.8 ) );
2486
//-----------------------------------------------------------------------------
2487
void KMReaderWin::slotDocumentChanged()
2492
//-----------------------------------------------------------------------------
2493
void KMReaderWin::slotTextSelected(bool)
2495
QString temp = mViewer->selectedText();
2496
QApplication::clipboard()->setText(temp);
2499
//-----------------------------------------------------------------------------
2500
void KMReaderWin::selectAll()
2502
mViewer->selectAll();
2505
//-----------------------------------------------------------------------------
2506
QString KMReaderWin::copyText()
2508
QString temp = mViewer->selectedText();
2512
//-----------------------------------------------------------------------------
2513
void KMReaderWin::slotDocumentDone()
382
//-----------------------------------------------------------------------------
383
void KMReaderWin::setMsgPart( KMime::Content* aMsgPart )
385
mViewer->setMessagePart( aMsgPart );
388
//-----------------------------------------------------------------------------
389
QString KMReaderWin::copyText() const
391
return mViewer->selectedText();
2517
394
//-----------------------------------------------------------------------------
2518
395
void KMReaderWin::setHtmlOverride( bool override )
2520
mHtmlOverride = override;
2522
message()->setDecodeHTML( htmlMail() );
397
mViewer->setHtmlOverride( override );
2525
// keep toggle display mode action state in sync.
2526
if ( mToggleDisplayModeAction )
2527
mToggleDisplayModeAction->setChecked( htmlMail() );
400
bool KMReaderWin::htmlOverride() const
402
return mViewer->htmlOverride();
2530
405
//-----------------------------------------------------------------------------
2531
406
void KMReaderWin::setHtmlLoadExtOverride( bool override )
2533
mHtmlLoadExtOverride = override;
408
mViewer->setHtmlLoadExtOverride( override );
2536
411
//-----------------------------------------------------------------------------
2537
bool KMReaderWin::htmlMail()
412
bool KMReaderWin::htmlMail() const
2539
return ((mHtmlMail && !mHtmlOverride) || (!mHtmlMail && mHtmlOverride));
414
return mViewer->htmlMail();
2542
417
//-----------------------------------------------------------------------------
2543
418
bool KMReaderWin::htmlLoadExternal()
2545
return ((mHtmlLoadExternal && !mHtmlLoadExtOverride) ||
2546
(!mHtmlLoadExternal && mHtmlLoadExtOverride));
2549
//-----------------------------------------------------------------------------
2550
void KMReaderWin::saveRelativePosition()
2552
const QScrollBar *scrollBar = mViewer->view()->verticalScrollBar();
2553
if ( scrollBar->maximum() )
2554
mSavedRelativePosition = static_cast<float>( scrollBar->value() ) / scrollBar->maximum();
2556
mSavedRelativePosition = 0;
2560
//-----------------------------------------------------------------------------
2561
void KMReaderWin::update( bool force )
2563
KMMessage *msg = message();
2565
saveRelativePosition();
2566
setMsg( msg, force );
2570
//-----------------------------------------------------------------------------
2571
KMMessage *KMReaderWin::message() const
2577
KMMessage *message = 0;
2578
if ( mLastSerNum ) {
2581
KMMsgDict::instance()->getLocation( mLastSerNum, &folder, &index );
2582
if ( folder && index >= 0 ) {
2583
message = folder->getMsg( index );
2586
kWarning() << "Attempt to reference invalid serial number" << mLastSerNum;
2592
//-----------------------------------------------------------------------------
2593
void KMReaderWin::slotUrlClicked()
2595
KMMainWidget *mainWidget = dynamic_cast<KMMainWidget*>(mMainWindow);
2597
if ( message() && message()->parent() ) {
2598
identity = message()->parent()->identity();
2601
KMCommand *command = new KMUrlClickedCommand( mClickedUrl, identity, this,
2602
false, mainWidget );
420
return mViewer->htmlLoadExternal();
423
//-----------------------------------------------------------------------------
424
Akonadi::Item KMReaderWin::message() const
426
return mViewer->messageItem();
2606
429
//-----------------------------------------------------------------------------
2607
430
void KMReaderWin::slotMailtoCompose()
2609
KMCommand *command = new KMMailtoComposeCommand( mClickedUrl, message() );
432
KMCommand *command = new KMMailtoComposeCommand( urlClicked(), message() );
2610
433
command->start();
2613
436
//-----------------------------------------------------------------------------
2614
437
void KMReaderWin::slotMailtoForward()
2616
KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mClickedUrl,
439
KMCommand *command = new KMMailtoForwardCommand( mMainWindow, urlClicked(),
2618
441
command->start();
2621
444
//-----------------------------------------------------------------------------
2622
445
void KMReaderWin::slotMailtoAddAddrBook()
2624
KMCommand *command = new KMMailtoAddAddrBookCommand( mClickedUrl,
447
const QString emailString = KPIMUtils::decodeMailtoUrl( urlClicked() );
449
KPIM::AddEmailAddressJob *job = new KPIM::AddEmailAddressJob( emailString, mMainWindow, this );
2629
453
//-----------------------------------------------------------------------------
2630
454
void KMReaderWin::slotMailtoOpenAddrBook()
2632
KMCommand *command = new KMMailtoOpenAddrBookCommand( mClickedUrl,
2637
//-----------------------------------------------------------------------------
2638
void KMReaderWin::slotUrlCopy()
2640
// we don't necessarily need a mainWidget for KMUrlCopyCommand so
2641
// it doesn't matter if the dynamic_cast fails.
2642
KMCommand *command =
2643
new KMUrlCopyCommand( mClickedUrl,
2644
dynamic_cast<KMMainWidget*>( mMainWindow ) );
2648
//-----------------------------------------------------------------------------
2649
void KMReaderWin::slotUrlOpen( const KUrl &url )
2651
if ( !url.isEmpty() )
2653
KMCommand *command = new KMUrlOpenCommand( mClickedUrl, this );
456
const QString emailString = KPIMUtils::decodeMailtoUrl( urlClicked() );
458
KPIM::OpenEmailAddressJob *job = new KPIM::OpenEmailAddressJob( emailString, mMainWindow, this );
2657
462
//-----------------------------------------------------------------------------
2658
463
void KMReaderWin::slotAddBookmarks()
2660
KMCommand *command = new KMAddBookmarksCommand( mClickedUrl, this );
465
KMCommand *command = new KMAddBookmarksCommand( urlClicked(), this );
2661
466
command->start();
2664
469
//-----------------------------------------------------------------------------
2665
470
void KMReaderWin::slotUrlSave()
2667
KMCommand *command = new KMUrlSaveCommand( mClickedUrl, mMainWindow );
472
KMCommand *command = new KMUrlSaveCommand( urlClicked(), mMainWindow );
2668
473
command->start();
2671
476
//-----------------------------------------------------------------------------
2672
477
void KMReaderWin::slotMailtoReply()
2674
KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mClickedUrl,
479
KMCommand *command = new KMMailtoReplyCommand( mMainWindow, urlClicked(),
2675
480
message(), copyText() );
2676
481
command->start();
2679
//-----------------------------------------------------------------------------
2680
partNode * KMReaderWin::partNodeFromUrl( const KUrl & url ) {
2681
return mRootNode ? mRootNode->findId( msgPartFromUrl( url ) ) : 0 ;
2684
partNode * KMReaderWin::partNodeForId( int id ) {
2685
return mRootNode ? mRootNode->findId( id ) : 0 ;
2689
KUrl KMReaderWin::tempFileUrlFromPartNode( const partNode *node )
2694
foreach ( const QString &path, mTempFiles ) {
2695
int right = path.lastIndexOf( '/' );
2696
int left = path.lastIndexOf( '.', right );
2699
int res = path.mid( left + 1, right - left - 1 ).toInt( &ok );
2700
if ( ok && res == node->nodeId() )
2701
return KUrl( path );
2706
//-----------------------------------------------------------------------------
2707
void KMReaderWin::slotSaveAttachments()
2710
KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( mMainWindow,
2712
saveCommand->start();
2715
//-----------------------------------------------------------------------------
2716
void KMReaderWin::saveAttachment( const KUrl &tempFileName )
2718
mAtmCurrent = msgPartFromUrl( tempFileName );
2719
mAtmCurrentName = mClickedUrl.toLocalFile();
2720
slotHandleAttachment( KMHandleAttachmentCommand::Save ); // save
2723
//-----------------------------------------------------------------------------
2724
void KMReaderWin::slotSaveMsg()
2726
KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( mMainWindow, message() );
2728
if (saveCommand->url().isEmpty())
2731
saveCommand->start();
2734
//-----------------------------------------------------------------------------
2735
bool KMReaderWin::eventFilter( QObject *, QEvent *e )
2737
if ( e->type() == QEvent::MouseButtonPress ) {
2738
QMouseEvent* me = static_cast<QMouseEvent*>(e);
2739
if ( me->button() == Qt::LeftButton && ( me->modifiers() & Qt::ShiftModifier ) ) {
2740
// special processing for shift+click
2741
URLHandlerManager::instance()->handleShiftClick( mHoveredUrl, this );
2745
if ( me->button() == Qt::LeftButton ) {
2746
mCanStartDrag = URLHandlerManager::instance()->willHandleDrag( mHoveredUrl, this );
2747
mLastClickPosition = me->pos();
2751
if ( e->type() == QEvent::MouseButtonRelease ) {
2752
mCanStartDrag = false;
2755
if ( e->type() == QEvent::MouseMove ) {
2756
QMouseEvent* me = static_cast<QMouseEvent*>( e );
2758
if ( ( mLastClickPosition - me->pos() ).manhattanLength() > KGlobalSettings::dndEventDelay() ) {
2759
if ( mCanStartDrag && !mHoveredUrl.isEmpty() && mHoveredUrl.protocol() == "attachment" ) {
2760
mCanStartDrag = false;
2761
URLHandlerManager::instance()->handleDrag( mHoveredUrl, this );
2762
slotUrlOn( QString() );
2768
// standard event processing
2772
void KMReaderWin::fillCommandInfo( partNode *node, KMMessage **msg, int *nodeId )
2774
Q_ASSERT( msg && nodeId );
2776
if ( mSerNumOfOriginalMessage != 0 ) {
2777
KMFolder *folder = 0;
2779
KMMsgDict::instance()->getLocation( mSerNumOfOriginalMessage, &folder, &index );
2780
if ( folder && index != -1 )
2781
*msg = folder->getMsg( index );
2784
kWarning() << "Unable to find the original message, aborting attachment deletion!";
2788
*nodeId = node->nodeId() + mNodeIdOffset;
2791
*nodeId = node->nodeId();
2796
void KMReaderWin::slotDeleteAttachment(partNode * node)
2798
if ( KMessageBox::warningContinueCancel( this,
2799
i18n("Deleting an attachment might invalidate any digital signature on this message."),
2800
i18n("Delete Attachment"), KStandardGuiItem::del(), KStandardGuiItem::cancel(),
2801
"DeleteAttachmentSignatureWarning" )
2802
!= KMessageBox::Continue ) {
2808
fillCommandInfo( node, &msg, &nodeId );
2809
if ( msg && nodeId != -1 ) {
2810
KMDeleteAttachmentCommand* command = new KMDeleteAttachmentCommand( nodeId, msg, this );
2814
// If we are operating on a copy of parts of the message, make sure to update the copy as well.
2815
if ( mSerNumOfOriginalMessage != 0 && message() ) {
2816
message()->deleteBodyPart( node->nodeId() );
2821
void KMReaderWin::slotEditAttachment(partNode * node)
2823
if ( KMessageBox::warningContinueCancel( this,
2824
i18n("Modifying an attachment might invalidate any digital signature on this message."),
2825
i18n("Edit Attachment"), KGuiItem( i18n("Edit"), "document-properties" ), KStandardGuiItem::cancel(),
2826
"EditAttachmentSignatureWarning" )
2827
!= KMessageBox::Continue ) {
2833
fillCommandInfo( node, &msg, &nodeId );
2834
if ( msg && nodeId != -1 ) {
2835
KMEditAttachmentCommand* command = new KMEditAttachmentCommand( nodeId, msg, this );
2839
// FIXME: If we are operating on a copy of parts of the message, make sure to update the copy as well.
2842
KMail::CSSHelper* KMReaderWin::cssHelper() const
2847
bool KMReaderWin::decryptMessage() const
2849
if ( !GlobalSettings::self()->alwaysDecrypt() )
2850
return mDecrytMessageOverwrite;
2854
void KMReaderWin::scrollToAttachment( const partNode *node )
2856
DOM::Document doc = mViewer->htmlDocument();
2858
// The anchors for this are created in ObjectTreeParser::parseObjectTree()
2859
mViewer->gotoAnchor( QString::fromLatin1( "att%1" ).arg( node->nodeId() ) );
2861
// Remove any old color markings which might be there
2862
const partNode *root = node->topLevelParent();
2863
for ( int i = 0; i <= root->totalChildCount() + 1; i++ ) {
2864
DOM::Element attachmentDiv = doc.getElementById( QString( "attachmentDiv%1" ).arg( i + 1 ) );
2865
if ( !attachmentDiv.isNull() )
2866
attachmentDiv.removeAttribute( "style" );
2869
// Now, color the div of the attachment in yellow, so that the user sees what happened.
2870
// We created a special marked div for this in writeAttachmentMarkHeader() in ObjectTreeParser,
2871
// find and modify that now.
2872
DOM::Element attachmentDiv = doc.getElementById( QString( "attachmentDiv%1" ).arg( node->nodeId() ) );
2873
if ( attachmentDiv.isNull() ) {
2874
kWarning() << "Could not find attachment div for attachment" << node->nodeId();
2877
attachmentDiv.setAttribute( "style", QString( "border:2px solid %1" )
2878
.arg( cssHelper()->pgpWarnColor().name() ) );
2880
// Update rendering, otherwise the rendering is not updated when the user clicks on an attachment
2881
// that causes scrolling and the open attachment dialog
2882
doc.updateRendering();
2885
void KMReaderWin::toggleFullAddressList()
2887
toggleFullAddressList( "To" );
2888
toggleFullAddressList( "Cc" );
2891
DOM::HTMLElement KMReaderWin::getHTMLElementById( const QString &id )
2893
Q_ASSERT( !id.isNull() );
2894
Q_ASSERT( !id.isEmpty() );
2895
DOM::Document doc = mViewer->htmlDocument();
2896
return static_cast<DOM::HTMLElement>( doc.getElementById( id ) );
2899
void KMReaderWin::toggleFullAddressList( const QString &field )
2901
// First inject the current icon
2902
DOM::HTMLElement tag = getHTMLElementById( "iconFull" + field + "AddressList" );
2905
Q_ASSERT( tag.tagName() == "span" );
2907
QString imgpath( KStandardDirs::locate( "data","kmail/pics/" ) );
2910
bool doShow = ( field == "To" && showFullToAddressList() ) || ( field == "Cc" && showFullCcAddressList() );
2912
urlHandle.append( "kmail:hideFull" + field + "AddressList" );
2913
imgSrc.append( "quicklistOpened.png" );
2915
urlHandle.append( "kmail:showFull" + field + "AddressList" );
2916
imgSrc.append( "quicklistClosed.png" );
2919
QString link = "<span style=\"text-align: right;\"><a href=\"" + urlHandle + "\"><img src=\"" + imgpath + imgSrc + "\"/></a></span>";
2920
tag.setInnerHTML( link );
2922
// Then show/hide the full address list
2923
DOM::HTMLElement dotsTag = getHTMLElementById( "dotsFull" + field + "AddressList" );
2924
Q_ASSERT( dotsTag.tagName() == "span" );
2926
tag = getHTMLElementById( "hiddenFull" + field + "AddressList" );
2927
Q_ASSERT( tag.tagName() == "span" );
2930
dotsTag.addCSSProperty( "display", "none" );
2931
tag.removeCSSProperty( "display" );
2933
tag.addCSSProperty( "display", "none" );
2934
dotsTag.removeCSSProperty( "display" );
2938
void KMReaderWin::injectAttachments()
2940
// inject attachments in header view
2941
// we have to do that after the otp has run so we also see encrypted parts
2942
DOM::Document doc = mViewer->htmlDocument();
2943
DOM::Element injectionPoint = doc.getElementById( "attachmentInjectionPoint" );
2944
if ( injectionPoint.isNull() )
2947
QString imgpath( KStandardDirs::locate("data","kmail/pics/") );
2951
if( !showAttachmentQuicklist() ) {
2952
urlHandle.append( "kmail:showAttachmentQuicklist" );
2953
imgSrc.append( "quicklistClosed.png" );
2955
urlHandle.append( "kmail:hideAttachmentQuicklist" );
2956
imgSrc.append( "quicklistOpened.png" );
2959
QColor background = KColorScheme( QPalette::Active, KColorScheme::View ).background().color();
2960
QString html = renderAttachments( mRootNode, background );
2961
if ( html.isEmpty() )
2965
if ( headerStyle() == HeaderStyle::fancy() ) {
2966
link += "<div style=\"text-align: left;\"><a href=\""+urlHandle+"\"><img src=\""+imgpath+imgSrc+"\"/></a></div>";
2967
html.prepend( link );
2968
html.prepend( QString::fromLatin1("<div style=\"float:left;\">%1 </div>" ).arg(i18n("Attachments:")) );
2970
link += "<div style=\"text-align: right;\"><a href=\""+urlHandle+"\"><img src=\""+imgpath+imgSrc+"\"/></a></div>";
2971
html.prepend( link );
2974
assert( injectionPoint.tagName() == "div" );
2975
static_cast<DOM::HTMLElement>( injectionPoint ).setInnerHTML( html );
2978
static QColor nextColor( const QColor & c )
2981
c.getHsv( &h, &s, &v );
2982
return QColor::fromHsv( (h + 50) % 360, qMax(s, 64), v );
2985
QString KMReaderWin::renderAttachments(partNode * node, const QColor &bgColor )
2991
if ( node->firstChild() ) {
2992
QString subHtml = renderAttachments( node->firstChild(), nextColor( bgColor ) );
2993
if ( !subHtml.isEmpty() ) {
2996
if( !showAttachmentQuicklist() ) {
2997
visibility.append( "display:none;" );
3001
if ( node != mRootNode || headerStyle() != HeaderStyle::enterprise() )
3002
margin = "padding:2px; margin:2px; ";
3003
QString align = "left";
3004
if ( headerStyle() == HeaderStyle::enterprise() )
3006
if ( node->msgPart().typeStr().toLower() == "message" || node == mRootNode )
3007
html += QString::fromLatin1("<div style=\"background:%1; %2"
3008
"vertical-align:middle; float:%3; %4\">").arg( bgColor.name() ).arg( margin )
3009
.arg( align ).arg( visibility );
3011
if ( node->msgPart().typeStr().toLower() == "message" || node == mRootNode )
3015
QString label, icon;
3016
icon = node->msgPart().iconName( KIconLoader::Small );
3017
label = node->msgPart().contentDescription();
3018
if( label.isEmpty() )
3019
label = node->msgPart().name().trimmed();
3020
if( label.isEmpty() )
3021
label = node->msgPart().fileName();
3022
bool typeBlacklisted = node->msgPart().typeStr().toLower() == "multipart";
3023
if ( !typeBlacklisted ) {
3024
typeBlacklisted = StringUtil::isCryptoPart( node->msgPart().typeStr(), node->msgPart().subtypeStr(),
3025
node->msgPart().fileName() );
3027
typeBlacklisted = typeBlacklisted || node == mRootNode;
3028
bool firstTextChildOfEncapsulatedMsg = node->msgPart().typeStr().toLower() == "text" &&
3029
node->msgPart().subtypeStr().toLower() == "plain" &&
3030
node->parentNode() &&
3031
node->parentNode()->msgPart().typeStr().toLower() == "message";
3032
typeBlacklisted = typeBlacklisted || firstTextChildOfEncapsulatedMsg;
3033
if ( !label.isEmpty() && !icon.isEmpty() && !typeBlacklisted ) {
3034
html += "<div style=\"float:left;\">";
3035
html += QString::fromLatin1( "<span style=\"white-space:nowrap; border-width: 0px; border-left-width: 5px; border-color: %1; 2px; border-left-style: solid;\">" ).arg( bgColor.name() );
3036
QString fileName = writeMessagePartToTempFile( &node->msgPart(), node->nodeId() );
3037
QString href = node->asHREF( "header" );
3038
html += QString::fromLatin1( "<a href=\"" ) + href +
3039
QString::fromLatin1( "\">" );
3040
html += "<img style=\"vertical-align:middle;\" src=\"" + icon + "\"/> ";
3041
if ( headerStyle() == HeaderStyle::enterprise() ) {
3042
QFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
3043
QFontMetrics fm( bodyFont );
3044
html += fm.elidedText( label, Qt::ElideRight, 180 );
3045
} else if ( headerStyle() == HeaderStyle::fancy() ) {
3046
QFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
3047
QFontMetrics fm( bodyFont );
3048
html += fm.elidedText( label, Qt::ElideRight, 1000 );
3052
html += "</a></span></div> ";
3056
html += renderAttachments( node->nextSibling(), nextColor ( bgColor ) );
3060
using namespace KMail::Interface;
3062
void KMReaderWin::setBodyPartMemento( const partNode *node,
3063
const QByteArray &which,
3064
BodyPartMemento *memento )
3066
const QByteArray index = node->path() + ':' + which.toLower();
3068
const std::map<QByteArray,BodyPartMemento*>::iterator it =
3069
mBodyPartMementoMap.lower_bound( index );
3071
if ( it != mBodyPartMementoMap.end() && it->first == index ) {
3072
if ( memento && memento == it->second ) {
3079
it->second = memento;
3081
mBodyPartMementoMap.erase( it );
3085
mBodyPartMementoMap.insert( it, std::make_pair( index, memento ) );
3089
if ( Observable * o = memento ? memento->asObservable() : 0 ) {
3096
BodyPartMemento *KMReaderWin::bodyPartMemento( const partNode *node,
3097
const QByteArray &which ) const
3099
const QByteArray index = node->path() + ':' + which.toLower();
3100
const std::map<QByteArray,BodyPartMemento*>::const_iterator it =
3101
mBodyPartMementoMap.find( index );
3103
if ( it == mBodyPartMementoMap.end() ) {
3110
void KMReaderWin::clearBodyPartMementos()
3112
for ( std::map<QByteArray,BodyPartMemento*>::const_iterator
3113
it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end();
3117
mBodyPartMementoMap.clear();
3120
bool KMReaderWin::showFullToAddressList() const
3122
return mShowFullToAddressList;
3125
void KMReaderWin::setShowFullToAddressList( bool showFullToAddressList )
3127
mShowFullToAddressList = showFullToAddressList;
3130
bool KMReaderWin::showFullCcAddressList() const
3132
return mShowFullCcAddressList;
3135
void KMReaderWin::setShowFullCcAddressList( bool showFullCcAddressList )
3137
mShowFullCcAddressList = showFullCcAddressList;
485
CSSHelper* KMReaderWin::cssHelper() const
487
return mViewer->cssHelper();
490
bool KMReaderWin::htmlLoadExtOverride() const
492
return mViewer->htmlLoadExtOverride();
494
void KMReaderWin::setDecryptMessageOverwrite( bool overwrite )
496
mViewer->setDecryptMessageOverwrite( overwrite );
498
const AttachmentStrategy * KMReaderWin::attachmentStrategy() const
500
return mViewer->attachmentStrategy();
503
QString KMReaderWin::overrideEncoding() const
505
return mViewer->overrideEncoding();
508
KToggleAction *KMReaderWin::toggleFixFontAction()
510
return mViewer->toggleFixFontAction();
513
KAction *KMReaderWin::toggleMimePartTreeAction()
515
return mViewer->toggleMimePartTreeAction();
518
KAction *KMReaderWin::selectAllAction()
520
return mViewer->selectAllAction();
523
const HeaderStrategy * KMReaderWin::headerStrategy() const
525
return mViewer->headerStrategy();
528
HeaderStyle * KMReaderWin::headerStyle() const
530
return mViewer->headerStyle();
533
KAction *KMReaderWin::copyURLAction()
535
return mViewer->copyURLAction();
538
KAction *KMReaderWin::copyAction()
540
return mViewer->copyAction();
542
KAction *KMReaderWin::urlOpenAction()
544
return mViewer->urlOpenAction();
546
void KMReaderWin::setPrinting(bool enable)
548
mViewer->setPrinting( enable );
551
void KMReaderWin::clear(bool force )
553
mViewer->clear( force ? Viewer::Force : Viewer::Delayed );
556
void KMReaderWin::setMessage( const Akonadi::Item &item, Viewer::UpdateMode updateMode)
558
kDebug() << Q_FUNC_INFO << parentWidget();
559
mViewer->setMessageItem( item, updateMode );
562
void KMReaderWin::setMessage( KMime::Message::Ptr message)
564
mViewer->setMessage( message );
568
KUrl KMReaderWin::urlClicked() const
570
return mViewer->urlClicked();
573
void KMReaderWin::update( bool force )
575
mViewer->update( force ? Viewer::Force : Viewer::Delayed );
578
void KMReaderWin::slotUrlClicked( const Akonadi::Item & item, const KUrl & url )
581
if ( item.isValid() && item.parentCollection().isValid() ) {
582
QSharedPointer<FolderCollection> fd = FolderCollection::forCollection( item.parentCollection() );
584
identity = fd->identity();
586
KMail::Util::handleClickedURL( url, identity );
589
void KMReaderWin::slotShowReader( KMime::Content* msgPart, bool htmlMail, const QString &encoding )
591
KMReaderMainWin *win = new KMReaderMainWin( msgPart, htmlMail, encoding );
595
void KMReaderWin::slotShowMessage( KMime::Message::Ptr message, const QString& encoding )
597
KMReaderMainWin *win = new KMReaderMainWin();
598
win->showMessage( encoding, message );
602
void KMReaderWin::slotDeleteMessage(const Akonadi::Item& item)
604
if ( !item.isValid() )
606
KMTrashMsgCommand *command = new KMTrashMsgCommand( item.parentCollection(), item, -1 );
3140
611
#include "kmreaderwin.moc"