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