1 /* -*- mode: C++; c-file-style: "gnu" -*-
2 This file is part of KMail, the KDE mail client.
3 Copyright (c) 1997 Markus Wuebben <markus.wuebben@kde.org>
4 Copyright (c) 2009 Laurent Montel <montel@kde.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 // define this to copy all html that is written to the readerwindow to
22 // filehtmlwriter.out in the current working directory
23 #include "kmreaderwin.h"
25 #include "globalsettings.h"
26 #include "kmversion.h"
27 #include "kmmainwidget.h"
28 #include "kmreadermainwin.h"
29 #include <kpimutils/email.h>
30 #include <kpimutils/kfileio.h>
31 #include <libkdepim/addemailaddressjob.h>
32 #include <libkdepim/openemailaddressjob.h>
33 #include "kmcommands.h"
34 #include "mdnadvicedialog.h"
36 #include <QVBoxLayout>
37 #include "messageviewer/headerstrategy.h"
38 #include "messageviewer/headerstyle.h"
39 #include "messageviewer/mailwebview.h"
40 #include "messageviewer/globalsettings.h"
42 #include <Akonadi/ItemModifyJob>
45 #include "messageviewer/csshelper.h"
46 using MessageViewer::CSSHelper
;
49 #include "messageviewer/attachmentdialog.h"
50 #include "stringutil.h"
52 #include <kmime/kmime_mdn.h>
53 using namespace KMime
;
55 #include "messageviewer/viewer.h"
56 using namespace MessageViewer
;
57 #include "messageviewer/attachmentstrategy.h"
58 #include "messagecomposer/messagesender.h"
59 #include "messagecomposer/messagefactory.h"
60 using MessageComposer::MessageFactory
;
62 #include "messagecore/messagehelpers.h"
66 #include <kabc/addressee.h>
67 #include <kabc/vcardconverter.h>
71 #include <kactionmenu.h>
72 // for the click on attachment stuff (dnaber):
73 #include <kcharsets.h>
76 #include <kfiledialog.h>
78 #include <kmessagebox.h>
79 #include <kmimetypetrader.h>
80 #include <kglobalsettings.h>
82 #include <ktemporaryfile.h>
85 #include <kfontaction.h>
86 #include <kiconloader.h>
89 #include <kselectaction.h>
90 #include <kstandardaction.h>
91 #include <ktoggleaction.h>
92 #include <kconfiggroup.h>
102 #include <sys/stat.h>
107 using namespace KMail
;
109 //-----------------------------------------------------------------------------
110 KMReaderWin::KMReaderWin(QWidget
*aParent
,
112 KActionCollection
* actionCollection
,
113 Qt::WindowFlags aFlags
)
114 : QWidget(aParent
, aFlags
),
115 mMainWindow( mainWindow
),
116 mActionCollection( actionCollection
),
117 mMailToComposeAction( 0 ),
118 mMailToReplyAction( 0 ),
119 mMailToForwardAction( 0 ),
120 mAddAddrBookAction( 0 ),
121 mOpenAddrBookAction( 0 ),
122 mUrlSaveAsAction( 0 ),
123 mAddBookmarksAction( 0 )
126 QVBoxLayout
* vlay
= new QVBoxLayout( this );
127 vlay
->setMargin( 0 );
128 mViewer
= new Viewer( this, mainWindow
, mActionCollection
);
129 mViewer
->setAppName( "KMail" );
130 connect( mViewer
, SIGNAL(urlClicked( const Akonadi::Item
&, const KUrl
& ) ),
131 this, SLOT( slotUrlClicked( const Akonadi::Item
&, const KUrl
& ) ) );
132 connect( mViewer
, SIGNAL( requestConfigSync() ), kmkernel
, SLOT( slotRequestConfigSync() ) );
133 connect( mViewer
, SIGNAL( showReader( KMime::Content
* , bool, const QString
& ) ),
134 this, SLOT( slotShowReader( KMime::Content
* , bool, const QString
& ) ) );
135 connect( mViewer
, SIGNAL( showMessage(KMime::Message::Ptr
, const QString
&) ),
136 this, SLOT( slotShowMessage(KMime::Message::Ptr
, const QString
& ) ) );
137 connect( mViewer
, SIGNAL( showStatusBarMessage( const QString
& ) ),
138 this, SIGNAL( showStatusBarMessage( const QString
& ) ) );
139 connect( mViewer
, SIGNAL( deleteMessage( Akonadi::Item
) ),
140 this, SLOT( slotDeleteMessage( Akonadi::Item
) ) );
141 vlay
->addWidget( mViewer
);
144 mDelayedMarkTimer
.setSingleShot( true );
145 connect( &mDelayedMarkTimer
, SIGNAL(timeout()),
146 this, SLOT(slotTouchMessage()) );
149 void KMReaderWin::createActions()
151 KActionCollection
*ac
= mActionCollection
;
159 mMailToComposeAction
= new KAction( KIcon( "mail-message-new" ),
160 i18n( "New Message To..." ), this );
161 ac
->addAction("mail_new", mMailToComposeAction
);
162 connect( mMailToComposeAction
, SIGNAL(triggered(bool)),
163 SLOT(slotMailtoCompose()) );
166 mMailToReplyAction
= new KAction( KIcon( "mail-reply-sender" ),
167 i18n( "Reply To..." ), this );
168 ac
->addAction( "mailto_reply", mMailToReplyAction
);
169 connect( mMailToReplyAction
, SIGNAL(triggered(bool)),
170 SLOT(slotMailtoReply()) );
173 mMailToForwardAction
= new KAction( KIcon( "mail-forward" ),
174 i18n( "Forward To..." ), this );
175 ac
->addAction( "mailto_forward", mMailToForwardAction
);
176 connect( mMailToForwardAction
, SIGNAL(triggered(bool)),
177 SLOT(slotMailtoForward()) );
179 // add to addressbook
180 mAddAddrBookAction
= new KAction( KIcon( "contact-new" ),
181 i18n( "Add to Address Book" ), this );
182 ac
->addAction( "add_addr_book", mAddAddrBookAction
);
183 connect( mAddAddrBookAction
, SIGNAL(triggered(bool)),
184 SLOT(slotMailtoAddAddrBook()) );
186 // open in addressbook
187 mOpenAddrBookAction
= new KAction( KIcon( "view-pim-contacts" ),
188 i18n( "Open in Address Book" ), this );
189 ac
->addAction( "openin_addr_book", mOpenAddrBookAction
);
190 connect( mOpenAddrBookAction
, SIGNAL(triggered(bool)),
191 SLOT(slotMailtoOpenAddrBook()) );
193 mAddBookmarksAction
= new KAction( KIcon( "bookmark-new" ), i18n( "Bookmark This Link" ), this );
194 ac
->addAction( "add_bookmarks", mAddBookmarksAction
);
195 connect( mAddBookmarksAction
, SIGNAL(triggered(bool)),
196 SLOT(slotAddBookmarks()) );
199 mUrlSaveAsAction
= new KAction( i18n( "Save Link As..." ), this );
200 ac
->addAction( "saveas_url", mUrlSaveAsAction
);
201 connect( mUrlSaveAsAction
, SIGNAL(triggered(bool)), SLOT(slotUrlSave()) );
204 KAction
*action
= new KAction(KIcon("edit-find"), i18n("&Find in Message..."), this);
205 ac
->addAction("find_in_messages", action
);
206 connect(action
, SIGNAL(triggered(bool)), SLOT(slotFind()));
207 action
->setShortcut(KStandardShortcut::find());
211 void KMReaderWin::setUseFixedFont( bool useFixedFont
)
213 mViewer
->setUseFixedFont( useFixedFont
);
216 bool KMReaderWin::isFixedFont() const
218 return mViewer
->isFixedFont();
221 //-----------------------------------------------------------------------------
222 KMReaderWin::~KMReaderWin()
227 //-----------------------------------------------------------------------------
228 void KMReaderWin::readConfig(void)
230 mViewer
->readConfig();
233 void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy
* strategy
) {
234 mViewer
->setAttachmentStrategy( strategy
);
237 void KMReaderWin::setHeaderStyleAndStrategy( HeaderStyle
* style
,
238 const HeaderStrategy
* strategy
) {
239 mViewer
->setHeaderStyleAndStrategy( style
, strategy
);
241 //-----------------------------------------------------------------------------
242 void KMReaderWin::setOverrideEncoding( const QString
& encoding
)
244 mViewer
->setOverrideEncoding( encoding
);
247 //-----------------------------------------------------------------------------
248 void KMReaderWin::clearCache()
251 mDelayedMarkTimer
.stop();
254 // enter items for the "Important changes" list here:
255 static const char * const kmailChanges
[] = {
256 "KMail is now based on the Akonadi Personal Information Management framework, which brings many "
257 "changes all around."
259 static const int numKMailChanges
=
260 sizeof kmailChanges
/ sizeof *kmailChanges
;
262 // enter items for the "new features" list here, so the main body of
263 // the welcome page can be left untouched (probably much easier for
264 // the translators). Note that the <li>...</li> tags are added
265 // automatically below:
266 static const char * const kmailNewFeatures
[] = {
267 "Push email (IMAP IDLE)",
268 "Improved virtual folders",
270 "Support for adding notes (annotations) to mails",
272 "Less GUI freezes, mail checks happen in the background"
274 static const int numKMailNewFeatures
=
275 sizeof kmailNewFeatures
/ sizeof *kmailNewFeatures
;
278 //-----------------------------------------------------------------------------
280 QString
KMReaderWin::newFeaturesMD5()
283 for ( int i
= 0 ; i
< numKMailChanges
; ++i
)
284 str
+= kmailChanges
[i
];
285 for ( int i
= 0 ; i
< numKMailNewFeatures
; ++i
)
286 str
+= kmailNewFeatures
[i
];
288 return md5
.base64Digest();
291 //-----------------------------------------------------------------------------
292 void KMReaderWin::displaySplashPage( const QString
&info
)
294 mViewer
->displaySplashPage( info
);
297 void KMReaderWin::displayBusyPage()
300 i18n( "<h2 style='margin-top: 0px;'>Retrieving Folder Contents</h2><p>Please wait . . .</p> " );
302 displaySplashPage( info
);
305 void KMReaderWin::displayOfflinePage()
308 i18n( "<h2 style='margin-top: 0px;'>Offline</h2><p>KMail is currently in offline mode. "
309 "Click <a href=\"kmail:goOnline\">here</a> to go online . . .</p> " );
311 displaySplashPage( info
);
315 //-----------------------------------------------------------------------------
316 void KMReaderWin::displayAboutPage()
318 KLocalizedString info
=
319 ki18nc("%1: KMail version; %2: help:// URL; "
320 "%3: generated list of new features; "
321 "%4: First-time user text (only shown on first start); "
322 "%5: generated list of important changes; "
323 "--- end of comment ---",
324 "<h2 style='margin-top: 0px;'>Welcome to KMail %1</h2><p>KMail is the email client by KDE."
325 "It is designed to be fully compatible with "
326 "Internet mailing standards including MIME, SMTP, POP3, and IMAP."
328 "<ul><li>KMail has many powerful features which are described in the "
329 "<a href=\"%2\">documentation</a></li>\n"
330 "%5\n" // important changes
331 "%3\n" // new features
332 "%4\n" // first start info
333 "<p>We hope that you will enjoy KMail.</p>\n"
334 "<p>Thank you,</p>\n"
335 "<p style='margin-bottom: 0px'> The KMail Team</p>")
336 .subs( KMAIL_VERSION
)
337 .subs( "help:/kmail/index.html" );
339 if ( ( numKMailNewFeatures
> 1 ) || ( numKMailNewFeatures
== 1 && strlen(kmailNewFeatures
[0]) > 0 ) ) {
340 QString featuresText
=
341 i18n("<p>Some of the new features in this release of KMail include "
342 "(compared to KMail %1, which is part of KDE Software Compilation %2):</p>\n",
343 QString("1.13"), KDE::versionString() ); // prior KMail and KDE version
344 featuresText
+= "<ul>\n";
345 for ( int i
= 0 ; i
< numKMailNewFeatures
; i
++ )
346 featuresText
+= "<li>" + i18n( kmailNewFeatures
[i
] ) + "</li>\n";
347 featuresText
+= "</ul>\n";
348 info
= info
.subs( featuresText
);
351 info
= info
.subs( QString() ); // remove the place holder
353 if( kmkernel
->firstStart() ) {
354 info
= info
.subs( i18n("<p>Please take a moment to fill in the KMail "
355 "configuration panel at Settings->Configure "
357 "You need to create at least a default identity and "
358 "an incoming as well as outgoing mail account."
361 info
= info
.subs( QString() ); // remove the place holder
364 if ( ( numKMailChanges
> 1 ) || ( numKMailChanges
== 1 && strlen(kmailChanges
[0]) > 0 ) ) {
365 QString changesText
=
366 i18n("<p><span style='font-size:125%; font-weight:bold;'>"
367 "Important changes</span> (compared to KMail %1):</p>\n",
369 changesText
+= "<ul>\n";
370 for ( int i
= 0 ; i
< numKMailChanges
; i
++ )
371 changesText
+= i18n("<li>%1</li>\n", i18n( kmailChanges
[i
] ) );
372 changesText
+= "</ul>\n";
373 info
= info
.subs( changesText
);
376 info
= info
.subs( QString() ); // remove the place holder
378 displaySplashPage( info
.toString() );
383 //-----------------------------------------------------------------------------
384 void KMReaderWin::slotTouchMessage()
386 if ( !message().isValid() )
388 MessageStatus status
;
389 status
.setStatusFromFlags( message().flags() );
391 if ( !status
.isUnread() )
394 Akonadi::Item::List items
;
395 items
.append( message() );
396 KMCommand
*command
= new KMSetStatusCommand( MessageStatus::statusRead(), items
);
399 // should we send an MDN?
400 if ( MessageViewer::GlobalSettings::notSendWhenEncrypted() &&
401 message()->encryptionState() != KMMsgNotEncrypted
&&
402 message()->encryptionState() != KMMsgEncryptionStateUnknown
)
405 kDebug() << "AKONADI PORT: Disabled code in " << Q_FUNC_INFO
;
407 Akonadi::Collection col
= message().parentCollection();
408 if ( col
.isValid() &&
409 ( KMKernel::self()->folderIsSentMailFolder( col
) ||
410 KMKernel::self()->folderIsTrash( col
) ||
411 KMKernel::self()->folderIsDraftOrOutbox( col
) ||
412 KMKernel::self()->folderIsTemplates( col
) ) )
415 KMime::Message::Ptr msg
= MessageCore::Util::message( message() );
419 QPair
< bool, KMime::MDN::SendingMode
> mdnSend
= MDNAdviceHelper::instance()->checkAndSetMDNInfo( message(), KMime::MDN::Displayed
);
420 if( mdnSend
.first
) {
421 KConfigGroup
mdnConfig( KMKernel::config(), "MDN" );
422 int quote
= mdnConfig
.readEntry
<int>( "quote-message", 0 );
423 MessageFactory
factory( msg
, Akonadi::Item().id() );
424 factory
.setIdentityManager( KMKernel::self()->identityManager() );
425 factory
.setFolderIdentity( KMail::Util::folderIdentity( message() ) );
426 KMime::Message::Ptr mdn
= factory
.createMDN( KMime::MDN::ManualAction
, KMime::MDN::Displayed
, mdnSend
.second
, quote
);
428 if( !kmkernel
->msgSender()->send( mdn
, MessageSender::SendLater
) ) {
429 kDebug() << "Sending failed.";
437 //-----------------------------------------------------------------------------
438 void KMReaderWin::slotFind()
442 //-----------------------------------------------------------------------------
443 void KMReaderWin::slotCopySelectedText()
445 QString selection
= mViewer
->selectedText();
446 selection
.replace( QChar::Nbsp
, ' ' );
447 QApplication::clipboard()->setText( selection
);
450 //-----------------------------------------------------------------------------
451 void KMReaderWin::setMsgPart( KMime::Content
* aMsgPart
)
453 mViewer
->setMessagePart( aMsgPart
);
456 //-----------------------------------------------------------------------------
457 QString
KMReaderWin::copyText() const
459 return mViewer
->selectedText();
462 //-----------------------------------------------------------------------------
463 void KMReaderWin::setHtmlOverride( bool override
)
465 mViewer
->setHtmlOverride( override
);
468 bool KMReaderWin::htmlOverride() const
470 return mViewer
->htmlOverride();
473 //-----------------------------------------------------------------------------
474 void KMReaderWin::setHtmlLoadExtOverride( bool override
)
476 mViewer
->setHtmlLoadExtOverride( override
);
479 //-----------------------------------------------------------------------------
480 bool KMReaderWin::htmlMail()
482 return mViewer
->htmlMail();
485 //-----------------------------------------------------------------------------
486 bool KMReaderWin::htmlLoadExternal()
488 return mViewer
->htmlLoadExternal();
491 //-----------------------------------------------------------------------------
492 Akonadi::Item
KMReaderWin::message() const
494 return mViewer
->messageItem();
497 //-----------------------------------------------------------------------------
498 void KMReaderWin::slotMailtoCompose()
500 KMCommand
*command
= new KMMailtoComposeCommand( urlClicked(), message() );
504 //-----------------------------------------------------------------------------
505 void KMReaderWin::slotMailtoForward()
507 KMCommand
*command
= new KMMailtoForwardCommand( mMainWindow
, urlClicked(),
512 //-----------------------------------------------------------------------------
513 void KMReaderWin::slotMailtoAddAddrBook()
515 const QString emailString
= KPIMUtils::decodeMailtoUrl( urlClicked() );
517 KPIM::AddEmailAddressJob
*job
= new KPIM::AddEmailAddressJob( emailString
, mMainWindow
, this );
521 //-----------------------------------------------------------------------------
522 void KMReaderWin::slotMailtoOpenAddrBook()
524 const QString emailString
= KPIMUtils::decodeMailtoUrl( urlClicked() );
526 KPIM::OpenEmailAddressJob
*job
= new KPIM::OpenEmailAddressJob( emailString
, mMainWindow
, this );
530 //-----------------------------------------------------------------------------
531 void KMReaderWin::slotAddBookmarks()
533 KMCommand
*command
= new KMAddBookmarksCommand( urlClicked(), this );
537 //-----------------------------------------------------------------------------
538 void KMReaderWin::slotUrlSave()
540 KMCommand
*command
= new KMUrlSaveCommand( urlClicked(), mMainWindow
);
544 //-----------------------------------------------------------------------------
545 void KMReaderWin::slotMailtoReply()
547 KMCommand
*command
= new KMMailtoReplyCommand( mMainWindow
, urlClicked(),
548 message(), copyText() );
553 CSSHelper
* KMReaderWin::cssHelper() const
555 return mViewer
->cssHelper();
558 bool KMReaderWin::htmlLoadExtOverride() const
560 return mViewer
->htmlLoadExtOverride();
562 void KMReaderWin::setDecryptMessageOverwrite( bool overwrite
)
564 mViewer
->setDecryptMessageOverwrite( overwrite
);
566 const AttachmentStrategy
* KMReaderWin::attachmentStrategy() const
568 return mViewer
->attachmentStrategy();
571 QString
KMReaderWin::overrideEncoding() const
573 return mViewer
->overrideEncoding();
576 KToggleAction
*KMReaderWin::toggleFixFontAction()
578 return mViewer
->toggleFixFontAction();
581 KAction
*KMReaderWin::toggleMimePartTreeAction()
583 return mViewer
->toggleMimePartTreeAction();
586 KAction
*KMReaderWin::selectAllAction()
588 return mViewer
->selectAllAction();
591 const HeaderStrategy
* KMReaderWin::headerStrategy() const
593 return mViewer
->headerStrategy();
596 HeaderStyle
* KMReaderWin::headerStyle() const
598 return mViewer
->headerStyle();
601 KAction
*KMReaderWin::copyURLAction()
603 return mViewer
->copyURLAction();
606 KAction
*KMReaderWin::copyAction()
608 return mViewer
->copyAction();
610 KAction
*KMReaderWin::urlOpenAction()
612 return mViewer
->urlOpenAction();
614 void KMReaderWin::setPrinting(bool enable
)
616 mViewer
->setPrinting( enable
);
619 void KMReaderWin::clear(bool force
)
621 mViewer
->clear( force
? Viewer::Force
: Viewer::Delayed
);
624 void KMReaderWin::setMessage( const Akonadi::Item
&item
, Viewer::UpdateMode updateMode
)
626 kDebug() << Q_FUNC_INFO
<< parentWidget();
627 mViewer
->setMessageItem( item
, updateMode
);
629 mDelayedMarkTimer
.stop();
630 if ( item
.isValid() ) {
631 MessageStatus status
;
632 status
.setStatusFromFlags( item
.flags() );
633 if ( status
.isUnread() && MessageViewer::GlobalSettings::self()->delayedMarkAsRead() ) {
634 if (MessageViewer::GlobalSettings::self()->delayedMarkTime() != 0 )
635 mDelayedMarkTimer
.start( MessageViewer::GlobalSettings::self()->delayedMarkTime() * 1000 );
642 void KMReaderWin::setMessage(Message::Ptr message
)
644 mViewer
->setMessage( message
);
648 KUrl
KMReaderWin::urlClicked() const
650 return mViewer
->urlClicked();
653 void KMReaderWin::update( bool force
)
655 mViewer
->update( force
? Viewer::Force
: Viewer::Delayed
);
658 void KMReaderWin::slotUrlClicked( const Akonadi::Item
& item
, const KUrl
& url
)
661 if ( item
.isValid() && item
.parentCollection().isValid() ) {
662 QSharedPointer
<FolderCollection
> fd
= FolderCollection::forCollection( item
.parentCollection() );
664 identity
= fd
->identity();
666 KMail::Util::handleClickedURL( url
, identity
);
669 void KMReaderWin::slotShowReader( KMime::Content
* msgPart
, bool htmlMail
, const QString
&encoding
)
671 KMReaderMainWin
*win
= new KMReaderMainWin( msgPart
, htmlMail
, encoding
);
675 void KMReaderWin::slotShowMessage( KMime::Message::Ptr message
, const QString
& encoding
)
677 KMReaderMainWin
*win
= new KMReaderMainWin();
678 win
->showMessage( encoding
, message
);
682 void KMReaderWin::slotDeleteMessage(const Akonadi::Item
& item
)
684 if ( !item
.isValid() )
686 KMTrashMsgCommand
*command
= new KMTrashMsgCommand( item
.parentCollection(), item
, -1 );
691 #include "kmreaderwin.moc"