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