00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <config.h>
00010
00011 #include "kmreaderwin.h"
00012
00013 #include "globalsettings.h"
00014 #include "kmversion.h"
00015 #include "kmmainwidget.h"
00016 #include "kmreadermainwin.h"
00017 #include "kmailicalifaceimpl.h"
00018 #include <kpgpblock.h>
00019 #include <libkdepim/kfileio.h>
00020 #include "kmfolderindex.h"
00021 #include "kmcommands.h"
00022 #include "kmmsgpartdlg.h"
00023 #include "mailsourceviewer.h"
00024 using KMail::MailSourceViewer;
00025 #include "partNode.h"
00026 #include "kmmsgdict.h"
00027 #include "kmsender.h"
00028 #include "kcursorsaver.h"
00029 #include "kmkernel.h"
00030 #include "kmfolder.h"
00031 #include "vcardviewer.h"
00032 using KMail::VCardViewer;
00033 #include "objecttreeparser.h"
00034 using KMail::ObjectTreeParser;
00035 #include "partmetadata.h"
00036 using KMail::PartMetaData;
00037 #include "attachmentstrategy.h"
00038 using KMail::AttachmentStrategy;
00039 #include "headerstrategy.h"
00040 using KMail::HeaderStrategy;
00041 #include "headerstyle.h"
00042 using KMail::HeaderStyle;
00043 #include "khtmlparthtmlwriter.h"
00044 using KMail::HtmlWriter;
00045 using KMail::KHtmlPartHtmlWriter;
00046 #include "htmlstatusbar.h"
00047 using KMail::HtmlStatusBar;
00048 #include "folderjob.h"
00049 using KMail::FolderJob;
00050 #include "csshelper.h"
00051 using KMail::CSSHelper;
00052 #include "isubject.h"
00053 using KMail::ISubject;
00054 #include "urlhandlermanager.h"
00055 using KMail::URLHandlerManager;
00056 #include "interfaces/observable.h"
00057
00058 #include "broadcaststatus.h"
00059
00060 #include <kmime_mdn.h>
00061 using namespace KMime;
00062 #ifdef KMAIL_READER_HTML_DEBUG
00063 #include "filehtmlwriter.h"
00064 using KMail::FileHtmlWriter;
00065 #include "teehtmlwriter.h"
00066 using KMail::TeeHtmlWriter;
00067 #endif
00068
00069 #include <mimelib/mimepp.h>
00070 #include <mimelib/body.h>
00071 #include <mimelib/utility.h>
00072
00073
00074 #include <kabc/addressee.h>
00075 #include <kabc/vcardconverter.h>
00076
00077
00078 #include <khtml_part.h>
00079 #include <khtmlview.h>
00080 #include <dom/html_element.h>
00081 #include <dom/html_block.h>
00082 #include <dom/html_document.h>
00083 #include <dom/dom_string.h>
00084
00085 #include <kapplication.h>
00086
00087 #include <kuserprofile.h>
00088 #include <kcharsets.h>
00089 #include <kpopupmenu.h>
00090 #include <kstandarddirs.h>
00091 #include <kcursor.h>
00092 #include <kdebug.h>
00093 #include <kfiledialog.h>
00094 #include <klocale.h>
00095 #include <kmessagebox.h>
00096 #include <kglobalsettings.h>
00097 #include <krun.h>
00098 #include <ktempfile.h>
00099 #include <kprocess.h>
00100 #include <kdialog.h>
00101 #include <kaction.h>
00102 #include <kiconloader.h>
00103 #include <kmdcodec.h>
00104
00105 #include <qclipboard.h>
00106 #include <qhbox.h>
00107 #include <qtextcodec.h>
00108 #include <qpaintdevicemetrics.h>
00109 #include <qlayout.h>
00110 #include <qlabel.h>
00111 #include <qsplitter.h>
00112 #include <qstyle.h>
00113
00114
00115 #undef Never
00116 #undef Always
00117
00118 #include <unistd.h>
00119 #include <stdlib.h>
00120 #include <sys/stat.h>
00121 #include <errno.h>
00122 #include <stdio.h>
00123 #include <ctype.h>
00124 #include <string.h>
00125
00126 #ifdef HAVE_PATHS_H
00127 #include <paths.h>
00128 #endif
00129
00130 class NewByteArray : public QByteArray
00131 {
00132 public:
00133 NewByteArray &appendNULL();
00134 NewByteArray &operator+=( const char * );
00135 NewByteArray &operator+=( const QByteArray & );
00136 NewByteArray &operator+=( const QCString & );
00137 QByteArray& qByteArray();
00138 };
00139
00140 NewByteArray& NewByteArray::appendNULL()
00141 {
00142 QByteArray::detach();
00143 uint len1 = size();
00144 if ( !QByteArray::resize( len1 + 1 ) )
00145 return *this;
00146 *(data() + len1) = '\0';
00147 return *this;
00148 }
00149 NewByteArray& NewByteArray::operator+=( const char * newData )
00150 {
00151 if ( !newData )
00152 return *this;
00153 QByteArray::detach();
00154 uint len1 = size();
00155 uint len2 = qstrlen( newData );
00156 if ( !QByteArray::resize( len1 + len2 ) )
00157 return *this;
00158 memcpy( data() + len1, newData, len2 );
00159 return *this;
00160 }
00161 NewByteArray& NewByteArray::operator+=( const QByteArray & newData )
00162 {
00163 if ( newData.isNull() )
00164 return *this;
00165 QByteArray::detach();
00166 uint len1 = size();
00167 uint len2 = newData.size();
00168 if ( !QByteArray::resize( len1 + len2 ) )
00169 return *this;
00170 memcpy( data() + len1, newData.data(), len2 );
00171 return *this;
00172 }
00173 NewByteArray& NewByteArray::operator+=( const QCString & newData )
00174 {
00175 if ( newData.isEmpty() )
00176 return *this;
00177 QByteArray::detach();
00178 uint len1 = size();
00179 uint len2 = newData.length();
00180 if ( !QByteArray::resize( len1 + len2 ) )
00181 return *this;
00182 memcpy( data() + len1, newData.data(), len2 );
00183 return *this;
00184 }
00185 QByteArray& NewByteArray::qByteArray()
00186 {
00187 return *((QByteArray*)this);
00188 }
00189
00190
00191
00192
00193
00194
00195
00196 void KMReaderWin::objectTreeToDecryptedMsg( partNode* node,
00197 NewByteArray& resultingData,
00198 KMMessage& theMessage,
00199 bool weAreReplacingTheRootNode,
00200 int recCount )
00201 {
00202 kdDebug(5006) << QString("-------------------------------------------------" ) << endl;
00203 kdDebug(5006) << QString("KMReaderWin::objectTreeToDecryptedMsg( %1 ) START").arg( recCount ) << endl;
00204 if( node ) {
00205 partNode* curNode = node;
00206 partNode* dataNode = curNode;
00207 partNode * child = node->firstChild();
00208 bool bIsMultipart = false;
00209
00210 switch( curNode->type() ){
00211 case DwMime::kTypeText: {
00212 kdDebug(5006) << "* text *" << endl;
00213 switch( curNode->subType() ){
00214 case DwMime::kSubtypeHtml:
00215 kdDebug(5006) << "html" << endl;
00216 break;
00217 case DwMime::kSubtypeXVCard:
00218 kdDebug(5006) << "v-card" << endl;
00219 break;
00220 case DwMime::kSubtypeRichtext:
00221 kdDebug(5006) << "rich text" << endl;
00222 break;
00223 case DwMime::kSubtypeEnriched:
00224 kdDebug(5006) << "enriched " << endl;
00225 break;
00226 case DwMime::kSubtypePlain:
00227 kdDebug(5006) << "plain " << endl;
00228 break;
00229 default:
00230 kdDebug(5006) << "default " << endl;
00231 break;
00232 }
00233 }
00234 break;
00235 case DwMime::kTypeMultipart: {
00236 kdDebug(5006) << "* multipart *" << endl;
00237 bIsMultipart = true;
00238 switch( curNode->subType() ){
00239 case DwMime::kSubtypeMixed:
00240 kdDebug(5006) << "mixed" << endl;
00241 break;
00242 case DwMime::kSubtypeAlternative:
00243 kdDebug(5006) << "alternative" << endl;
00244 break;
00245 case DwMime::kSubtypeDigest:
00246 kdDebug(5006) << "digest" << endl;
00247 break;
00248 case DwMime::kSubtypeParallel:
00249 kdDebug(5006) << "parallel" << endl;
00250 break;
00251 case DwMime::kSubtypeSigned:
00252 kdDebug(5006) << "signed" << endl;
00253 break;
00254 case DwMime::kSubtypeEncrypted: {
00255 kdDebug(5006) << "encrypted" << endl;
00256 if ( child ) {
00257
00258
00259
00260 partNode* data =
00261 child->findType( DwMime::kTypeApplication, DwMime::kSubtypeOctetStream, false, true );
00262 if ( !data )
00263 data = child->findType( DwMime::kTypeApplication, DwMime::kSubtypePkcs7Mime, false, true );
00264 if ( data && data->firstChild() )
00265 dataNode = data;
00266 }
00267 }
00268 break;
00269 default :
00270 kdDebug(5006) << "( unknown subtype )" << endl;
00271 break;
00272 }
00273 }
00274 break;
00275 case DwMime::kTypeMessage: {
00276 kdDebug(5006) << "* message *" << endl;
00277 switch( curNode->subType() ){
00278 case DwMime::kSubtypeRfc822: {
00279 kdDebug(5006) << "RfC 822" << endl;
00280 if ( child )
00281 dataNode = child;
00282 }
00283 break;
00284 }
00285 }
00286 break;
00287 case DwMime::kTypeApplication: {
00288 kdDebug(5006) << "* application *" << endl;
00289 switch( curNode->subType() ){
00290 case DwMime::kSubtypePostscript:
00291 kdDebug(5006) << "postscript" << endl;
00292 break;
00293 case DwMime::kSubtypeOctetStream: {
00294 kdDebug(5006) << "octet stream" << endl;
00295 if ( child )
00296 dataNode = child;
00297 }
00298 break;
00299 case DwMime::kSubtypePgpEncrypted:
00300 kdDebug(5006) << "pgp encrypted" << endl;
00301 break;
00302 case DwMime::kSubtypePgpSignature:
00303 kdDebug(5006) << "pgp signed" << endl;
00304 break;
00305 case DwMime::kSubtypePkcs7Mime: {
00306 kdDebug(5006) << "pkcs7 mime" << endl;
00307
00308
00309 if ( child && curNode->encryptionState() != KMMsgNotEncrypted )
00310 dataNode = child;
00311 }
00312 break;
00313 }
00314 }
00315 break;
00316 case DwMime::kTypeImage: {
00317 kdDebug(5006) << "* image *" << endl;
00318 switch( curNode->subType() ){
00319 case DwMime::kSubtypeJpeg:
00320 kdDebug(5006) << "JPEG" << endl;
00321 break;
00322 case DwMime::kSubtypeGif:
00323 kdDebug(5006) << "GIF" << endl;
00324 break;
00325 }
00326 }
00327 break;
00328 case DwMime::kTypeAudio: {
00329 kdDebug(5006) << "* audio *" << endl;
00330 switch( curNode->subType() ){
00331 case DwMime::kSubtypeBasic:
00332 kdDebug(5006) << "basic" << endl;
00333 break;
00334 }
00335 }
00336 break;
00337 case DwMime::kTypeVideo: {
00338 kdDebug(5006) << "* video *" << endl;
00339 switch( curNode->subType() ){
00340 case DwMime::kSubtypeMpeg:
00341 kdDebug(5006) << "mpeg" << endl;
00342 break;
00343 }
00344 }
00345 break;
00346 case DwMime::kTypeModel:
00347 kdDebug(5006) << "* model *" << endl;
00348 break;
00349 }
00350
00351
00352 DwHeaders& rootHeaders( theMessage.headers() );
00353 DwBodyPart * part = dataNode->dwPart() ? dataNode->dwPart() : 0;
00354 DwHeaders * headers(
00355 (part && part->hasHeaders())
00356 ? &part->Headers()
00357 : ( (weAreReplacingTheRootNode || !dataNode->parentNode())
00358 ? &rootHeaders
00359 : 0 ) );
00360 if( dataNode == curNode ) {
00361 kdDebug(5006) << "dataNode == curNode: Save curNode without replacing it." << endl;
00362
00363
00364
00365
00366 if( headers ) {
00367 if( dataNode->parentNode() && !weAreReplacingTheRootNode ) {
00368 kdDebug(5006) << "dataNode is NOT replacing the root node: Store the headers." << endl;
00369 resultingData += headers->AsString().c_str();
00370 } else if( weAreReplacingTheRootNode && part->hasHeaders() ){
00371 kdDebug(5006) << "dataNode replace the root node: Do NOT store the headers but change" << endl;
00372 kdDebug(5006) << " the Message's headers accordingly." << endl;
00373 kdDebug(5006) << " old Content-Type = " << rootHeaders.ContentType().AsString().c_str() << endl;
00374 kdDebug(5006) << " new Content-Type = " << headers->ContentType( ).AsString().c_str() << endl;
00375 rootHeaders.ContentType() = headers->ContentType();
00376 theMessage.setContentTransferEncodingStr(
00377 headers->HasContentTransferEncoding()
00378 ? headers->ContentTransferEncoding().AsString().c_str()
00379 : "" );
00380 rootHeaders.ContentDescription() = headers->ContentDescription();
00381 rootHeaders.ContentDisposition() = headers->ContentDisposition();
00382 theMessage.setNeedsAssembly();
00383 }
00384 }
00385
00386
00387 if( headers && bIsMultipart && dataNode->firstChild() ) {
00388 kdDebug(5006) << "is valid Multipart, processing children:" << endl;
00389 QCString boundary = headers->ContentType().Boundary().c_str();
00390 curNode = dataNode->firstChild();
00391
00392 while( curNode ) {
00393 kdDebug(5006) << "--boundary" << endl;
00394 if( resultingData.size() &&
00395 ( '\n' != resultingData.at( resultingData.size()-1 ) ) )
00396 resultingData += QCString( "\n" );
00397 resultingData += QCString( "\n" );
00398 resultingData += "--";
00399 resultingData += boundary;
00400 resultingData += "\n";
00401
00402
00403
00404 objectTreeToDecryptedMsg( curNode,
00405 resultingData,
00406 theMessage,
00407 false,
00408 recCount + 1 );
00409 curNode = curNode->nextSibling();
00410 }
00411 kdDebug(5006) << "--boundary--" << endl;
00412 resultingData += "\n--";
00413 resultingData += boundary;
00414 resultingData += "--\n\n";
00415 kdDebug(5006) << "Multipart processing children - DONE" << endl;
00416 } else if( part ){
00417
00418 kdDebug(5006) << "is Simple part or invalid Multipart, processing single body (if inline encrypted):" << endl;
00419
00420
00421
00422
00423 ObjectTreeParser otp( 0, 0, false, false, true );
00424 dataNode->setProcessed( false, true );
00425 otp.setKeepEncryptions( false );
00426 otp.parseObjectTree( curNode );
00427
00428
00429
00430
00431 bool bDecryptedInlinePGP = false;
00432 QPtrList<Kpgp::Block> pgpBlocks;
00433 QStrList nonPgpBlocks;
00434 if ( Kpgp::Module::prepareMessageForDecryption( otp.rawReplyString(),
00435 pgpBlocks,
00436 nonPgpBlocks ) ) {
00437 if ( pgpBlocks.count() == 1 ) {
00438 Kpgp::Block * block = pgpBlocks.first();
00439 if ( block->type() == Kpgp::PgpMessageBlock ) {
00440
00441 block->decrypt();
00442 resultingData += nonPgpBlocks.first() + block->text() + nonPgpBlocks.last();
00443 bDecryptedInlinePGP = true;
00444 }
00445 }
00446 }
00447 if( !bDecryptedInlinePGP )
00448 resultingData += otp.rawReplyString();
00449
00450
00451
00452 kdDebug(5006) << "decrypting of single body - DONE" << endl;
00453 }
00454 } else {
00455 kdDebug(5006) << "dataNode != curNode: Replace curNode by dataNode." << endl;
00456 bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parentNode();
00457 if( rootNodeReplaceFlag ) {
00458 kdDebug(5006) << " Root node will be replaced." << endl;
00459 } else {
00460 kdDebug(5006) << " Root node will NOT be replaced." << endl;
00461 }
00462
00463
00464 objectTreeToDecryptedMsg( dataNode,
00465 resultingData,
00466 theMessage,
00467 rootNodeReplaceFlag,
00468 recCount + 1 );
00469 }
00470 }
00471 kdDebug(5006) << QString("\nKMReaderWin::objectTreeToDecryptedMsg( %1 ) END").arg( recCount ) << endl;
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 void KMReaderWin::createWidgets() {
00496 QVBoxLayout * vlay = new QVBoxLayout( this );
00497 mSplitter = new QSplitter( Qt::Vertical, this, "mSplitter" );
00498 vlay->addWidget( mSplitter );
00499 mMimePartTree = new KMMimePartTree( this, mSplitter, "mMimePartTree" );
00500 mBox = new QHBox( mSplitter, "mBox" );
00501 setStyleDependantFrameWidth();
00502 mBox->setFrameStyle( mMimePartTree->frameStyle() );
00503 mColorBar = new HtmlStatusBar( mBox, "mColorBar" );
00504 mViewer = new KHTMLPart( mBox, "mViewer" );
00505 mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
00506 mSplitter->setResizeMode( mMimePartTree, QSplitter::KeepSize );
00507 }
00508
00509 const int KMReaderWin::delay = 150;
00510
00511
00512 KMReaderWin::KMReaderWin(QWidget *aParent,
00513 QWidget *mainWindow,
00514 KActionCollection* actionCollection,
00515 const char *aName,
00516 int aFlags )
00517 : QWidget(aParent, aName, aFlags | Qt::WDestructiveClose),
00518 mAttachmentStrategy( 0 ),
00519 mHeaderStrategy( 0 ),
00520 mHeaderStyle( 0 ),
00521 mOverrideCodec( 0 ),
00522 mCSSHelper( 0 ),
00523 mRootNode( 0 ),
00524 mMainWindow( mainWindow ),
00525 mHtmlWriter( 0 )
00526 {
00527 mSplitterSizes << 180 << 100;
00528 mMimeTreeMode = 1;
00529 mMimeTreeAtBottom = true;
00530 mAutoDelete = false;
00531 mLastSerNum = 0;
00532 mWaitingForSerNum = 0;
00533 mMessage = 0;
00534 mLastStatus = KMMsgStatusUnknown;
00535 mMsgDisplay = true;
00536 mPrinting = false;
00537 mShowColorbar = false;
00538 mAtmUpdate = false;
00539
00540 createWidgets();
00541 initHtmlWidget();
00542 readConfig();
00543
00544 mHtmlOverride = false;
00545
00546 connect( &updateReaderWinTimer, SIGNAL(timeout()),
00547 this, SLOT(updateReaderWin()) );
00548 connect( &mResizeTimer, SIGNAL(timeout()),
00549 this, SLOT(slotDelayedResize()) );
00550 connect( &mDelayedMarkTimer, SIGNAL(timeout()),
00551 this, SLOT(slotTouchMessage()) );
00552
00553 createActions( actionCollection );
00554 }
00555
00556 void KMReaderWin::createActions( KActionCollection * ac ) {
00557 if ( !ac )
00558 return;
00559
00560 mMailToComposeAction = new KAction( i18n("New Message To..."), 0, this,
00561 SLOT(slotMailtoCompose()), ac,
00562 "mailto_compose" );
00563 mMailToReplyAction = new KAction( i18n("Reply To..."), 0, this,
00564 SLOT(slotMailtoReply()), ac,
00565 "mailto_reply" );
00566 mMailToForwardAction = new KAction( i18n("Forward To..."),
00567 0, this, SLOT(slotMailtoForward()), ac,
00568 "mailto_forward" );
00569 mAddAddrBookAction = new KAction( i18n("Add to Address Book"),
00570 0, this, SLOT(slotMailtoAddAddrBook()),
00571 ac, "add_addr_book" );
00572 mOpenAddrBookAction = new KAction( i18n("Open in Address Book"),
00573 0, this, SLOT(slotMailtoOpenAddrBook()),
00574 ac, "openin_addr_book" );
00575 mCopyAction = new KAction( i18n("Copy to Clipboard"), 0, this,
00576 SLOT(slotUrlCopy()), ac, "copy_address" );
00577 mCopyURLAction = new KAction( i18n("Copy Link Address"), 0, this,
00578 SLOT(slotUrlCopy()), ac, "copy_url" );
00579 mUrlOpenAction = new KAction( i18n("Open URL"), 0, this,
00580 SLOT(slotUrlOpen()), ac, "open_url" );
00581 mAddBookmarksAction = new KAction( i18n("Bookmark This Link"),
00582 "bookmark_add",
00583 0, this, SLOT(slotAddBookmarks()),
00584 ac, "add_bookmarks" );
00585 mUrlSaveAsAction = new KAction( i18n("Save Link As..."), 0, this,
00586 SLOT(slotUrlSave()), ac, "saveas_url" );
00587 mViewSourceAction = new KAction( i18n("&View Source"), Key_V, this,
00588 SLOT(slotShowMsgSrc()), ac, "view_source" );
00589
00590 mToggleFixFontAction = new KToggleAction( i18n("Use Fi&xed Font"),
00591 Key_X, this, SLOT(slotToggleFixedFont()),
00592 ac, "toggle_fixedfont" );
00593
00594 mStartIMChatAction = new KAction( i18n("Chat &With..."), 0, this,
00595 SLOT(slotIMChat()), ac, "start_im_chat" );
00596 }
00597
00598
00599
00600 KMReaderWin::~KMReaderWin()
00601 {
00602 delete mHtmlWriter; mHtmlWriter = 0;
00603 if (mAutoDelete) delete message();
00604 delete mRootNode; mRootNode = 0;
00605 removeTempFiles();
00606 }
00607
00608
00609
00610 void KMReaderWin::slotMessageArrived( KMMessage *msg )
00611 {
00612 if (msg && ((KMMsgBase*)msg)->isMessage()) {
00613 if ( msg->getMsgSerNum() == mWaitingForSerNum ) {
00614 setMsg( msg, true );
00615 } else {
00616 kdDebug( 5006 ) << "KMReaderWin::slotMessageArrived - ignoring update" << endl;
00617 }
00618 }
00619 }
00620
00621
00622 void KMReaderWin::update( KMail::Interface::Observable * observable ) {
00623 if ( !mAtmUpdate ) {
00624 kdDebug(5006) << "KMReaderWin::update - message" << endl;
00625 updateReaderWin();
00626 return;
00627 }
00628
00629 if ( !mRootNode )
00630 return;
00631
00632 kdDebug(5006) << "KMReaderWin::update - attachment " << mAtmCurrentName << endl;
00633 partNode * node = mRootNode->findId( mAtmCurrent );
00634 if ( !node ) {
00635 kdWarning(5006) << "KMReaderWin::update - Could not find node for attachment!" << endl;
00636 return;
00637 }
00638
00639 assert( dynamic_cast<KMMessage*>( observable ) != 0 );
00640
00641
00642
00643
00644 node->setDwPart( static_cast<KMMessage*>( observable )->lastUpdatedPart() );
00645
00646
00647 ::chmod( QFile::encodeName( mAtmCurrentName ), S_IRWXU );
00648 KPIM::kByteArrayToFile( node->msgPart().bodyDecodedBinary(), mAtmCurrentName,
00649 false, false, true );
00650 ::chmod( QFile::encodeName( mAtmCurrentName ), S_IRUSR );
00651
00652
00653
00654 }
00655
00656
00657 void KMReaderWin::removeTempFiles()
00658 {
00659 for (QStringList::Iterator it = mTempFiles.begin(); it != mTempFiles.end();
00660 it++)
00661 {
00662 QFile::remove(*it);
00663 }
00664 mTempFiles.clear();
00665 for (QStringList::Iterator it = mTempDirs.begin(); it != mTempDirs.end();
00666 it++)
00667 {
00668 QDir(*it).rmdir(*it);
00669 }
00670 mTempDirs.clear();
00671 }
00672
00673
00674
00675 bool KMReaderWin::event(QEvent *e)
00676 {
00677 if (e->type() == QEvent::ApplicationPaletteChange)
00678 {
00679 delete mCSSHelper;
00680 mCSSHelper = new CSSHelper( QPaintDeviceMetrics( mViewer->view() ), this );
00681 if (message())
00682 message()->readConfig();
00683 update( true );
00684 return true;
00685 }
00686 return QWidget::event(e);
00687 }
00688
00689
00690
00691 void KMReaderWin::readConfig(void)
00692 {
00693 const KConfigGroup mdnGroup( KMKernel::config(), "MDN" );
00694 KConfigGroup reader( KMKernel::config(), "Reader" );
00695
00696 delete mCSSHelper;
00697 mCSSHelper = new CSSHelper( QPaintDeviceMetrics( mViewer->view() ), this );
00698
00699 mNoMDNsWhenEncrypted = mdnGroup.readBoolEntry( "not-send-when-encrypted", true );
00700
00701
00702
00703 mUseFixedFont = reader.readBoolEntry( "useFixedFont", false );
00704 mHtmlMail = reader.readBoolEntry( "htmlMail", false );
00705 setHeaderStyleAndStrategy( HeaderStyle::create( reader.readEntry( "header-style", "fancy" ) ),
00706 HeaderStrategy::create( reader.readEntry( "header-set-displayed", "rich" ) ) );
00707
00708 mAttachmentStrategy =
00709 AttachmentStrategy::create( reader.readEntry( "attachment-strategy" ) );
00710
00711 mViewer->setOnlyLocalReferences( !reader.readBoolEntry( "htmlLoadExternal", false ) );
00712
00713
00714
00715 mShowColorbar = reader.readBoolEntry( "showColorbar", Kpgp::Module::getKpgp()->usePGP() );
00716
00717
00718
00719 reader.writeEntry( "showColorbar", mShowColorbar );
00720
00721 mMimeTreeAtBottom = reader.readEntry( "MimeTreeLocation", "bottom" ) != "top";
00722 const QString s = reader.readEntry( "MimeTreeMode", "smart" );
00723 if ( s == "never" )
00724 mMimeTreeMode = 0;
00725 else if ( s == "always" )
00726 mMimeTreeMode = 2;
00727 else
00728 mMimeTreeMode = 1;
00729
00730 const int mimeH = reader.readNumEntry( "MimePaneHeight", 100 );
00731 const int messageH = reader.readNumEntry( "MessagePaneHeight", 180 );
00732 mSplitterSizes.clear();
00733 if ( mMimeTreeAtBottom )
00734 mSplitterSizes << messageH << mimeH;
00735 else
00736 mSplitterSizes << mimeH << messageH;
00737
00738 adjustLayout();
00739
00740 if (message())
00741 update();
00742 KMMessage::readConfig();
00743 }
00744
00745
00746 void KMReaderWin::adjustLayout() {
00747 if ( mMimeTreeAtBottom )
00748 mSplitter->moveToLast( mMimePartTree );
00749 else
00750 mSplitter->moveToFirst( mMimePartTree );
00751 mSplitter->setSizes( mSplitterSizes );
00752
00753 if ( mMimeTreeMode == 2 && mMsgDisplay )
00754 mMimePartTree->show();
00755 else
00756 mMimePartTree->hide();
00757
00758 if ( mShowColorbar && mMsgDisplay )
00759 mColorBar->show();
00760 else
00761 mColorBar->hide();
00762 }
00763
00764
00765 void KMReaderWin::saveSplitterSizes( KConfigBase & c ) const {
00766 if ( !mSplitter || !mMimePartTree )
00767 return;
00768 if ( mMimePartTree->isHidden() )
00769 return;
00770
00771 c.writeEntry( "MimePaneHeight", mSplitter->sizes()[ mMimeTreeAtBottom ? 1 : 0 ] );
00772 c.writeEntry( "MessagePaneHeight", mSplitter->sizes()[ mMimeTreeAtBottom ? 0 : 1 ] );
00773 }
00774
00775
00776 void KMReaderWin::writeConfig( bool sync ) const {
00777 KConfigGroup reader( KMKernel::config(), "Reader" );
00778
00779 reader.writeEntry( "useFixedFont", mUseFixedFont );
00780 if ( headerStyle() )
00781 reader.writeEntry( "header-style", headerStyle()->name() );
00782 if ( headerStrategy() )
00783 reader.writeEntry( "header-set-displayed", headerStrategy()->name() );
00784 if ( attachmentStrategy() )
00785 reader.writeEntry( "attachment-strategy", attachmentStrategy()->name() );
00786
00787 saveSplitterSizes( reader );
00788
00789 if ( sync )
00790 kmkernel->slotRequestConfigSync();
00791 }
00792
00793
00794 void KMReaderWin::initHtmlWidget(void)
00795 {
00796 mViewer->widget()->setFocusPolicy(WheelFocus);
00797
00798 mViewer->setPluginsEnabled(false);
00799 mViewer->setJScriptEnabled(false);
00800 mViewer->setJavaEnabled(false);
00801 mViewer->setMetaRefreshEnabled(false);
00802 mViewer->setURLCursor(KCursor::handCursor());
00803
00804 mViewer->view()->setLineWidth(0);
00805
00806 if ( !htmlWriter() )
00807 #ifdef KMAIL_READER_HTML_DEBUG
00808 mHtmlWriter = new TeeHtmlWriter( new FileHtmlWriter( QString::null ),
00809 new KHtmlPartHtmlWriter( mViewer, 0 ) );
00810 #else
00811 mHtmlWriter = new KHtmlPartHtmlWriter( mViewer, 0 );
00812 #endif
00813
00814 connect(mViewer->browserExtension(),
00815 SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)),this,
00816 SLOT(slotUrlOpen(const KURL &)));
00817 connect(mViewer->browserExtension(),
00818 SIGNAL(createNewWindow(const KURL &, const KParts::URLArgs &)),this,
00819 SLOT(slotUrlOpen(const KURL &)));
00820 connect(mViewer,SIGNAL(onURL(const QString &)),this,
00821 SLOT(slotUrlOn(const QString &)));
00822 connect(mViewer,SIGNAL(popupMenu(const QString &, const QPoint &)),
00823 SLOT(slotUrlPopup(const QString &, const QPoint &)));
00824 connect( kmkernel->imProxy(), SIGNAL( sigContactPresenceChanged( const QString & ) ),
00825 this, SLOT( contactStatusChanged( const QString & ) ) );
00826 connect( kmkernel->imProxy(), SIGNAL( sigPresenceInfoExpired() ),
00827 this, SLOT( updateReaderWin() ) );
00828 }
00829
00830 void KMReaderWin::contactStatusChanged( const QString &uid)
00831 {
00832 kdDebug( 5006 ) << k_funcinfo << " got a presence change for " << uid << endl;
00833
00834 DOM::NodeList presenceNodes = mViewer->htmlDocument()
00835 .getElementsByName( DOM::DOMString( QString::fromLatin1("presence-") + uid ) );
00836 for ( unsigned int i = 0; i < presenceNodes.length(); ++i )
00837 {
00838 DOM::Node n = presenceNodes.item( i );
00839 kdDebug( 5006 ) << "name is " << n.nodeName().string() << endl;
00840 kdDebug( 5006 ) << "value of content was " << n.firstChild().nodeValue().string() << endl;
00841 QString newPresence = kmkernel->imProxy()->presenceString( uid );
00842 if ( newPresence.isNull() )
00843 newPresence = QString::fromLatin1( "ENOIMRUNNING" );
00844 n.firstChild().setNodeValue( newPresence );
00845 kdDebug( 5006 ) << "value of content is now " << n.firstChild().nodeValue().string() << endl;
00846 }
00847 kdDebug( 5006 ) << "and we updated the above presence nodes" << uid << endl;
00848 }
00849
00850 void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy * strategy ) {
00851 mAttachmentStrategy = strategy ? strategy : AttachmentStrategy::smart() ;
00852 update( true );
00853 }
00854
00855 void KMReaderWin::setHeaderStyleAndStrategy( const HeaderStyle * style,
00856 const HeaderStrategy * strategy ) {
00857 mHeaderStyle = style ? style : HeaderStyle::fancy() ;
00858 mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich() ;
00859 update( true );
00860 }
00861
00862 void KMReaderWin::setOverrideCodec( const QTextCodec * codec ) {
00863 if ( mOverrideCodec == codec )
00864 return;
00865 mOverrideCodec = codec;
00866 update( true );
00867 }
00868
00869
00870 void KMReaderWin::setMsg(KMMessage* aMsg, bool force)
00871 {
00872 if (aMsg)
00873 kdDebug(5006) << "(" << aMsg->getMsgSerNum() << ", last " << mLastSerNum << ") " << aMsg->subject() << " "
00874 << aMsg->fromStrip() << ", readyToShow " << (aMsg->readyToShow()) << endl;
00875
00876 bool complete = true;
00877 if ( aMsg &&
00878 !aMsg->readyToShow() &&
00879 (aMsg->getMsgSerNum() != mLastSerNum) &&
00880 !aMsg->isComplete() )
00881 complete = false;
00882
00883
00884 if (!force && aMsg && mLastSerNum != 0 && aMsg->getMsgSerNum() == mLastSerNum)
00885 return;
00886
00887
00888 if (aMsg && message())
00889 message()->detach( this );
00890 if (aMsg)
00891 aMsg->attach( this );
00892 mAtmUpdate = false;
00893
00894
00895
00896 mDelayedMarkTimer.stop();
00897
00898 mLastSerNum = (aMsg) ? aMsg->getMsgSerNum() : 0;
00899 if ( !aMsg ) mWaitingForSerNum = 0;
00900
00901
00902 if (mLastSerNum <= 0)
00903 mMessage = aMsg;
00904 else
00905 mMessage = 0;
00906 if (message() != aMsg) {
00907 mMessage = aMsg;
00908 mLastSerNum = 0;
00909 Q_ASSERT(0);
00910 }
00911
00912 if (aMsg) {
00913 aMsg->setOverrideCodec( overrideCodec() );
00914 aMsg->setDecodeHTML( htmlMail() );
00915 mLastStatus = aMsg->status();
00916
00917 if ( !aMsg->isComplete() )
00918 mViewer->setDNDEnabled( false );
00919 else
00920 mViewer->setDNDEnabled( true );
00921 } else {
00922 mLastStatus = KMMsgStatusUnknown;
00923 }
00924
00925
00926
00927 if ( complete )
00928 {
00929
00930 if (force) {
00931
00932 updateReaderWinTimer.stop();
00933 updateReaderWin();
00934 }
00935 else if (updateReaderWinTimer.isActive())
00936 updateReaderWinTimer.changeInterval( delay );
00937 else
00938 updateReaderWinTimer.start( 0, TRUE );
00939 }
00940
00941 if ( GlobalSettings::delayedMarkAsRead() ) {
00942 if ( GlobalSettings::delayedMarkTime() != 0 )
00943 mDelayedMarkTimer.start( GlobalSettings::delayedMarkTime() * 1000, TRUE );
00944 else
00945 slotTouchMessage();
00946 }
00947 }
00948
00949
00950 void KMReaderWin::clearCache()
00951 {
00952 updateReaderWinTimer.stop();
00953 clear();
00954 mDelayedMarkTimer.stop();
00955 mLastSerNum = 0;
00956 mWaitingForSerNum = 0;
00957 mMessage = 0;
00958 }
00959
00960
00961 static const char * const kmailChanges[] = {
00962 I18N_NOOP("Support for 3rd-party CryptPlugs has been discontinued. "
00963 "Support for the GnuPG cryptographic backend is now included "
00964 "directly in KMail.")
00965 };
00966 static const int numKMailChanges =
00967 sizeof kmailChanges / sizeof *kmailChanges;
00968
00969
00970
00971
00972
00973 static const char * const kmailNewFeatures[] = {
00974 I18N_NOOP( "Antispam wizard" ),
00975 I18N_NOOP( "Filter log" ),
00976 I18N_NOOP( "Quick search" ),
00977 I18N_NOOP( "Automatic mailing-list detection" ),
00978 I18N_NOOP( "View/open message files" ),
00979 I18N_NOOP( "HTML message composing" ),
00980 I18N_NOOP( "New filter criteria: in address book, in category, has attachment" ),
00981 I18N_NOOP("Cryptographic backend auto-configuration"),
00982 I18N_NOOP("Sign/encrypt key separation"),
00983 I18N_NOOP("Per-identity S/MIME key preselection"),
00984 I18N_NOOP("Per-identity cryptographic message format preselection"),
00985 I18N_NOOP("Per-contact crypto preferences"),
00986 I18N_NOOP("List only opened IMAP folders"),
00987 };
00988 static const int numKMailNewFeatures =
00989 sizeof kmailNewFeatures / sizeof *kmailNewFeatures;
00990
00991
00992
00993
00994 QString KMReaderWin::newFeaturesMD5()
00995 {
00996 QCString str;
00997 for ( int i = 0 ; i < numKMailChanges ; ++i )
00998 str += kmailChanges[i];
00999 for ( int i = 0 ; i < numKMailNewFeatures ; ++i )
01000 str += kmailNewFeatures[i];
01001 KMD5 md5( str );
01002 return md5.base64Digest();
01003 }
01004
01005
01006 void KMReaderWin::displayAboutPage()
01007 {
01008 mMsgDisplay = false;
01009 adjustLayout();
01010
01011 QString location = locate("data", "kmail/about/main.html");
01012 QString content = KPIM::kFileToString(location);
01013 mViewer->begin(KURL( location ));
01014 QString info =
01015 i18n("%1: KMail version; %2: help:// URL; %3: homepage URL; "
01016 "%4: prior KMail version; %5: prior KDE version; "
01017 "%6: generated list of new features; "
01018 "%7: First-time user text (only shown on first start); "
01019 "%8: prior KMail version; "
01020 "%9: generated list of important changes; "
01021 "--- end of comment ---",
01022 "<h2>Welcome to KMail %1</h2><p>KMail is the email client for the K "
01023 "Desktop Environment. It is designed to be fully compatible with "
01024 "Internet mailing standards including MIME, SMTP, POP3 and IMAP."
01025 "</p>\n"
01026 "<ul><li>KMail has many powerful features which are described in the "
01027 "<a href=\"%2\">documentation</a></li>\n"
01028 "<li>The <a href=\"%3\">KMail homepage</A> offers information about "
01029 "new versions of KMail</li></ul>\n"
01030 "<p><span style='font-size:125%; font-weight:bold;'>"
01031 "Important changes</span> (compared to KMail %8):</p>\n"
01032 "<ul>\n%9</ul>\n"
01033 "<p>Some of the new features in this release of KMail include "
01034 "(compared to KMail %4, which is part of KDE %5):</p>\n"
01035 "<ul>\n%6</ul>\n"
01036 "%7\n"
01037 "<p>We hope that you will enjoy KMail.</p>\n"
01038 "<p>Thank you,</p>\n"
01039 "<p> The KMail Team</p>")
01040 .arg(KMAIL_VERSION)
01041 .arg("help:/kmail/index.html")
01042 .arg("http://kmail.kde.org/")
01043 .arg("1.6").arg("3.2");
01044
01045 QString featureItems;
01046 for ( int i = 0 ; i < numKMailNewFeatures ; i++ )
01047 featureItems += i18n("<li>%1</li>\n").arg( i18n( kmailNewFeatures[i] ) );
01048
01049 info = info.arg( featureItems );
01050
01051 if( kmkernel->firstStart() ) {
01052 info = info.arg( i18n("<p>Please take a moment to fill in the KMail "
01053 "configuration panel at Settings->Configure "
01054 "KMail.\n"
01055 "You need to create at least a default identity and "
01056 "an incoming as well as outgoing mail account."
01057 "</p>\n") );
01058 } else {
01059 info = info.arg( QString::null );
01060 }
01061
01062 QString changesItems;
01063 for ( int i = 0 ; i < numKMailChanges ; i++ )
01064 changesItems += i18n("<li>%1</li>\n").arg( i18n( kmailChanges[i] ) );
01065
01066 info = info.arg("1.6").arg( changesItems );
01067
01068 mViewer->write(content.arg(pointsToPixel( mCSSHelper->bodyFont().pointSize() )).arg(info));
01069 mViewer->end();
01070 }
01071
01072 void KMReaderWin::enableMsgDisplay() {
01073 mMsgDisplay = true;
01074 adjustLayout();
01075 }
01076
01077
01078
01079
01080 void KMReaderWin::updateReaderWin()
01081 {
01082 if (!mMsgDisplay) return;
01083
01084 htmlWriter()->reset();
01085
01086 KMFolder* folder;
01087 if (message(&folder))
01088 {
01089 if( !kmkernel->iCalIface().isResourceImapFolder( folder ) ){
01090 if ( mShowColorbar )
01091 mColorBar->show();
01092 else
01093 mColorBar->hide();
01094 displayMessage();
01095 }
01096 }
01097 else
01098 {
01099 mColorBar->hide();
01100 mMimePartTree->hide();
01101 mMimePartTree->clear();
01102 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01103 htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) + "</body></html>" );
01104 htmlWriter()->end();
01105 }
01106 }
01107
01108
01109 int KMReaderWin::pointsToPixel(int pointSize) const
01110 {
01111 const QPaintDeviceMetrics pdm(mViewer->view());
01112
01113 return (pointSize * pdm.logicalDpiY() + 36) / 72;
01114 }
01115
01116
01117 void KMReaderWin::showHideMimeTree( bool isPlainTextTopLevel ) {
01118 if ( mMimeTreeMode == 2 ||
01119 ( mMimeTreeMode == 1 && !isPlainTextTopLevel ) )
01120 mMimePartTree->show();
01121 else {
01122
01123 KConfigGroup reader( KMKernel::config(), "Reader" );
01124 saveSplitterSizes( reader );
01125 mMimePartTree->hide();
01126 }
01127 }
01128
01129 void KMReaderWin::displayMessage() {
01130 KMMessage * msg = message();
01131
01132 mMimePartTree->clear();
01133 showHideMimeTree( !msg ||
01134 ( msg->type() == DwMime::kTypeText
01135 && msg->subtype() == DwMime::kSubtypePlain ) );
01136
01137 if ( !msg )
01138 return;
01139
01140 msg->setOverrideCodec( overrideCodec() );
01141
01142 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01143 htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
01144
01145 if (!parent())
01146 setCaption(msg->subject());
01147
01148 removeTempFiles();
01149
01150 mColorBar->setNeutralMode();
01151
01152 parseMsg(msg);
01153
01154 if( mColorBar->isNeutral() )
01155 mColorBar->setNormalMode();
01156
01157 htmlWriter()->queue("</body></html>");
01158 htmlWriter()->flush();
01159 }
01160
01161
01162
01163 void KMReaderWin::parseMsg(KMMessage* aMsg)
01164 {
01165 #ifndef NDEBUG
01166 kdDebug( 5006 )
01167 << "parseMsg(KMMessage* aMsg "
01168 << ( aMsg == message() ? "==" : "!=" )
01169 << " aMsg )" << endl;
01170 #endif
01171
01172 KMMessagePart msgPart;
01173 QCString subtype, contDisp;
01174 QByteArray str;
01175
01176 assert(aMsg!=0);
01177
01178 delete mRootNode;
01179 mRootNode = partNode::fromMessage( aMsg );
01180 const QCString mainCntTypeStr = mRootNode->typeString() + '/' + mRootNode->subTypeString();
01181
01182 QString cntDesc = aMsg->subject();
01183 if( cntDesc.isEmpty() )
01184 cntDesc = i18n("( body part )");
01185 KIO::filesize_t cntSize = aMsg->msgSize();
01186 QString cntEnc;
01187 if( aMsg->contentTransferEncodingStr().isEmpty() )
01188 cntEnc = "7bit";
01189 else
01190 cntEnc = aMsg->contentTransferEncodingStr();
01191
01192
01193 mRootNode->fillMimePartTree( 0,
01194 mMimePartTree,
01195 cntDesc,
01196 mainCntTypeStr,
01197 cntEnc,
01198 cntSize );
01199
01200 partNode* vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeXVCard );
01201 bool hasVCard = false;
01202 if( vCardNode ) {
01203
01204
01205 const QString vcard = vCardNode->msgPart().bodyToUnicode( overrideCodec() );
01206 KABC::VCardConverter t;
01207 if ( !t.parseVCards( vcard ).empty() ) {
01208 hasVCard = true;
01209 kdDebug(5006) << "FOUND A VALID VCARD" << endl;
01210 writeMessagePartToTempFile( &vCardNode->msgPart(), vCardNode->nodeId() );
01211 }
01212 }
01213 htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard) );
01214
01215
01216 ObjectTreeParser otp( this );
01217 otp.parseObjectTree( mRootNode );
01218
01219
01220
01221 KMMsgEncryptionState encryptionState = mRootNode->overallEncryptionState();
01222 KMMsgSignatureState signatureState = mRootNode->overallSignatureState();
01223 aMsg->setEncryptionState( encryptionState );
01224 aMsg->setSignatureState( signatureState );
01225
01226 bool emitReplaceMsgByUnencryptedVersion = false;
01227 const KConfigGroup reader( KMKernel::config(), "Reader" );
01228 if ( reader.readBoolEntry( "store-displayed-messages-unencrypted", false ) ) {
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242 kdDebug(5006) << "\n\n\nKMReaderWin::parseMsg() - special post-encryption handling:\n1." << endl;
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254 if( (aMsg == message())
01255
01256
01257 && ((KMMsgStatusUnknown | KMMsgStatusNew | KMMsgStatusUnread) & mLastStatus)
01258
01259 && (mIdOfLastViewedMessage != aMsg->msgId())
01260
01261 && ( (KMMsgFullyEncrypted == encryptionState)
01262 || (KMMsgPartiallyEncrypted == encryptionState) ) ) {
01263
01264 kdDebug(5006) << "KMReaderWin - calling objectTreeToDecryptedMsg()" << endl;
01265
01266 NewByteArray decryptedData;
01267
01268 objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg );
01269
01270 decryptedData.appendNULL();
01271 QCString resultString( decryptedData.data() );
01272 kdDebug(5006) << "KMReaderWin - resulting data:" << resultString << endl;
01273
01274 if( !resultString.isEmpty() ) {
01275 kdDebug(5006) << "KMReaderWin - composing unencrypted message" << endl;
01276
01277 aMsg->setBody( resultString );
01278 KMMessage* unencryptedMessage = new KMMessage( *aMsg );
01279
01280
01281
01282
01283
01284
01285
01286 kdDebug(5006) << "KMReaderWin - resulting message:" << unencryptedMessage->asString() << endl;
01287 kdDebug(5006) << "KMReaderWin - attach unencrypted message to aMsg" << endl;
01288 aMsg->setUnencryptedMsg( unencryptedMessage );
01289 emitReplaceMsgByUnencryptedVersion = true;
01290 }
01291 }
01292 }
01293
01294
01295 const int rootNodeCntType = mRootNode ? mRootNode->type() : DwMime::kTypeText;
01296 const int rootNodeCntSubtype = mRootNode ? mRootNode->subType() : DwMime::kSubtypePlain;
01297
01298
01299 setIdOfLastViewedMessage( aMsg->msgId() );
01300
01301 if( emitReplaceMsgByUnencryptedVersion ) {
01302 kdDebug(5006) << "KMReaderWin - invoce saving in decrypted form:" << endl;
01303 emit replaceMsgByUnencryptedVersion();
01304 } else {
01305 kdDebug(5006) << "KMReaderWin - finished parsing and displaying of message." << endl;
01306 showHideMimeTree( rootNodeCntType == DwMime::kTypeText &&
01307 rootNodeCntSubtype == DwMime::kSubtypePlain );
01308 }
01309 }
01310
01311
01312
01313 QString KMReaderWin::writeMsgHeader(KMMessage* aMsg, bool hasVCard)
01314 {
01315 kdFatal( !headerStyle(), 5006 )
01316 << "trying to writeMsgHeader() without a header style set!" << endl;
01317 kdFatal( !headerStrategy(), 5006 )
01318 << "trying to writeMsgHeader() without a header strategy set!" << endl;
01319 QString href;
01320 if (hasVCard)
01321 href = QString("file:") + KURL::encode_string( mTempFiles.last() );
01322
01323 return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting );
01324 }
01325
01326
01327
01328
01329 QString KMReaderWin::writeMessagePartToTempFile( KMMessagePart* aMsgPart,
01330 int aPartNum )
01331 {
01332 QString fileName = aMsgPart->fileName();
01333 if( fileName.isEmpty() )
01334 fileName = aMsgPart->name();
01335
01336
01337 KTempFile *tempFile = new KTempFile( QString::null,
01338 "." + QString::number( aPartNum ) );
01339 tempFile->setAutoDelete( true );
01340 QString fname = tempFile->name();
01341 delete tempFile;
01342
01343 if( ::access( QFile::encodeName( fname ), W_OK ) != 0 )
01344
01345 if( ::mkdir( QFile::encodeName( fname ), 0 ) != 0
01346 || ::chmod( QFile::encodeName( fname ), S_IRWXU ) != 0 )
01347 return QString::null;
01348
01349 assert( !fname.isNull() );
01350
01351 mTempDirs.append( fname );
01352
01353 int slashPos = fileName.findRev( '/' );
01354 if( -1 != slashPos )
01355 fileName = fileName.mid( slashPos + 1 );
01356 if( fileName.isEmpty() )
01357 fileName = "unnamed";
01358 fname += "/" + fileName;
01359
01360 QByteArray data = aMsgPart->bodyDecodedBinary();
01361 size_t size = data.size();
01362 if ( aMsgPart->type() == DwMime::kTypeText && size) {
01363
01364 size = KMFolder::crlf2lf( data.data(), size );
01365 }
01366 if( !KPIM::kBytesToFile( data.data(), size, fname, false, false, false ) )
01367 return QString::null;
01368
01369 mTempFiles.append( fname );
01370
01371
01372 ::chmod( QFile::encodeName( fname ), S_IRUSR );
01373
01374 return fname;
01375 }
01376
01377
01378
01379 void KMReaderWin::showVCard( KMMessagePart * msgPart ) {
01380 const QString vCard = msgPart->bodyToUnicode( overrideCodec() );
01381
01382 VCardViewer *vcv = new VCardViewer(this, vCard, "vCardDialog");
01383 vcv->show();
01384 }
01385
01386
01387 void KMReaderWin::printMsg()
01388 {
01389 if (!message()) return;
01390 mViewer->view()->print();
01391 }
01392
01393
01394
01395 int KMReaderWin::msgPartFromUrl(const KURL &aUrl)
01396 {
01397 if (aUrl.isEmpty()) return -1;
01398
01399 if (!aUrl.isLocalFile()) return -1;
01400
01401 QString path = aUrl.path();
01402 uint right = path.findRev('/');
01403 uint left = path.findRev('.', right);
01404
01405 bool ok;
01406 int res = path.mid(left + 1, right - left - 1).toInt(&ok);
01407 return (ok) ? res : -1;
01408 }
01409
01410
01411
01412 void KMReaderWin::resizeEvent(QResizeEvent *)
01413 {
01414 if( !mResizeTimer.isActive() )
01415 {
01416
01417
01418
01419
01420 mResizeTimer.start( 100, true );
01421 }
01422 }
01423
01424
01425
01426 void KMReaderWin::slotDelayedResize()
01427 {
01428 mSplitter->setGeometry(0, 0, width(), height());
01429 }
01430
01431
01432
01433 void KMReaderWin::slotTouchMessage()
01434 {
01435 if ( !message() )
01436 return;
01437
01438 if ( !message()->isNew() && !message()->isUnread() )
01439 return;
01440
01441 SerNumList serNums;
01442 serNums.append( message()->getMsgSerNum() );
01443 KMCommand *command = new KMSetStatusCommand( KMMsgStatusRead, serNums );
01444 command->start();
01445 if ( mNoMDNsWhenEncrypted &&
01446 message()->encryptionState() != KMMsgNotEncrypted &&
01447 message()->encryptionState() != KMMsgEncryptionStateUnknown )
01448 return;
01449 if ( KMMessage * receipt = message()->createMDN( MDN::ManualAction,
01450 MDN::Displayed,
01451 true ) )
01452 if ( !kmkernel->msgSender()->send( receipt ) )
01453 KMessageBox::error( this, i18n("Could not send MDN.") );
01454 }
01455
01456
01457
01458 void KMReaderWin::closeEvent(QCloseEvent *e)
01459 {
01460 QWidget::closeEvent(e);
01461 writeConfig();
01462 }
01463
01464
01465 bool foundSMIMEData( const QString aUrl,
01466 QString& displayName,
01467 QString& libName,
01468 QString& keyId )
01469 {
01470 static QString showCertMan("showCertificate#");
01471 displayName = "";
01472 libName = "";
01473 keyId = "";
01474 int i1 = aUrl.find( showCertMan );
01475 if( -1 < i1 ) {
01476 i1 += showCertMan.length();
01477 int i2 = aUrl.find(" ### ", i1);
01478 if( i1 < i2 )
01479 {
01480 displayName = aUrl.mid( i1, i2-i1 );
01481 i1 = i2+5;
01482 i2 = aUrl.find(" ### ", i1);
01483 if( i1 < i2 )
01484 {
01485 libName = aUrl.mid( i1, i2-i1 );
01486 i2 += 5;
01487
01488 keyId = aUrl.mid( i2 );
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501 }
01502 }
01503 }
01504 return !keyId.isEmpty();
01505 }
01506
01507
01508
01509 void KMReaderWin::slotUrlOn(const QString &aUrl)
01510 {
01511 if ( aUrl.stripWhiteSpace().isEmpty() ) {
01512 KPIM::BroadcastStatus::instance()->reset();
01513 return;
01514 }
01515
01516 const KURL url(aUrl);
01517 mUrlClicked = url;
01518
01519 const QString msg = URLHandlerManager::instance()->statusBarMessage( url, this );
01520
01521 kdWarning( msg.isEmpty(), 5006 ) << "KMReaderWin::slotUrlOn(): Unhandled URL hover!" << endl;
01522 KPIM::BroadcastStatus::instance()->setTransientStatusMsg( msg );
01523 }
01524
01525
01526
01527 void KMReaderWin::slotUrlOpen(const KURL &aUrl, const KParts::URLArgs &)
01528 {
01529 mUrlClicked = aUrl;
01530
01531 if ( URLHandlerManager::instance()->handleClick( aUrl, this ) )
01532 return;
01533
01534 kdWarning( 5006 ) << "KMReaderWin::slotOpenUrl(): Unhandled URL click!" << endl;
01535 emit urlClicked( aUrl, Qt::LeftButton );
01536 }
01537
01538
01539 void KMReaderWin::slotUrlPopup(const QString &aUrl, const QPoint& aPos)
01540 {
01541 const KURL url( aUrl );
01542 mUrlClicked = url;
01543
01544 if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) )
01545 return;
01546
01547 if ( message() ) {
01548 kdWarning( 5006 ) << "KMReaderWin::slotUrlPopup(): Unhandled URL right-click!" << endl;
01549 emit popupMenu( *message(), url, aPos );
01550 }
01551 }
01552
01553 void KMReaderWin::showAttachmentPopup( int id, const QString & name, const QPoint & p ) {
01554 mAtmCurrent = id;
01555 mAtmCurrentName = name;
01556 KPopupMenu *menu = new KPopupMenu();
01557 menu->insertItem(SmallIcon("fileopen"),i18n("Open"), 1);
01558 menu->insertItem(i18n("Open With..."), 2);
01559 menu->insertItem(i18n("to view something", "View"), 3);
01560 menu->insertItem(SmallIcon("filesaveas"),i18n("Save As..."), 4);
01561 menu->insertItem(i18n("Properties"), 5);
01562 connect(menu, SIGNAL(activated(int)), this, SLOT(slotAtmLoadPart(int)));
01563 menu->exec( p ,0 );
01564 delete menu;
01565 }
01566
01567
01568 void KMReaderWin::setStyleDependantFrameWidth()
01569 {
01570 if ( !mBox )
01571 return;
01572
01573 int frameWidth;
01574 if( style().isA("KeramikStyle") )
01575 frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
01576 else
01577 frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
01578 if ( frameWidth < 0 )
01579 frameWidth = 0;
01580 if ( frameWidth != mBox->lineWidth() )
01581 mBox->setLineWidth( frameWidth );
01582 }
01583
01584
01585 void KMReaderWin::styleChange( QStyle& oldStyle )
01586 {
01587 setStyleDependantFrameWidth();
01588 QWidget::styleChange( oldStyle );
01589 }
01590
01591
01592 void KMReaderWin::slotAtmLoadPart( int choice )
01593 {
01594 mChoice = choice;
01595
01596 partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
01597 if ( node && !node->msgPart().isComplete() )
01598 {
01599
01600 mAtmUpdate = true;
01601 KMLoadPartsCommand *command = new KMLoadPartsCommand( node, message() );
01602 connect( command, SIGNAL( partsRetrieved() ),
01603 this, SLOT( slotAtmDistributeClick() ) );
01604 command->start();
01605 } else
01606 slotAtmDistributeClick();
01607 }
01608
01609
01610 void KMReaderWin::slotAtmDistributeClick()
01611 {
01612 switch ( mChoice )
01613 {
01614 case 1:
01615 slotAtmOpen();
01616 break;
01617 case 2:
01618 slotAtmOpenWith();
01619 break;
01620 case 3:
01621 slotAtmView();
01622 break;
01623 case 4:
01624 slotAtmSave();
01625 break;
01626 case 5:
01627 slotAtmProperties();
01628 break;
01629 default: kdWarning(5006) << "unknown menu item " << mChoice << endl;
01630 }
01631 }
01632
01633
01634 void KMReaderWin::slotFind()
01635 {
01636
01637 KAction *act = mViewer->actionCollection()->action("find");
01638 if( act )
01639 act->activate();
01640 }
01641
01642
01643 void KMReaderWin::slotToggleFixedFont()
01644 {
01645 mUseFixedFont = !mUseFixedFont;
01646 update(true);
01647 }
01648
01649
01650
01651 void KMReaderWin::slotCopySelectedText()
01652 {
01653 kapp->clipboard()->setText( mViewer->selectedText() );
01654 }
01655
01656
01657
01658 void KMReaderWin::atmViewMsg(KMMessagePart* aMsgPart)
01659 {
01660 assert(aMsgPart!=0);
01661 partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
01662 KMMessage* msg;
01663 if (node && node->dwPart()->Body().Message()) {
01664
01665 msg = new KMMessage( new DwMessage(*node->dwPart()->Body().Message()) );
01666 } else {
01667 msg = new KMMessage;
01668 msg->fromString(aMsgPart->bodyDecoded());
01669 }
01670 assert(msg != 0);
01671
01672 msg->setParent( message()->parent() );
01673 msg->setUID(message()->UID());
01674 msg->setReadyToShow(true);
01675 KMReaderMainWin *win = new KMReaderMainWin();
01676 win->showMsg( overrideCodec(), msg );
01677 win->show();
01678 }
01679
01680
01681 void KMReaderWin::setMsgPart( partNode * node ) {
01682 htmlWriter()->reset();
01683 mColorBar->hide();
01684 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01685 htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
01686
01687 if ( node ) {
01688 ObjectTreeParser otp( this, 0, true );
01689 otp.parseObjectTree( node );
01690 }
01691
01692 htmlWriter()->queue( "</body></html>" );
01693 htmlWriter()->flush();
01694 }
01695
01696
01697 void KMReaderWin::setMsgPart( KMMessagePart* aMsgPart, bool aHTML,
01698 const QString& aFileName, const QString& pname )
01699 {
01700 KCursorSaver busy(KBusyPtr::busy());
01701 if (qstricmp(aMsgPart->typeStr(), "message")==0) {
01702
01703 KMMessage* msg = new KMMessage;
01704 assert(aMsgPart!=0);
01705 msg->fromString(aMsgPart->bodyDecoded());
01706 mMainWindow->setCaption(msg->subject());
01707 setMsg(msg, true);
01708 setAutoDelete(true);
01709 } else if (qstricmp(aMsgPart->typeStr(), "text")==0) {
01710 if (qstricmp(aMsgPart->subtypeStr(), "x-vcard") == 0) {
01711 showVCard( aMsgPart );
01712 return;
01713 }
01714 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01715 htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
01716
01717 if (aHTML && (qstricmp(aMsgPart->subtypeStr(), "html")==0)) {
01718
01719 htmlWriter()->queue( aMsgPart->bodyToUnicode( overrideCodec() ) );
01720 mColorBar->setHtmlMode();
01721 } else {
01722 const QCString str = aMsgPart->bodyDecoded();
01723 ObjectTreeParser otp( this );
01724 otp.writeBodyStr( str,
01725 overrideCodec() ? overrideCodec() : aMsgPart->codec(),
01726 message() ? message()->from() : QString::null );
01727 }
01728 htmlWriter()->queue("</body></html>");
01729 htmlWriter()->flush();
01730 mMainWindow->setCaption(i18n("View Attachment: %1").arg(pname));
01731 } else if (qstricmp(aMsgPart->typeStr(), "image")==0 ||
01732 (qstricmp(aMsgPart->typeStr(), "application")==0 &&
01733 qstricmp(aMsgPart->subtypeStr(), "postscript")==0))
01734 {
01735 if (aFileName.isEmpty()) return;
01736
01737 QImageIO *iio = new QImageIO();
01738 iio->setFileName(aFileName);
01739 if( iio->read() ) {
01740 QImage img = iio->image();
01741 QRect desk = KGlobalSettings::desktopGeometry(mMainWindow);
01742
01743 int width, height;
01744 if( img.width() < 50 )
01745 width = 70;
01746 else if( img.width()+20 < desk.width() )
01747 width = img.width()+20;
01748 else
01749 width = desk.width();
01750 if( img.height() < 50 )
01751 height = 70;
01752 else if( img.height()+20 < desk.height() )
01753 height = img.height()+20;
01754 else
01755 height = desk.height();
01756 mMainWindow->resize( width, height );
01757 }
01758
01759 htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
01760 htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
01761 htmlWriter()->write( "<img src=\"file:" +
01762 KURL::encode_string( aFileName ) +
01763 "\" border=\"0\">\n"
01764 "</body></html>\n" );
01765 htmlWriter()->end();
01766 setCaption( i18n("View Attachment: %1").arg( pname ) );
01767 show();
01768 } else {
01769 MailSourceViewer *viewer = new MailSourceViewer();
01770 QString str = aMsgPart->bodyDecoded();
01771
01772
01773 if( str.length() < (unsigned) aMsgPart->decodedSize() ) {
01774 str += QString::fromLatin1("\n") + i18n("[KMail: Attachment contains binary data. Trying to show first character.]",
01775 "[KMail: Attachment contains binary data. Trying to show first %n characters.]",
01776 str.length());
01777 }
01778 viewer->setText(str);
01779 viewer->resize(500, 550);
01780 viewer->show();
01781 }
01782
01783 }
01784
01785
01786
01787 void KMReaderWin::slotAtmView()
01788 {
01789 partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
01790 if( node ) {
01791 KMMessagePart& msgPart = node->msgPart();
01792 QString pname = msgPart.fileName();
01793 if (pname.isEmpty()) pname=msgPart.name();
01794 if (pname.isEmpty()) pname=msgPart.contentDescription();
01795 if (pname.isEmpty()) pname="unnamed";
01796
01797 if (qstricmp(msgPart.typeStr(), "message")==0) {
01798 atmViewMsg(&msgPart);
01799 } else if ((qstricmp(msgPart.typeStr(), "text")==0) &&
01800 (qstricmp(msgPart.subtypeStr(), "x-vcard")==0)) {
01801 setMsgPart( &msgPart, htmlMail(), mAtmCurrentName, pname );
01802 } else {
01803 KMReaderMainWin *win = new KMReaderMainWin(&msgPart, htmlMail(),
01804 mAtmCurrentName, pname, overrideCodec() );
01805 win->show();
01806 }
01807 }
01808 }
01809
01810
01811
01812 void KMReaderWin::slotAtmOpen()
01813 {
01814 openAttachment( mAtmCurrent, mAtmCurrentName );
01815 }
01816
01817 void KMReaderWin::openAttachment( int id, const QString & name ) {
01818 mAtmCurrentName = name;
01819 mAtmCurrent = id;
01820
01821 QString str, pname, cmd, fileName;
01822
01823 partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
01824 if( !node ) {
01825 kdWarning(5006) << "KMReaderWin::openAttachment - could not find node " << id << endl;
01826 return;
01827 }
01828
01829 KMMessagePart& msgPart = node->msgPart();
01830 if (qstricmp(msgPart.typeStr(), "message")==0)
01831 {
01832 atmViewMsg(&msgPart);
01833 return;
01834 }
01835
01836 const QString contentTypeStr =
01837 ( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
01838
01839 if ( contentTypeStr == "text/x-vcard" ) {
01840 showVCard( &msgPart );
01841 return;
01842 }
01843
01844
01845 KMimeType::Ptr mimetype;
01846
01847 mimetype = KMimeType::mimeType( contentTypeStr );
01848 if ( mimetype->name() == "application/octet-stream" ) {
01849
01850 mimetype = KMimeType::findByPath( name, 0, true );
01851 }
01852 if ( ( mimetype->name() == "application/octet-stream" )
01853 && msgPart.isComplete() ) {
01854
01855
01856 mimetype = KMimeType::findByFileContent( name );
01857 }
01858
01859 KService::Ptr offer =
01860 KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
01861
01862
01863 mOffer = offer;
01864 QString open_text;
01865 QString filenameText = msgPart.fileName();
01866 if ( filenameText.isEmpty() )
01867 filenameText = msgPart.name();
01868 if ( offer ) {
01869 open_text = i18n("&Open with '%1'").arg( offer->name() );
01870 } else {
01871 open_text = i18n("&Open With...");
01872 }
01873 const QString text = i18n("Open attachment '%1'?\n"
01874 "Note that opening an attachment may compromise "
01875 "your system's security.")
01876 .arg( filenameText );
01877 const int choice = KMessageBox::questionYesNoCancel( this, text,
01878 i18n("Open Attachment?"), KStdGuiItem::saveAs(), open_text,
01879 QString::fromLatin1("askSave") + mimetype->name() );
01880
01881 if( choice == KMessageBox::Yes ) {
01882 slotAtmLoadPart( 4 );
01883 }
01884 else if( choice == KMessageBox::No ) {
01885
01886
01887 if ( !msgPart.isComplete() ) {
01888
01889 mAtmUpdate = true;
01890 KMLoadPartsCommand *command = new KMLoadPartsCommand( node, message() );
01891 connect( command, SIGNAL( partsRetrieved() ),
01892 this, SLOT( slotDoAtmOpen() ) );
01893 command->start();
01894 } else {
01895 slotDoAtmOpen();
01896 }
01897 } else {
01898 kdDebug(5006) << "Canceled opening attachment" << endl;
01899 }
01900 }
01901
01902
01903 void KMReaderWin::slotDoAtmOpen()
01904 {
01905 if ( !mOffer ) {
01906 slotAtmOpenWith();
01907 return;
01908 }
01909
01910 KURL url;
01911 url.setPath( mAtmCurrentName );
01912 KURL::List lst;
01913 lst.append( url );
01914 KRun::run( *mOffer, lst );
01915 }
01916
01917
01918 void KMReaderWin::slotAtmOpenWith()
01919 {
01920
01921
01922
01923 KURL::List lst;
01924 KURL url;
01925 url.setPath(mAtmCurrentName);
01926 lst.append(url);
01927 KRun::displayOpenWithDialog(lst);
01928 }
01929
01930
01931
01932 void KMReaderWin::slotAtmSave()
01933 {
01934 if ( !mRootNode )
01935 return;
01936
01937 partNode * node = mRootNode->findId( mAtmCurrent );
01938 if ( !node ) {
01939 kdWarning(5006) << "KMReaderWin::slotAtmSave - could not find node " << mAtmCurrent << endl;
01940 return;
01941 }
01942
01943 QPtrList<partNode> parts;
01944 parts.append( node );
01945
01946 KMSaveAttachmentsCommand *command =
01947 new KMSaveAttachmentsCommand( this, parts, message(), false );
01948 command->start();
01949 }
01950
01951
01952
01953 void KMReaderWin::slotAtmProperties()
01954 {
01955 KMMsgPartDialogCompat dlg(0,TRUE);
01956
01957 partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
01958 if( node ) {
01959 KMMessagePart& msgPart = node->msgPart();
01960
01961 dlg.setMsgPart(&msgPart);
01962 dlg.exec();
01963 }
01964 }
01965
01966
01967
01968 void KMReaderWin::slotScrollUp()
01969 {
01970 static_cast<QScrollView *>(mViewer->widget())->scrollBy(0, -10);
01971 }
01972
01973
01974
01975 void KMReaderWin::slotScrollDown()
01976 {
01977 static_cast<QScrollView *>(mViewer->widget())->scrollBy(0, 10);
01978 }
01979
01980 bool KMReaderWin::atBottom() const
01981 {
01982 const QScrollView *view = static_cast<const QScrollView *>(mViewer->widget());
01983 return view->contentsY() + view->visibleHeight() >= view->contentsHeight();
01984 }
01985
01986
01987 void KMReaderWin::slotJumpDown()
01988 {
01989 QScrollView *view = static_cast<QScrollView *>(mViewer->widget());
01990 int offs = (view->clipper()->height() < 30) ? view->clipper()->height() : 30;
01991 view->scrollBy( 0, view->clipper()->height() - offs );
01992 }
01993
01994
01995 void KMReaderWin::slotScrollPrior()
01996 {
01997 static_cast<QScrollView *>(mViewer->widget())->scrollBy(0, -(int)(height()*0.8));
01998 }
01999
02000
02001
02002 void KMReaderWin::slotScrollNext()
02003 {
02004 static_cast<QScrollView *>(mViewer->widget())->scrollBy(0, (int)(height()*0.8));
02005 }
02006
02007
02008 void KMReaderWin::slotDocumentChanged()
02009 {
02010
02011 }
02012
02013
02014
02015 void KMReaderWin::slotTextSelected(bool)
02016 {
02017 QString temp = mViewer->selectedText();
02018 kapp->clipboard()->setText(temp);
02019 }
02020
02021
02022 void KMReaderWin::selectAll()
02023 {
02024 mViewer->selectAll();
02025 }
02026
02027
02028 QString KMReaderWin::copyText()
02029 {
02030 QString temp = mViewer->selectedText();
02031 return temp;
02032 }
02033
02034
02035
02036 void KMReaderWin::slotDocumentDone()
02037 {
02038
02039 }
02040
02041
02042
02043 void KMReaderWin::setHtmlOverride(bool override)
02044 {
02045 mHtmlOverride = override;
02046 if (message())
02047 message()->setDecodeHTML(htmlMail());
02048 }
02049
02050
02051
02052 bool KMReaderWin::htmlMail()
02053 {
02054 return ((mHtmlMail && !mHtmlOverride) || (!mHtmlMail && mHtmlOverride));
02055 }
02056
02057
02058
02059 void KMReaderWin::update( bool force )
02060 {
02061 KMMessage* msg = message();
02062 if ( msg )
02063 setMsg( msg, force );
02064 }
02065
02066
02067
02068 KMMessage* KMReaderWin::message( KMFolder** aFolder ) const
02069 {
02070 KMFolder* tmpFolder;
02071 KMFolder*& folder = aFolder ? *aFolder : tmpFolder;
02072 folder = 0;
02073 if (mMessage)
02074 return mMessage;
02075 if (mLastSerNum) {
02076 KMMessage *message = 0;
02077 int index;
02078 kmkernel->msgDict()->getLocation( mLastSerNum, &folder, &index );
02079 if (folder )
02080 message = folder->getMsg( index );
02081 if (!message)
02082 kdWarning(5006) << "Attempt to reference invalid serial number " << mLastSerNum << "\n" << endl;
02083 return message;
02084 }
02085 return 0;
02086 }
02087
02088
02089
02090
02091 void KMReaderWin::slotUrlClicked()
02092 {
02093 KMMainWidget *mainWidget = dynamic_cast<KMMainWidget*>(mMainWindow);
02094 uint identity = 0;
02095 if ( message() && message()->parent() ) {
02096 identity = message()->parent()->identity();
02097 }
02098
02099 KMCommand *command = new KMUrlClickedCommand( mUrlClicked, identity, this,
02100 false, mainWidget );
02101 command->start();
02102 }
02103
02104
02105 void KMReaderWin::slotMailtoCompose()
02106 {
02107 KMCommand *command = new KMMailtoComposeCommand( mUrlClicked, message() );
02108 command->start();
02109 }
02110
02111
02112 void KMReaderWin::slotMailtoForward()
02113 {
02114 KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mUrlClicked,
02115 message() );
02116 command->start();
02117 }
02118
02119
02120 void KMReaderWin::slotMailtoAddAddrBook()
02121 {
02122 KMCommand *command = new KMMailtoAddAddrBookCommand( mUrlClicked,
02123 mMainWindow);
02124 command->start();
02125 }
02126
02127
02128 void KMReaderWin::slotMailtoOpenAddrBook()
02129 {
02130 KMCommand *command = new KMMailtoOpenAddrBookCommand( mUrlClicked,
02131 mMainWindow );
02132 command->start();
02133 }
02134
02135
02136 void KMReaderWin::slotUrlCopy()
02137 {
02138
02139
02140 KMCommand *command =
02141 new KMUrlCopyCommand( mUrlClicked,
02142 dynamic_cast<KMMainWidget*>( mMainWindow ) );
02143 command->start();
02144 }
02145
02146
02147 void KMReaderWin::slotUrlOpen( const KURL &url )
02148 {
02149 if ( !url.isEmpty() )
02150 mUrlClicked = url;
02151 KMCommand *command = new KMUrlOpenCommand( mUrlClicked, this );
02152 command->start();
02153 }
02154
02155
02156 void KMReaderWin::slotAddBookmarks()
02157 {
02158 KMCommand *command = new KMAddBookmarksCommand( mUrlClicked, this );
02159 command->start();
02160 }
02161
02162
02163 void KMReaderWin::slotUrlSave()
02164 {
02165 KMCommand *command = new KMUrlSaveCommand( mUrlClicked, mMainWindow );
02166 command->start();
02167 }
02168
02169
02170 void KMReaderWin::slotMailtoReply()
02171 {
02172 KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mUrlClicked,
02173 message(), copyText() );
02174 command->start();
02175 }
02176
02177
02178 void KMReaderWin::slotShowMsgSrc()
02179 {
02180 KMMessage *msg = message();
02181 if ( !msg )
02182 return;
02183 KMShowMsgSrcCommand *command = new KMShowMsgSrcCommand( msg, isFixedFont() );
02184 command->start();
02185 }
02186
02187
02188 partNode * KMReaderWin::partNodeFromUrl( const KURL & url ) {
02189 return mRootNode ? mRootNode->findId( msgPartFromUrl( url ) ) : 0 ;
02190 }
02191
02192 partNode * KMReaderWin::partNodeForId( int id ) {
02193 return mRootNode ? mRootNode->findId( id ) : 0 ;
02194 }
02195
02196
02197 void KMReaderWin::slotSaveAttachments()
02198 {
02199 mAtmUpdate = true;
02200 KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( mMainWindow,
02201 message() );
02202 saveCommand->start();
02203 }
02204
02205
02206 void KMReaderWin::slotSaveMsg()
02207 {
02208 KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( mMainWindow, message() );
02209
02210 if (saveCommand->url().isEmpty())
02211 delete saveCommand;
02212 else
02213 saveCommand->start();
02214 }
02215
02216 void KMReaderWin::slotIMChat()
02217 {
02218 KMCommand *command = new KMIMChatCommand( mUrlClicked, message() );
02219 command->start();
02220 }
02221
02222 #include "kmreaderwin.moc"
02223
02224